am 41f61f09: (-s ours) Import revised translations.  DO NOT MERGE

* commit '41f61f09d7f40520d666cdcc037a1365f3cc879f':
  Import revised translations.  DO NOT MERGE
diff --git a/proguard.flags b/proguard.flags
index 699f23e..19c8fd5 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -20,6 +20,17 @@
   public void setHoverAlpha(float);
 }
 
+-keep class com.android.launcher2.CellLayout$LayoutParams {
+  public void setWidth(int);
+  public int getWidth();
+  public void setHeight(int);
+  public int getHeight();
+  public void setX(int);
+  public int getX();
+  public void setY(int);
+  public int getY();
+}
+
 -keep class com.android.launcher2.Workspace {
   public float getBackgroundAlpha();
   public void setBackgroundAlpha(float);
diff --git a/res/drawable-hdpi/widget_resize_frame_holo.9.png b/res/drawable-hdpi/widget_resize_frame_holo.9.png
new file mode 100644
index 0000000..8da665b
--- /dev/null
+++ b/res/drawable-hdpi/widget_resize_frame_holo.9.png
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_handle_bottom.png b/res/drawable-hdpi/widget_resize_handle_bottom.png
new file mode 100644
index 0000000..495476b
--- /dev/null
+++ b/res/drawable-hdpi/widget_resize_handle_bottom.png
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_handle_left.png b/res/drawable-hdpi/widget_resize_handle_left.png
new file mode 100644
index 0000000..c73cf0e
--- /dev/null
+++ b/res/drawable-hdpi/widget_resize_handle_left.png
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_handle_right.png b/res/drawable-hdpi/widget_resize_handle_right.png
new file mode 100644
index 0000000..9532302
--- /dev/null
+++ b/res/drawable-hdpi/widget_resize_handle_right.png
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_handle_top.png b/res/drawable-hdpi/widget_resize_handle_top.png
new file mode 100644
index 0000000..a3d2f7c
--- /dev/null
+++ b/res/drawable-hdpi/widget_resize_handle_top.png
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_frame_holo.9.png b/res/drawable-mdpi/widget_resize_frame_holo.9.png
new file mode 100644
index 0000000..0572f89
--- /dev/null
+++ b/res/drawable-mdpi/widget_resize_frame_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_handle_bottom.png b/res/drawable-mdpi/widget_resize_handle_bottom.png
new file mode 100644
index 0000000..6c93973
--- /dev/null
+++ b/res/drawable-mdpi/widget_resize_handle_bottom.png
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_handle_left.png b/res/drawable-mdpi/widget_resize_handle_left.png
new file mode 100644
index 0000000..7139415
--- /dev/null
+++ b/res/drawable-mdpi/widget_resize_handle_left.png
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_handle_right.png b/res/drawable-mdpi/widget_resize_handle_right.png
new file mode 100644
index 0000000..442224b
--- /dev/null
+++ b/res/drawable-mdpi/widget_resize_handle_right.png
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_handle_top.png b/res/drawable-mdpi/widget_resize_handle_top.png
new file mode 100644
index 0000000..2435884
--- /dev/null
+++ b/res/drawable-mdpi/widget_resize_handle_top.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/ic_generic_search.png b/res/drawable-xlarge-hdpi/ic_generic_search.png
new file mode 100644
index 0000000..67bac5c
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/ic_generic_search.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/ic_voice_search.png b/res/drawable-xlarge-hdpi/ic_voice_search.png
new file mode 100644
index 0000000..5d2f341
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/ic_voice_search.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/widget_resize_frame_holo.9.png b/res/drawable-xlarge-hdpi/widget_resize_frame_holo.9.png
new file mode 100644
index 0000000..7d16d7d
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/widget_resize_frame_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/widget_resize_handle_bottom.png b/res/drawable-xlarge-hdpi/widget_resize_handle_bottom.png
new file mode 100644
index 0000000..045c15e
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/widget_resize_handle_bottom.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/widget_resize_handle_left.png b/res/drawable-xlarge-hdpi/widget_resize_handle_left.png
new file mode 100644
index 0000000..f0fc4d6
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/widget_resize_handle_left.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/widget_resize_handle_right.png b/res/drawable-xlarge-hdpi/widget_resize_handle_right.png
new file mode 100644
index 0000000..9c1f366
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/widget_resize_handle_right.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/widget_resize_handle_top.png b/res/drawable-xlarge-hdpi/widget_resize_handle_top.png
new file mode 100644
index 0000000..f7839ed
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/widget_resize_handle_top.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/ic_generic_search.png b/res/drawable-xlarge-mdpi/ic_generic_search.png
index d92071b..e3fd5a2 100644
--- a/res/drawable-xlarge-mdpi/ic_generic_search.png
+++ b/res/drawable-xlarge-mdpi/ic_generic_search.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/ic_voice_search.png b/res/drawable-xlarge-mdpi/ic_voice_search.png
index a2fe874..3c52e2a 100644
--- a/res/drawable-xlarge-mdpi/ic_voice_search.png
+++ b/res/drawable-xlarge-mdpi/ic_voice_search.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/widget_resize_frame_holo.9.png b/res/drawable-xlarge-mdpi/widget_resize_frame_holo.9.png
new file mode 100644
index 0000000..e2e1396
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/widget_resize_frame_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/widget_resize_handle_bottom.png b/res/drawable-xlarge-mdpi/widget_resize_handle_bottom.png
new file mode 100644
index 0000000..99ac1b2
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/widget_resize_handle_bottom.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/widget_resize_handle_left.png b/res/drawable-xlarge-mdpi/widget_resize_handle_left.png
new file mode 100644
index 0000000..d031ddd
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/widget_resize_handle_left.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/widget_resize_handle_right.png b/res/drawable-xlarge-mdpi/widget_resize_handle_right.png
new file mode 100644
index 0000000..f1b689c
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/widget_resize_handle_right.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/widget_resize_handle_top.png b/res/drawable-xlarge-mdpi/widget_resize_handle_top.png
new file mode 100644
index 0000000..40bef02
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/widget_resize_handle_top.png
Binary files differ
diff --git a/res/layout-xlarge-land/all_apps_tabbed.xml b/res/layout-xlarge-land/all_apps_tabbed.xml
index d03a571..9244213 100644
--- a/res/layout-xlarge-land/all_apps_tabbed.xml
+++ b/res/layout-xlarge-land/all_apps_tabbed.xml
@@ -16,6 +16,10 @@
 <com.android.launcher2.AllAppsTabbed
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher">
+    <com.android.launcher2.AllAppsBackground
+        android:id="@+id/all_apps_background"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
     <LinearLayout
         android:orientation="vertical"
         android:layout_width="match_parent"
@@ -44,16 +48,23 @@
                     android:layout_height="wrap_content"
                     android:layout_gravity="center"
                     android:visibility="invisible"/>
-                <ImageView
+                <TextView
                     android:id="@+id/market_button"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_gravity="center"
-                    android:onClick="onClickAppMarketButton"/>
+                    android:gravity="center"
+                    android:paddingRight="22dp"
+                    android:text="@string/market"
+                    android:textColor="@color/workspace_all_apps_and_delete_zone_text_color"
+                    android:textSize="18sp"
+                    android:shadowColor="@color/workspace_all_apps_and_delete_zone_text_shadow_color"
+                    android:shadowDx="0.0"
+                    android:shadowDy="0.0"
+                    android:shadowRadius="2.0" />
             </FrameLayout>
             <com.android.launcher2.DeleteZone
                 android:id="@+id/all_apps_delete_zone"
-                android:text="@string/delete_zone_label_all_apps"
                 android:drawablePadding="@dimen/delete_zone_drawable_padding"
                 android:drawableLeft="@drawable/delete_zone_selector"
                 android:layout_width="wrap_content"
@@ -64,7 +75,7 @@
                 android:paddingRight="22dp"
                 launcher:direction="horizontal"
 
-                android:gravity="center_horizontal|center_vertical"
+                android:gravity="center"
                 android:textColor="@color/workspace_all_apps_and_delete_zone_text_color"
                 android:textSize="18sp"
                 android:shadowColor="@color/workspace_all_apps_and_delete_zone_text_shadow_color"
diff --git a/res/layout-xlarge-land/customization_drawer.xml b/res/layout-xlarge-land/customization_drawer_tab_contents.xml
similarity index 100%
rename from res/layout-xlarge-land/customization_drawer.xml
rename to res/layout-xlarge-land/customization_drawer_tab_contents.xml
diff --git a/res/layout-xlarge-land/launcher.xml b/res/layout-xlarge-land/launcher.xml
deleted file mode 100644
index 957327e..0000000
--- a/res/layout-xlarge-land/launcher.xml
+++ /dev/null
@@ -1,215 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<com.android.launcher2.DragLayer
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
-
-    android:id="@+id/drag_layer"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <!-- The workspace contains 5 screens of cells -->
-    <com.android.launcher2.Workspace
-        android:id="@+id/workspace"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:paddingTop="?android:attr/actionBarSize"
-        android:paddingBottom="10dp"
-        launcher:defaultScreen="2"
-        launcher:cellCountX="8"
-        launcher:cellCountY="7"
-        launcher:pageSpacing="50dp">
-
-        <include android:id="@+id/cell1" layout="@layout/workspace_screen" />
-        <include android:id="@+id/cell2" layout="@layout/workspace_screen" />
-        <include android:id="@+id/cell3" layout="@layout/workspace_screen" />
-        <include android:id="@+id/cell4" layout="@layout/workspace_screen" />
-        <include android:id="@+id/cell5" layout="@layout/workspace_screen" />
-    </com.android.launcher2.Workspace>
-
-    <include
-        layout="@layout/all_apps_tabbed"
-        android:id="@+id/all_apps_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_gravity="top" />
-
-    <RelativeLayout
-        android:id="@+id/all_apps_button_cluster"
-        android:layout_width="fill_parent"
-        android:layout_height="?android:attr/actionBarSize"
-        android:layout_gravity="top">
-
-       <!-- Global search icon -->
-       <ImageView
-           android:id="@+id/search_button"
-           android:layout_width="wrap_content"
-           android:layout_height="wrap_content"
-           android:layout_alignParentTop="true"
-           android:layout_alignParentLeft="true"
-           android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
-           android:paddingRight="@dimen/toolbar_button_horizontal_padding"
-           android:paddingTop="@dimen/toolbar_button_vertical_padding"
-           android:paddingBottom="@dimen/toolbar_button_vertical_padding"
-           android:src="@drawable/ic_generic_search"
-           android:background="@drawable/button_bg"
-           android:onClick="onClickSearchButton"
-           android:focusable="true"
-           android:clickable="true" />
-           
-        <ImageView
-            android:id="@+id/search_divider"
-            android:src="@drawable/divider_launcher_holo"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_toRightOf="@id/search_button"
-            android:paddingTop="@dimen/toolbar_button_vertical_padding"
-            android:paddingBottom="@dimen/toolbar_button_vertical_padding"
-
-            android:onClick="onClickSearchButton"
-            android:focusable="false"
-            android:clickable="true" />
-
-        <!-- Voice search icon -->
-        <ImageView
-            android:id="@+id/voice_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_toRightOf="@id/search_divider"
-            android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
-            android:paddingRight="@dimen/toolbar_button_horizontal_padding"
-            android:paddingTop="@dimen/toolbar_button_vertical_padding"
-            android:paddingBottom="@dimen/toolbar_button_vertical_padding"
-            android:src="@drawable/ic_voice_search"
-            android:background="@drawable/button_bg"
-            android:onClick="onClickVoiceButton"
-            android:focusable="true"
-            android:clickable="true"/>
-
-        <ImageView
-            android:id="@+id/configure_button"
-            android:src="@drawable/ic_home_add_holo_dark"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignParentTop="true"
-            android:layout_alignParentRight="true"
-            android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
-            android:paddingRight="@dimen/toolbar_button_horizontal_padding"
-            android:paddingTop="@dimen/toolbar_button_vertical_padding"
-            android:paddingBottom="@dimen/toolbar_button_vertical_padding"
-            android:background="@drawable/button_bg"
-
-            android:onClick="onClickConfigureButton"
-            android:focusable="true"
-            android:clickable="true" />
-        <ImageView
-            android:id="@+id/divider"
-            android:src="@drawable/divider_launcher_holo"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_toLeftOf="@id/configure_button"
-            android:paddingTop="@dimen/toolbar_button_vertical_padding"
-            android:paddingBottom="@dimen/toolbar_button_vertical_padding"
-
-            android:onClick="onClickAllAppsButton"
-            android:focusable="false"
-            android:clickable="true" />
-        <TextView
-            android:id="@+id/all_apps_button"
-            android:text="@string/all_apps_button_label"
-            android:drawablePadding="@dimen/all_apps_button_drawable_padding"
-            android:drawableLeft="@drawable/ic_home_all_apps_holo_dark"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_toLeftOf="@id/divider"
-            android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
-            android:paddingRight="@dimen/toolbar_button_horizontal_padding"
-            android:paddingTop="@dimen/all_apps_button_vertical_padding"
-            android:paddingBottom="@dimen/all_apps_button_vertical_padding"
-            android:background="@drawable/button_bg"
-            
-            android:gravity="center_horizontal|center_vertical"
-            android:textColor="#CCFFFFFF"
-            android:textSize="18sp"
-
-            android:shadowColor="#DA000000"
-            android:shadowDx="0.0"
-            android:shadowDy="0.0"
-            android:shadowRadius="2.5"
-
-            android:onClick="onClickAllAppsButton"
-            android:focusable="true"
-            android:clickable="true" />
-        <ImageView
-            android:id="@+id/divider_during_drag"
-            android:src="@drawable/divider_launcher_holo"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_toLeftOf="@id/configure_button"
-            android:paddingTop="@dimen/toolbar_button_vertical_padding"
-            android:paddingBottom="@dimen/toolbar_button_vertical_padding"
-            android:visibility="gone"/>
-        <com.android.launcher2.DeleteZone
-            android:id="@+id/delete_zone"
-            android:text="@string/delete_zone_label_workspace"
-            android:drawablePadding="@dimen/delete_zone_drawable_padding"
-            android:drawableLeft="@drawable/delete_zone_selector"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignRight="@id/configure_button"
-            android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
-            android:paddingRight="@dimen/toolbar_button_horizontal_padding"
-            android:paddingTop="@dimen/toolbar_button_vertical_padding"
-            android:paddingBottom="@dimen/toolbar_button_vertical_padding"
-            android:background="@drawable/button_bg"
-
-            android:gravity="center_horizontal|center_vertical"
-            android:textColor="@color/workspace_all_apps_and_delete_zone_text_color"
-            android:textSize="18sp"
-            android:shadowColor="@color/workspace_all_apps_and_delete_zone_text_shadow_color"
-            android:shadowDx="0.0"
-            android:shadowDy="0.0"
-            android:shadowRadius="2.0"
-
-            android:visibility="gone"
-            launcher:direction="horizontal" />
-    </RelativeLayout>
-
-    <TabHost
-        android:id="@+id/customization_drawer"
-        android:layout_width="match_parent"
-        android:layout_height="480dp"
-        android:layout_gravity="bottom">
-        <LinearLayout
-            android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent">
-            <TabWidget
-                android:id="@android:id/tabs"
-                android:layout_width="952dp"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_horizontal"
-                android:background="@drawable/tab_unselected_holo"
-                android:tabStripEnabled="false" />
-            <FrameLayout
-                android:id="@android:id/tabcontent"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent">
-             </FrameLayout>
-          </LinearLayout>
-    </TabHost>
-</com.android.launcher2.DragLayer>
diff --git a/res/layout-xlarge-port/all_apps_tabbed.xml b/res/layout-xlarge-port/all_apps_tabbed.xml
index 269fa12..c357d2e 100644
--- a/res/layout-xlarge-port/all_apps_tabbed.xml
+++ b/res/layout-xlarge-port/all_apps_tabbed.xml
@@ -16,6 +16,10 @@
 <com.android.launcher2.AllAppsTabbed
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher">
+    <com.android.launcher2.AllAppsBackground
+        android:id="@+id/all_apps_background"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
     <LinearLayout
         android:orientation="vertical"
         android:layout_width="match_parent"
@@ -44,16 +48,23 @@
                     android:layout_height="wrap_content"
                     android:layout_gravity="center"
                     android:visibility="invisible"/>
-                <ImageView
+                <TextView
                     android:id="@+id/market_button"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_gravity="center"
-                    android:onClick="onClickAppMarketButton"/>
+                    android:gravity="center"
+                    android:paddingRight="22dp"
+                    android:text="@string/market"
+                    android:textColor="@color/workspace_all_apps_and_delete_zone_text_color"
+                    android:textSize="18sp"
+                    android:shadowColor="@color/workspace_all_apps_and_delete_zone_text_shadow_color"
+                    android:shadowDx="0.0"
+                    android:shadowDy="0.0"
+                    android:shadowRadius="2.0" />
             </FrameLayout>
             <com.android.launcher2.DeleteZone
                 android:id="@+id/all_apps_delete_zone"
-                android:text="@string/delete_zone_label_all_apps"
                 android:drawablePadding="@dimen/delete_zone_drawable_padding"
                 android:drawableLeft="@drawable/delete_zone_selector"
                 android:layout_width="wrap_content"
@@ -64,7 +75,7 @@
                 android:paddingRight="22dp"
                 launcher:direction="horizontal"
 
-                android:gravity="center_horizontal|center_vertical"
+                android:gravity="center"
                 android:textColor="@color/workspace_all_apps_and_delete_zone_text_color"
                 android:textSize="18sp"
                 android:shadowColor="@color/workspace_all_apps_and_delete_zone_text_shadow_color"
diff --git a/res/layout-xlarge-port/customization_drawer.xml b/res/layout-xlarge-port/customization_drawer_tab_contents.xml
similarity index 96%
rename from res/layout-xlarge-port/customization_drawer.xml
rename to res/layout-xlarge-port/customization_drawer_tab_contents.xml
index a1bc7cc..0381be0 100644
--- a/res/layout-xlarge-port/customization_drawer.xml
+++ b/res/layout-xlarge-port/customization_drawer_tab_contents.xml
@@ -21,7 +21,7 @@
     android:layout_height="match_parent"
     launcher:wallpaperCellSpanX="3"
     launcher:wallpaperCellCountX="9"
-    launcher:widgetCellCountX="10"
+    launcher:widgetCellCountX="9"
     launcher:cellCountX="5"
     launcher:cellCountY="3"
     launcher:pageLayoutWidthGap="36dp"
diff --git a/res/layout-xlarge-port/launcher.xml b/res/layout-xlarge-port/launcher.xml
deleted file mode 100644
index a8087f4..0000000
--- a/res/layout-xlarge-port/launcher.xml
+++ /dev/null
@@ -1,215 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<com.android.launcher2.DragLayer
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
-
-    android:id="@+id/drag_layer"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <!-- The workspace contains 5 screens of cells -->
-    <com.android.launcher2.Workspace
-        android:id="@+id/workspace"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:paddingTop="?android:attr/actionBarSize"
-        android:paddingBottom="10dp"
-        launcher:defaultScreen="2"
-        launcher:cellCountX="8"
-        launcher:cellCountY="7"
-        launcher:pageSpacing="64dp">
-
-        <include android:id="@+id/cell1" layout="@layout/workspace_screen" />
-        <include android:id="@+id/cell2" layout="@layout/workspace_screen" />
-        <include android:id="@+id/cell3" layout="@layout/workspace_screen" />
-        <include android:id="@+id/cell4" layout="@layout/workspace_screen" />
-        <include android:id="@+id/cell5" layout="@layout/workspace_screen" />
-    </com.android.launcher2.Workspace>
-
-    <include
-        layout="@layout/all_apps_tabbed"
-        android:id="@+id/all_apps_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_gravity="top" />
-
-    <RelativeLayout
-        android:id="@+id/all_apps_button_cluster"
-        android:layout_width="fill_parent"
-        android:layout_height="?android:attr/actionBarSize"
-        android:layout_gravity="top">
-
-       <!-- Global search icon -->
-       <ImageView
-           android:id="@+id/search_button"
-           android:layout_width="wrap_content"
-           android:layout_height="wrap_content"
-           android:layout_alignParentTop="true"
-           android:layout_alignParentLeft="true"
-           android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
-           android:paddingRight="@dimen/toolbar_button_horizontal_padding"
-           android:paddingTop="@dimen/toolbar_button_vertical_padding"
-           android:paddingBottom="@dimen/toolbar_button_vertical_padding"
-           android:src="@drawable/ic_generic_search"
-           android:background="@drawable/button_bg"
-           android:onClick="onClickSearchButton"
-           android:focusable="true"
-           android:clickable="true" />
-           
-        <ImageView
-            android:id="@+id/search_divider"
-            android:src="@drawable/divider_launcher_holo"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_toRightOf="@id/search_button"
-            android:paddingTop="@dimen/toolbar_button_vertical_padding"
-            android:paddingBottom="@dimen/toolbar_button_vertical_padding"
-
-            android:onClick="onClickSearchButton"
-            android:focusable="false"
-            android:clickable="true" />
-
-        <!-- Voice search icon -->
-        <ImageView
-            android:id="@+id/voice_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_toRightOf="@id/search_divider"
-            android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
-            android:paddingRight="@dimen/toolbar_button_horizontal_padding"
-            android:paddingTop="@dimen/toolbar_button_vertical_padding"
-            android:paddingBottom="@dimen/toolbar_button_vertical_padding"
-            android:src="@drawable/ic_voice_search"
-            android:background="@drawable/button_bg"
-            android:onClick="onClickVoiceButton"
-            android:focusable="true"
-            android:clickable="true"/>
-
-        <ImageView
-            android:id="@+id/configure_button"
-            android:src="@drawable/ic_home_add_holo_dark"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignParentTop="true"
-            android:layout_alignParentRight="true"
-            android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
-            android:paddingRight="@dimen/toolbar_button_horizontal_padding"
-            android:paddingTop="@dimen/toolbar_button_vertical_padding"
-            android:paddingBottom="@dimen/toolbar_button_vertical_padding"
-            android:background="@drawable/button_bg"
-
-            android:onClick="onClickConfigureButton"
-            android:focusable="true"
-            android:clickable="true" />
-        <ImageView
-            android:id="@+id/divider"
-            android:src="@drawable/divider_launcher_holo"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_toLeftOf="@id/configure_button"
-            android:paddingTop="@dimen/toolbar_button_vertical_padding"
-            android:paddingBottom="@dimen/toolbar_button_vertical_padding"
-
-            android:onClick="onClickAllAppsButton"
-            android:focusable="false"
-            android:clickable="true" />
-        <TextView
-            android:id="@+id/all_apps_button"
-            android:text="@string/all_apps_button_label"
-            android:drawablePadding="@dimen/all_apps_button_drawable_padding"
-            android:drawableLeft="@drawable/ic_home_all_apps_holo_dark"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_toLeftOf="@id/divider"
-            android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
-            android:paddingRight="@dimen/toolbar_button_horizontal_padding"
-            android:paddingTop="@dimen/all_apps_button_vertical_padding"
-            android:paddingBottom="@dimen/all_apps_button_vertical_padding"
-            android:background="@drawable/button_bg"
-            
-            android:gravity="center_horizontal|center_vertical"
-            android:textColor="#CCFFFFFF"
-            android:textSize="18sp"
-
-            android:shadowColor="#DA000000"
-            android:shadowDx="0.0"
-            android:shadowDy="0.0"
-            android:shadowRadius="2.5"
-
-            android:onClick="onClickAllAppsButton"
-            android:focusable="true"
-            android:clickable="true" />
-        <ImageView
-            android:id="@+id/divider_during_drag"
-            android:src="@drawable/divider_launcher_holo"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_toLeftOf="@id/configure_button"
-            android:paddingTop="@dimen/toolbar_button_vertical_padding"
-            android:paddingBottom="@dimen/toolbar_button_vertical_padding"
-            android:visibility="gone"/>
-        <com.android.launcher2.DeleteZone
-            android:id="@+id/delete_zone"
-            android:text="@string/delete_zone_label_workspace"
-            android:drawablePadding="@dimen/delete_zone_drawable_padding"
-            android:drawableLeft="@drawable/delete_zone_selector"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignRight="@id/configure_button"
-            android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
-            android:paddingRight="@dimen/toolbar_button_horizontal_padding"
-            android:paddingTop="@dimen/toolbar_button_vertical_padding"
-            android:paddingBottom="@dimen/toolbar_button_vertical_padding"
-            android:background="@drawable/button_bg"
-
-            android:gravity="center_horizontal|center_vertical"
-            android:textColor="@color/workspace_all_apps_and_delete_zone_text_color"
-            android:textSize="18sp"
-            android:shadowColor="@color/workspace_all_apps_and_delete_zone_text_shadow_color"
-            android:shadowDx="0.0"
-            android:shadowDy="0.0"
-            android:shadowRadius="2.0"
-
-            android:visibility="gone"
-            launcher:direction="horizontal" />
-    </RelativeLayout>
-
-    <TabHost
-        android:id="@+id/customization_drawer"
-        android:layout_width="match_parent"
-        android:layout_height="800dp"
-        android:layout_gravity="bottom">
-        <LinearLayout
-            android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent">
-            <TabWidget
-                android:id="@android:id/tabs"
-                android:layout_width="700dp"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_horizontal"
-                android:background="@drawable/tab_unselected_holo"
-                android:tabStripEnabled="false" />
-            <FrameLayout
-                android:id="@android:id/tabcontent"
-                android:layout_width="match_parent"
-                android:layout_height="650dp">
-             </FrameLayout>
-          </LinearLayout>
-    </TabHost>
-</com.android.launcher2.DragLayer>
diff --git a/res/layout-xlarge/button_bar.xml b/res/layout-xlarge/button_bar.xml
new file mode 100644
index 0000000..5c96c5c
--- /dev/null
+++ b/res/layout-xlarge/button_bar.xml
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher">
+
+   <!-- Global search icon -->
+   <ImageView
+       android:id="@+id/search_button"
+       android:layout_width="wrap_content"
+       android:layout_height="wrap_content"
+       android:layout_alignParentTop="true"
+       android:layout_alignParentLeft="true"
+       android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
+       android:paddingRight="@dimen/toolbar_button_horizontal_padding"
+       android:paddingTop="@dimen/toolbar_button_vertical_padding"
+       android:paddingBottom="@dimen/toolbar_button_vertical_padding"
+       android:src="@drawable/ic_generic_search"
+       android:background="@drawable/button_bg"
+       android:onClick="onClickSearchButton"
+       android:focusable="true"
+       android:clickable="true" />
+
+    <ImageView
+        android:id="@+id/search_divider"
+        android:src="@drawable/divider_launcher_holo"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_toRightOf="@id/search_button"
+        android:paddingTop="@dimen/toolbar_button_vertical_padding"
+        android:paddingBottom="@dimen/toolbar_button_vertical_padding"
+
+        android:onClick="onClickSearchButton"
+        android:focusable="false"
+        android:clickable="true" />
+
+    <!-- Voice search icon -->
+    <ImageView
+        android:id="@+id/voice_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toRightOf="@id/search_divider"
+        android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
+        android:paddingRight="@dimen/toolbar_button_horizontal_padding"
+        android:paddingTop="@dimen/toolbar_button_vertical_padding"
+        android:paddingBottom="@dimen/toolbar_button_vertical_padding"
+        android:src="@drawable/ic_voice_search"
+        android:background="@drawable/button_bg"
+        android:onClick="onClickVoiceButton"
+        android:focusable="true"
+        android:clickable="true"/>
+
+    <ImageView
+        android:id="@+id/configure_button"
+        android:src="@drawable/ic_home_add_holo_dark"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentRight="true"
+        android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
+        android:paddingRight="@dimen/toolbar_button_horizontal_padding"
+        android:paddingTop="@dimen/toolbar_button_vertical_padding"
+        android:paddingBottom="@dimen/toolbar_button_vertical_padding"
+        android:background="@drawable/button_bg"
+
+        android:focusable="true"
+        android:clickable="true" />
+    <ImageView
+        android:id="@+id/divider"
+        android:src="@drawable/divider_launcher_holo"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_toLeftOf="@id/configure_button"
+        android:paddingTop="@dimen/toolbar_button_vertical_padding"
+        android:paddingBottom="@dimen/toolbar_button_vertical_padding"
+
+        android:focusable="false"
+        android:clickable="true" />
+    <com.android.launcher2.StrokedTextView
+        android:id="@+id/all_apps_button"
+        android:text="@string/all_apps_button_label"
+        android:drawablePadding="@dimen/all_apps_button_drawable_padding"
+        android:drawableLeft="@drawable/ic_home_all_apps_holo_dark"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toLeftOf="@id/divider"
+        android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
+        android:paddingRight="@dimen/toolbar_button_horizontal_padding"
+        android:paddingTop="@dimen/all_apps_button_vertical_padding"
+        android:paddingBottom="@dimen/all_apps_button_vertical_padding"
+        android:background="@drawable/button_bg"
+
+        android:gravity="center_horizontal|center_vertical"
+        android:textColor="#CCFFFFFF"
+        android:textSize="18sp"
+
+        launcher:strokeColor="#991e3157"
+        launcher:strokeTextColor="#DDFFFFFF"
+        launcher:strokeWidth="2.5"
+
+        android:shadowColor="#DA000000"
+        android:shadowDx="0.0"
+        android:shadowDy="0.0"
+        android:shadowRadius="2.5"
+
+        android:focusable="true"
+        android:clickable="true" />
+    <ImageView
+        android:id="@+id/divider_during_drag"
+        android:src="@drawable/divider_launcher_holo"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_toLeftOf="@id/configure_button"
+        android:paddingTop="@dimen/toolbar_button_vertical_padding"
+        android:paddingBottom="@dimen/toolbar_button_vertical_padding"
+        android:visibility="gone" />
+    <com.android.launcher2.DeleteZone
+        android:id="@+id/delete_zone"
+        android:text="@string/delete_zone_label_workspace"
+        android:drawablePadding="@dimen/delete_zone_drawable_padding"
+        android:drawableLeft="@drawable/delete_zone_selector"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignRight="@id/configure_button"
+        android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
+        android:paddingRight="@dimen/toolbar_button_horizontal_padding"
+        android:paddingTop="@dimen/toolbar_button_vertical_padding"
+        android:paddingBottom="@dimen/toolbar_button_vertical_padding"
+        android:background="@drawable/button_bg"
+
+        android:gravity="center_horizontal|center_vertical"
+        android:textColor="@color/workspace_all_apps_and_delete_zone_text_color"
+        android:textSize="18sp"
+        android:shadowColor="@color/workspace_all_apps_and_delete_zone_text_shadow_color"
+        android:shadowDx="0.0"
+        android:shadowDy="0.0"
+        android:shadowRadius="2.0"
+
+        android:visibility="gone"
+        launcher:direction="horizontal" />
+</RelativeLayout>
\ No newline at end of file
diff --git a/res/layout-xlarge/customization_drawer.xml b/res/layout-xlarge/customization_drawer.xml
new file mode 100644
index 0000000..dd1234c
--- /dev/null
+++ b/res/layout-xlarge/customization_drawer.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<TabHost xmlns:android="http://schemas.android.com/apk/res/android">
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+        <TabWidget
+            android:id="@android:id/tabs"
+            android:layout_width="@dimen/customization_drawer_tab_widget_width"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:background="@drawable/tab_unselected_holo"
+            android:tabStripEnabled="false" />
+        <FrameLayout
+            android:id="@android:id/tabcontent"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/customization_drawer_content_height">
+         </FrameLayout>
+      </LinearLayout>
+</TabHost>
\ No newline at end of file
diff --git a/res/layout-xlarge/customize_paged_view_wallpaper.xml b/res/layout-xlarge/customize_paged_view_wallpaper.xml
index e3be86d..8c5abc8 100644
--- a/res/layout-xlarge/customize_paged_view_wallpaper.xml
+++ b/res/layout-xlarge/customize_paged_view_wallpaper.xml
@@ -18,12 +18,11 @@
     xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
 
     android:layout_width="wrap_content"
-    android:layout_height="365dp"
-    android:paddingLeft="12.5dp"
-    android:paddingRight="12.5dp"
-    android:paddingBottom="50dp"
-    android:gravity="top"
+    android:layout_height="match_parent"
+    android:layout_weight="1"
     android:orientation="vertical"
+    android:paddingRight="25dp"
+    android:paddingBottom="50dp"
 
     launcher:blurColor="#FF6B8CF0"
     launcher:outlineColor="#FF8CD2FF">
@@ -33,7 +32,8 @@
         android:id="@+id/wallpaper_preview"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_weight="1.0"
+        android:layout_weight="1"
+        android:adjustViewBounds="true"
         android:scaleType="fitStart" />
 
     <!-- The divider image. -->
@@ -41,6 +41,7 @@
         android:id="@+id/divider"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_weight="0"
         android:paddingTop="10dp"
         android:paddingBottom="10dp"
         android:src="@drawable/widget_divider" />
@@ -50,6 +51,7 @@
         android:id="@+id/wallpaper_name"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_weight="0"
         android:gravity="left"
 
         android:textColor="#FFFFFFFF"
diff --git a/res/layout-xlarge/customize_paged_view_widget.xml b/res/layout-xlarge/customize_paged_view_widget.xml
index 3b95ebc..c0b4552 100644
--- a/res/layout-xlarge/customize_paged_view_widget.xml
+++ b/res/layout-xlarge/customize_paged_view_widget.xml
@@ -18,13 +18,11 @@
     xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
 
     android:layout_width="wrap_content"
-    android:layout_height="365dp"
-    android:paddingLeft="12.5dp"
-    android:paddingTop="12.5dp"
-    android:paddingRight="12.5dp"
-    android:paddingBottom="50dp"
-    android:gravity="top"
+    android:layout_height="match_parent"
+    android:layout_weight="1"
     android:orientation="vertical"
+    android:paddingRight="25dp"
+    android:paddingBottom="50dp"
 
     launcher:blurColor="#FF6B8CF0"
     launcher:outlineColor="#FF8CD2FF">
@@ -34,7 +32,8 @@
         android:id="@+id/widget_preview"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_weight="1.0"
+        android:layout_weight="1"
+        android:adjustViewBounds="true"
         android:scaleType="fitStart" />
 
     <!-- The divider image. -->
@@ -42,6 +41,7 @@
         android:id="@+id/divider"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_weight="0"
         android:paddingTop="10dp"
         android:paddingBottom="10dp"
         android:src="@drawable/widget_divider" />
@@ -51,6 +51,7 @@
         android:id="@+id/widget_name"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_weight="0"
         android:gravity="left"
 
         android:textColor="#FFFFFFFF"
@@ -69,6 +70,7 @@
         android:id="@+id/widget_dims"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_weight="0"
         android:gravity="left"
 
         android:textColor="#FF999999"
diff --git a/res/layout-xlarge/launcher.xml b/res/layout-xlarge/launcher.xml
new file mode 100644
index 0000000..acf62f9
--- /dev/null
+++ b/res/layout-xlarge/launcher.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<com.android.launcher2.DragLayer
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+
+    android:id="@+id/drag_layer"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <!-- The workspace contains 5 screens of cells -->
+    <com.android.launcher2.Workspace
+        android:id="@+id/workspace"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:paddingTop="?android:attr/actionBarSize"
+        android:paddingBottom="10dp"
+        launcher:defaultScreen="2"
+        launcher:cellCountX="8"
+        launcher:cellCountY="7"
+        launcher:pageSpacing="@dimen/workspace_page_spacing">
+
+        <include android:id="@+id/cell1" layout="@layout/workspace_screen" />
+        <include android:id="@+id/cell2" layout="@layout/workspace_screen" />
+        <include android:id="@+id/cell3" layout="@layout/workspace_screen" />
+        <include android:id="@+id/cell4" layout="@layout/workspace_screen" />
+        <include android:id="@+id/cell5" layout="@layout/workspace_screen" />
+    </com.android.launcher2.Workspace>
+
+    <include
+        layout="@layout/all_apps_tabbed"
+        android:id="@+id/all_apps_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="top" />
+
+    <include layout="@layout/button_bar"
+        android:id="@+id/all_apps_button_cluster"
+        android:layout_width="fill_parent"
+        android:layout_height="?android:attr/actionBarSize"
+        android:layout_gravity="top" />
+
+    <include layout="@layout/customization_drawer"
+        android:id="@+id/customization_drawer"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/customization_drawer_height"
+        android:layout_gravity="bottom" />
+</com.android.launcher2.DragLayer>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 8f955b2..df0a210 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"تطبيقاتي"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"لم يتم العثور على ألعاب"</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"ليس لديك أي تطبيقات تم تنزيلها."</string>
+    <string name="market" msgid="2652226429823445833">"تسوق"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"تعذر إسقاط العنصر على هذه الشاشة الرئيسية"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"تحديد أداة للإنشاء"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"اسم المجلد"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"الرئيسية"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"إزالة"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"إزالة"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"إزالة التحديث"</string>
     <string name="menu_add" msgid="3065046628354640854">"إضافة"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"إدارة التطبيقات"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"خلفية"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index fe9eefb..5be82f1 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Моите приложения"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Няма намерени игри."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Нямате изтеглени приложения."</string>
+    <string name="market" msgid="2652226429823445833">"Магазин"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Елементът не можа да се премести на началния екран"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Избор на създаващо приспособление"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Име на папка"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Начало"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Премахване"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Деинсталиране"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Деинстал. на актуализацията"</string>
     <string name="menu_add" msgid="3065046628354640854">"Добавяне"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Управление на приложенията"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Тапет"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 91a85cf..56ada67 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Les meves aplicacions"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"No s\'ha trobat cap joc."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"No has baixat cap aplicació."</string>
+    <string name="market" msgid="2652226429823445833">"Botiga"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"No s\'ha pogut trasll. l\'element a la pant. d\'inici"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Selecciona un widget per crear-lo"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Nom de la carpeta"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Pàgina d\'inici"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Elimina"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Desinstal·la"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Desinstal·la l\'actualització"</string>
     <string name="menu_add" msgid="3065046628354640854">"Afegeix"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Gestiona les aplicacions"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Empaperat"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 8a3063e..47fb726 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Moje aplikace"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Nenalezeny žádné hry."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Nemáte žádné stažené aplikace."</string>
+    <string name="market" msgid="2652226429823445833">"Obchod"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Na tuto plochu nelze položku přetáhnout"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Vyberte widget"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Název složky"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Plocha"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Odebrat"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Odinstalovat"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Odinstalovat aktualizaci"</string>
     <string name="menu_add" msgid="3065046628354640854">"Přidat"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Spravovat aplikace"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Tapeta"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index ae10220..f481234 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Mine apps"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Ingen spil."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Du har ingen downloadede applikationer."</string>
+    <string name="market" msgid="2652226429823445833">"Butik"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Kunne ikke slippe elementet på denne startskærm"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Vælg widget for at oprette"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Mappenavn"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Start"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Fjern"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Afinstaller"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Afinstaller opdatering"</string>
     <string name="menu_add" msgid="3065046628354640854">"Tilføj"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Administrer programmer"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Tapet"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 6532237..f69ee43 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -25,7 +25,7 @@
     <string name="chooser_wallpaper" msgid="5988031014201479733">"Hintergrund auswählen"</string>
     <string name="wallpaper_instructions" msgid="4215640646180727542">"Hintergrund festlegen"</string>
     <string name="pick_wallpaper" msgid="5630222540525626723">"Hintergrundbilder"</string>
-    <string name="activity_not_found" msgid="5591731020063337696">"Anwendung ist nicht installiert."</string>
+    <string name="activity_not_found" msgid="5591731020063337696">"Die Anwendung ist nicht installiert."</string>
     <string name="configure_wallpaper" msgid="2820186271419674623">"Konfigurieren..."</string>
     <string name="widgets_tab_label" msgid="9145860100000983599">"Widgets"</string>
     <string name="folders_tab_label" msgid="1145293785541489736">"Ordner"</string>
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Meine Apps"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Keine Spiele gefunden."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Keine heruntergeladenen Anwendungen vorhanden"</string>
+    <string name="market" msgid="2652226429823445833">"Shop"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Element wurde nicht auf Startbildschirm abgelegt."</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Widget für Erstellung auswählen"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Ordnername"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Startseite"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Entfernen"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Deinstallieren"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Update deinstallieren"</string>
     <string name="menu_add" msgid="3065046628354640854">"Hinzufügen"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Apps verwalten"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Hintergrund"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 5cebab7..5e9b644 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Οι εφαρμογές μου"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Δεν βρέθηκαν παιχνίδια."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Δεν υπάρχουν εφαρμογές από λήψη."</string>
+    <string name="market" msgid="2652226429823445833">"Αγορές"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Δεν έγινε η απόθ. του στοιχείου στην αρχική οθόνη"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Επιλογή γραφ. στοιχείου δημιουργίας"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Όνομα φακέλου"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Αρχική σελίδα"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Κατάργηση"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Κατάργηση εγκατάστασης"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Κατάργηση εγκατάστασης ενημέρωσης"</string>
     <string name="menu_add" msgid="3065046628354640854">"Προσθήκη"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Διαχείριση εφαρμογών"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Ταπετσαρία"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 5693d76..7334133 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"My apps"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"No games found."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"You have no downloaded applications."</string>
+    <string name="market" msgid="2652226429823445833">"Shop"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Could not drop item onto this home screen"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Select widget to create"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Folder name"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Home"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Remove"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Uninstall"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Uninstall update"</string>
     <string name="menu_add" msgid="3065046628354640854">"Add"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Manage apps"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Wallpaper"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 207d5b5..eadcbae 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Mis aplicaciones"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"No se encontraron juegos."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"No has descargado ninguna aplicación."</string>
+    <string name="market" msgid="2652226429823445833">"Comprar"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"No se pudo colocar el elemento en esta pantalla principal"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Seleccionar widget para crear"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Nombre de carpeta"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Página principal"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Quitar"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Desinstalar"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Desinstalar la actualización"</string>
     <string name="menu_add" msgid="3065046628354640854">"Agregar"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Administrar aplicaciones"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Papel tapiz"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 0592f99..90b4e1d 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Mis aplicaciones"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"No hay juegos."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"No tienes aplicaciones descargadas."</string>
+    <string name="market" msgid="2652226429823445833">"Tienda"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"No se puede soltar el elemento en este escritorio."</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Seleccionar widget"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Nombre de carpeta"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Inicio"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Eliminar del  escritorio"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Desinstalar"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Desinstalar actualización"</string>
     <string name="menu_add" msgid="3065046628354640854">"Añadir"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Administrar aplicaciones"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Fondo de pantalla"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 11b9f2d..0d53ea5 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"برنامه های من"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"هیچ بازی پیدا نشد."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"شما هیچ برنامه کاربردی دانلود شده ای ندارید."</string>
+    <string name="market" msgid="2652226429823445833">"فروشگاه"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"نمی توان موردی در این صفحه اصلی انداخت"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"انتخاب ابزارک جهت ایجاد"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"نام پوشه"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"صفحه اصلی"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"حذف"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"حذف نصب"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"حذف نصب به روزرسانی"</string>
     <string name="menu_add" msgid="3065046628354640854">"افزودن"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"مدیریت برنامه ها"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"تصویر زمینه"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 7aee9f1..7b02c8d 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Omat sovellukset"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Ei pelejä."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Ei ladattuja sovelluksia."</string>
+    <string name="market" msgid="2652226429823445833">"Myymälä"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Kohdetta ei voi lisätä etusivulle"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Valitse luotava widget"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Kansion nimi"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Etusivu"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Poista"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Poista"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Poista päivitys"</string>
     <string name="menu_add" msgid="3065046628354640854">"Lisää"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Hallinnoi sovelluksia"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Taustakuva"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index efcbc8a..7ff39d7 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Mes applications"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Aucun jeu n\'a été trouvé."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Vous n\'avez téléchargé aucune application."</string>
+    <string name="market" msgid="2652226429823445833">"Acheter"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Impossible de déposer l\'élément sur l\'écran d\'accueil."</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Sélectionner le widget à créer"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Nom du dossier"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Page d\'accueil"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Supprimer"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Désinstaller"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Désinstaller la mise à jour"</string>
     <string name="menu_add" msgid="3065046628354640854">"Ajouter"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Gérer les applications"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Fond d\'écran"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 848f539..ea09db0 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Moje aplikacije"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Igre nisu pronađene."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Nemate preuzetih aplikacija"</string>
+    <string name="market" msgid="2652226429823445833">"Trgovina"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Nije bilo moguće spustiti stavku na početni zaslon"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Odabir widgeta za stvaranje"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Naziv mape"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Početna"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Ukloni"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Deinstaliraj"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Deinstalacija ažuriranja"</string>
     <string name="menu_add" msgid="3065046628354640854">"Dodaj"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Upravljaj aplikacijama"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Pozadinska slika"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 81be5a7..77d9dda 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Saját alkalmazások"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Nincsenek játékok."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Nincsenek letöltött alkalmazásai."</string>
+    <string name="market" msgid="2652226429823445833">"Bolt"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Nem lehet elhelyezni az elemet ezen a főoldalon"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"A létrehozandó modul kiválasztása"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Mappa neve"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Főoldal"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Eltávolítás"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Eltávolítás"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Eltávolítja a frissítést"</string>
     <string name="menu_add" msgid="3065046628354640854">"Hozzáadás"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Alkalmazások kezelése"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Háttérkép"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 4abe037..a7ed856 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Apl saya"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Tidak ditemukan permainan."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Anda tidak memiliki aplikasi yang diunduh."</string>
+    <string name="market" msgid="2652226429823445833">"Belanja"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Tidak dapat menaruh item pada layar utama ini"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Pilih widget untuk membuat"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Nama map"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Rumah"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Hapus"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Copot pemasangan"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Copot pemasangan pemutakhiran"</string>
     <string name="menu_add" msgid="3065046628354640854">"Tambahkan"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Mengelola aplikasi"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Wallpaper"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 4205973..003db6f 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Le mie applicazioni"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Nessun gioco trovato."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Non hai applicazioni scaricate."</string>
+    <string name="market" msgid="2652226429823445833">"Acquista"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Impossibile rilasciare elemento in schermata Home"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Seleziona il widget da creare"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Nome cartella"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Home"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Rimuovi"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Disinstalla"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Disinstalla aggiornamento"</string>
     <string name="menu_add" msgid="3065046628354640854">"Aggiungi"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Gestisci applicazioni"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Sfondo"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 8eaa433..75df245 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"היישומים שלי"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"לא נמצאו משחקים."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"לא הורדת יישומים."</string>
+    <string name="market" msgid="2652226429823445833">"קנה"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"אין אפשרות להניח פריט במסך בית זה"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"בחר widget כדי ליצור"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"שם תיקיה"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"דף הבית"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"הסר"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"הסר התקנה"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"הסר את התקנת העדכון"</string>
     <string name="menu_add" msgid="3065046628354640854">"הוסף"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"נהל יישומים"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"טפט"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 0264232..ee6ab83 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"マイアプリ"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"ゲームなし"</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"ダウンロードしたアプリケーションはありません。"</string>
+    <string name="market" msgid="2652226429823445833">"ショップ"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"このホーム画面にアイテムをドロップできませんでした"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"作成するウィジェットを選択"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"フォルダ名"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"ホーム"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"削除"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"アンインストール"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"アップデートをアンインストール"</string>
     <string name="menu_add" msgid="3065046628354640854">"追加"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"アプリの管理"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"壁紙"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 41de035..f2b8b0c 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"내 애플리케이션"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"게임이 없습니다."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"다운로드한 애플리케이션이 없습니다."</string>
+    <string name="market" msgid="2652226429823445833">"쇼핑"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"홈 화면에 항목을 드롭할 수 없습니다."</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"만들 위젯 선택"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"폴더 이름"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"홈"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"삭제"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"제거"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"업데이트 제거"</string>
     <string name="menu_add" msgid="3065046628354640854">"추가"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"애플리케이션 관리"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"배경화면"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 98817fd..acf0e27 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Mano programos"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Nerasta žaidimų."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Neturite atsisiųstų programų."</string>
+    <string name="market" msgid="2652226429823445833">"Parduotuvė"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Nepavyko pašalinti elemento šiame pagr. ekrane"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Pasirinkti norimą sukurti valdiklį"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Aplanko pavadinimas"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Pagrindinis"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Pašalinti"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Pašalinti"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Pašalinti naujinį"</string>
     <string name="menu_add" msgid="3065046628354640854">"Pridėti"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Valdyti programas"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Darbalaukio fonas"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index fec6492..9c1b389 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Manas lietotnes"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Nav nevienas spēles."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Nav ielādēta neviena lietojumprogramma."</string>
+    <string name="market" msgid="2652226429823445833">"Iepirkties"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Nevarēja nomest vienumu šajā sākumekrānā."</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Atlasīt izveidojamo logrīku"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Mapes nosaukums"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Sākums"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Noņemt"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Atinstalēt"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Atinstalēt atjauninājumu"</string>
     <string name="menu_add" msgid="3065046628354640854">"Pievienot"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Lietotņu pārvaldība"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Fona tapete"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 998812b..ccdab7e 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Mine programmer"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Finner ingen spill."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Du har ingen nedlastede programmer."</string>
+    <string name="market" msgid="2652226429823445833">"Butikk"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Kunne ikke slippe elementet på denne startskjermen"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Velg modul for oppretting"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Mappenavn"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Startsiden"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Fjern"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Avinstaller"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Avinstaller oppdateringen"</string>
     <string name="menu_add" msgid="3065046628354640854">"Legg til"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Administrer programmer"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Bakgrunnsbilde"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 95ef9a0..3d7c7ac 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Mijn apps"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Geen games gevonden."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"U heeft geen gedownloade apps."</string>
+    <string name="market" msgid="2652226429823445833">"Winkel"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Kan item niet neerzetten op dit startscherm"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Widget selecteren om te maken"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Mapnaam"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Startpagina"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Verwijderen"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Verwijderen"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Update verwijderen"</string>
     <string name="menu_add" msgid="3065046628354640854">"Toevoegen"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Apps beheren"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Achtergrond"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index b457e56..f116165 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Moje aplikacje"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Nie znaleziono gier."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Nie masz żadnych pobranych aplikacji."</string>
+    <string name="market" msgid="2652226429823445833">"Sklep"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Nie można upuścić elementu na ekranie głównym"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Wybierz widżet do utworzenia"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Nazwa folderu"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Ekran główny"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Usuń"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Odinstaluj"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Odinstaluj aktualizację"</string>
     <string name="menu_add" msgid="3065046628354640854">"Dodaj"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Zarządzaj aplikacjami"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Tapeta"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 931a8ea..a3a5a8d 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"As minhas aplicações"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Sem jogos."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Não existem aplicações transferidas."</string>
+    <string name="market" msgid="2652226429823445833">"Loja"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Não foi possível largar o item neste ecrã inicial"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Seleccionar widget a criar"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Nome da pasta"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Página inicial"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Remover"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Desinstalar"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Desinstalar atualização"</string>
     <string name="menu_add" msgid="3065046628354640854">"Adicionar"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Gerir aplicações"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Imagem de fundo"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index c4fb78a..55deb94 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Meus aplicativos"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Nenhum jogo encontrado."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Você não tem nenhum aplicativo transferido."</string>
+    <string name="market" msgid="2652226429823445833">"Comprar"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Não foi possível soltar o item nesta tela inicial"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Selecione um widget para criar"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Nome da pasta"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Página inicial"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Remover"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Desinstalar"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Desinstalar atualização"</string>
     <string name="menu_add" msgid="3065046628354640854">"Adicionar"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Gerenciar aplicativos"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Plano de fundo"</string>
diff --git a/res/values-rm/strings.xml b/res/values-rm/strings.xml
index 6ac87d4..1b5729b 100644
--- a/res/values-rm/strings.xml
+++ b/res/values-rm/strings.xml
@@ -51,6 +51,8 @@
     <skip />
     <!-- no translation found for all_apps_no_downloads (2284720393234453761) -->
     <skip />
+    <!-- no translation found for market (2652226429823445833) -->
+    <skip />
     <!-- no translation found for external_drop_widget_error (4976816434597126575) -->
     <skip />
     <!-- no translation found for external_drop_widget_pick_title (4481311720134376218) -->
@@ -83,6 +85,8 @@
     <skip />
     <!-- no translation found for delete_zone_label_all_apps (6664588234817475108) -->
     <skip />
+    <!-- no translation found for delete_zone_label_all_apps_system_app (3683920959591819044) -->
+    <skip />
     <string name="menu_add" msgid="3065046628354640854">"Agiuntar"</string>
     <!-- no translation found for menu_manage_apps (2308685199463588895) -->
     <skip />
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 7addc18..3a72c51 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Aplicaţiile mele"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Nu s-au găsit jocuri."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Nu aveţi aplicaţii descărcate."</string>
+    <string name="market" msgid="2652226429823445833">"Cumpăraţi"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Impos. de plasat elem. pe acest ecran de pornire"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Selectaţi obiectul widget"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Nume dosar"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Domiciliu"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Eliminaţi"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Dezinstalaţi"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Dezinstalaţi actualizarea"</string>
     <string name="menu_add" msgid="3065046628354640854">"Adăugaţi"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Gestionaţi aplicaţii"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Imagine de fundal"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 76ef1ff..912c3f4 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Мои приложения"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Игр не найдено."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"У вас нет загруженных приложений."</string>
+    <string name="market" msgid="2652226429823445833">"Маркет"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Не удается скопировать элемент на главный экран"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Выберите виджет"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Название папки"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Главная"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Удалить"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Удалить"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Удалить обновление"</string>
     <string name="menu_add" msgid="3065046628354640854">"Добавить"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Приложения"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Обои"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 90cc9eb..3cadf3b 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Moje aplikácie"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Nenašli sa žiadne hry."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Nemáte žiadne prevzaté aplikácie."</string>
+    <string name="market" msgid="2652226429823445833">"Obchod"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Položku sa nepodarilo pretiahnuť na túto plochu"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Vyberte miniaplikáciu"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Názov priečinka"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Domovská stránka"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Odstrániť"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Odinštalovať"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Odinštalovať aktualizáciu"</string>
     <string name="menu_add" msgid="3065046628354640854">"Pridať"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Spravovať aplikácie"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Tapeta"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 8ceeb87..daf0899 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Moji programi"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Ni najdenih iger."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Ni prenesenih programov."</string>
+    <string name="market" msgid="2652226429823445833">"Nakup"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Elementa ni bilo mogoče postaviti na ta začetni zaslon"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Izberite želeni pripomoček"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Ime mape"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Začetni zaslon"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Odstrani"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Odstrani"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Odstrani posodobitev"</string>
     <string name="menu_add" msgid="3065046628354640854">"Dodaj"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Upravljaj programe"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Slika za ozadje"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 5c89227..1d92080 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Моје апликације"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Нису пронађене игре."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Немате ниједну преузету апликацију."</string>
+    <string name="market" msgid="2652226429823445833">"Куповина"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Ставка није пребачена на овај почетни екран"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Изаберите виџет за креирање"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Име директоријума"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Почетна"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Уклони"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Деинсталирај"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Деинсталирај ажурирања"</string>
     <string name="menu_add" msgid="3065046628354640854">"Додај"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Управљање апликацијама"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Позадина"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index ad74885..8094f05 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Mina appar"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Inga spel hittades."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Du har inte hämtat några appar."</string>
+    <string name="market" msgid="2652226429823445833">"Butik"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Objektet kunde inte släppas på den här startsidan"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Välj en widget att skapa"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Mappnamn"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Startsida"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Ta bort"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Avinstallera"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Avinstallera uppdatering"</string>
     <string name="menu_add" msgid="3065046628354640854">"Lägg till"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Hantera appar"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Bakgrund"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 0a19cbb..26c33c9 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"แอปพลิเคชันของฉัน"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"ไม่พบเกม"</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"คุณไม่ได้ดาวน์โหลดแอปพลิเคชันไว้"</string>
+    <string name="market" msgid="2652226429823445833">"ร้าน"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"ไม่สามารถวางรายการลงในหน้าจอหลักนี้ได้"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"เลือกวิดเจ็ตที่จะสร้าง"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"ชื่อโฟลเดอร์"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"บ้าน"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"นำออก"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"ถอนการติดตั้ง"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"ถอนการติดตั้งการอัปเดต"</string>
     <string name="menu_add" msgid="3065046628354640854">"เพิ่ม"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"จัดการแอปพลิเคชัน"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"วอลเปเปอร์"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index f131b02..f21dc3c 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Aking mga app"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Walang nakitang mga laro."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Wala kang mga na-download na application."</string>
+    <string name="market" msgid="2652226429823445833">"Mamili"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Hindi ma-drop ang item sa homescreen na ito"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Pumili ng widget na lilikhain"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Pangalan ng folder"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Home"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Alisin"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"I-uninstall"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"I-uninstall ang update"</string>
     <string name="menu_add" msgid="3065046628354640854">"Idagdag"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Pamahalaan ang apps"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Wallpaper"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index c27c586..bf80bf5 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Uygulamalarım"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Oyun bulunamadı."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"İndirilmiş uygulamanız yok."</string>
+    <string name="market" msgid="2652226429823445833">"Alışveriş"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Öğe bu ana ekrana bırakılamadı"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Oluşturulacak widget\'i seç"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Klasör adı"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Ana Sayfa"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Kaldır"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Yüklemeyi Kaldır"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Güncelleme kaldırılsın mı?"</string>
     <string name="menu_add" msgid="3065046628354640854">"Ekle"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Uyglm yönet"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Duvar Kağıdı"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 2095bc9..267ca88 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Мої програми"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Ігор не знайдено."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"У вас немає завантажених програм."</string>
+    <string name="market" msgid="2652226429823445833">"Магазин"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Неможливо помістити елемент на цей головний екран"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Вибрати віджет для створення"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Назва папки"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Головна"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Видалити"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Видалити"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Видалити оновлення"</string>
     <string name="menu_add" msgid="3065046628354640854">"Додати"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Керув. прогр."</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Фоновий мал."</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 8e5b4c3..d3f549f 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"Ứng dụng của tôi"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"Không tìm thấy trò chơi."</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"Bạn không có ứng dụng nào được tải xuống."</string>
+    <string name="market" msgid="2652226429823445833">"Mua hàng"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"Không thể thả mục vào màn hình chính này"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Chọn tiện ích để tạo"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"Tên thư mục"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Màn hình trang chủ"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Xóa"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Gỡ cài đặt"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Gỡ cài đặt cập nhật"</string>
     <string name="menu_add" msgid="3065046628354640854">"Thêm"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Quản lý ứng dụng"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"Hình nền"</string>
diff --git a/res/values-xlarge-land/dimens.xml b/res/values-xlarge-land/dimens.xml
index 51037f5..b3d40d5 100644
--- a/res/values-xlarge-land/dimens.xml
+++ b/res/values-xlarge-land/dimens.xml
@@ -22,4 +22,11 @@
     <!-- Width/height gap overrides for the workspace -->
     <dimen name="workspace_width_gap">32dp</dimen>
     <dimen name="workspace_height_gap">2dp</dimen>
+
+    <dimen name="workspace_page_spacing">50dp</dimen>
+
+    <dimen name="customization_drawer_height">480dp</dimen>
+    <dimen name="customization_drawer_content_height">420dp</dimen>
+    <dimen name="customization_drawer_content_min_width">952dp</dimen>
+    <dimen name="customization_drawer_tab_widget_width">952dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/res/values-xlarge-port/dimens.xml b/res/values-xlarge-port/dimens.xml
index baa31aa..8a4c78b 100644
--- a/res/values-xlarge-port/dimens.xml
+++ b/res/values-xlarge-port/dimens.xml
@@ -22,4 +22,11 @@
     <!-- Width/height gap overrides for the workspace -->
     <dimen name="workspace_width_gap">0dp</dimen>
     <dimen name="workspace_height_gap">32dp</dimen>
+
+    <dimen name="workspace_page_spacing">64dp</dimen>
+
+    <dimen name="customization_drawer_height">800dp</dimen>
+    <dimen name="customization_drawer_content_height">420dp</dimen>
+    <dimen name="customization_drawer_content_min_width">640dp</dimen>
+    <dimen name="customization_drawer_tab_widget_width">700dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/res/values-xlarge/config.xml b/res/values-xlarge/config.xml
index dc9d096..56c7bc6 100644
--- a/res/values-xlarge/config.xml
+++ b/res/values-xlarge/config.xml
@@ -9,7 +9,8 @@
 
     <!-- Duration in milliseconds of the all apps / configuration zoom-in animation. -->
     <!-- NB: This should be less than the workspaceShrinkTime as they happen together. -->
-    <integer name="config_allAppsZoomInTime">1450</integer>
+    <integer name="config_allAppsZoomInTime">1000</integer>
+    <integer name="config_allAppsFadeInTime">250</integer>
 
     <!-- Duration in milliseconds of the transition between tabs in the all apps/customize
          tray -->
@@ -25,6 +26,7 @@
     <!-- Duration in milliseconds of the all apps / configuration zoom-in animation. -->
     <!-- NB: This should be less than the workspaceShrinkTime as they happen together. -->
     <integer name="config_customizeZoomInTime">800</integer>
+    <integer name="config_customizeFadeInTime">800</integer>
 
     <!-- Duration in milliseconds of the all apps zoom-out animation -->
     <!-- NB: This should be less than the workspaceUnshrinkTime as they happen together. -->
@@ -35,10 +37,9 @@
 
     <!-- Duration in milliseconds of the animations between all apps, customize, & home.
          NOTE: If these are changed, the toolbar animation times below should also be. -->
-    <integer name="config_allAppsCameraPanTime">700</integer>
     <integer name="config_allAppsFadeOutTime">500</integer>
     <integer name="config_customizeWorkspaceShrinkTime">800</integer>
-    <integer name="config_allAppsWorkspaceShrinkTime">1450</integer>
+    <integer name="config_allAppsWorkspaceShrinkTime">1000</integer>
     <integer name="config_workspaceUnshrinkTime">650</integer>
 
     <!-- Duration in milliseconds toolbar fade in and fade out animations.
@@ -66,12 +67,6 @@
     <integer name="config_screenOnDropAlphaFadeDelay">350</integer>
     <integer name="config_screenOnDropAlphaFadeDuration">50</integer>
 
-    <!-- Workspace screens are cached to bitmaps only when they're smaller than a certain size
-         (maxScaleForUsingWorkspaceScreenBitmapCache), since the bitmap cache itself is smaller
-         than the view itself (workspaceScreenBitmapCacheScale)  -->
-    <integer name="config_workspaceScreenBitmapCacheScale">20</integer>
-    <integer name="config_maxScaleForUsingWorkspaceScreenBitmapCache">50</integer>
-
     <!-- The slope, in percent, of the drag movement needed to drag an item out of the customization
          drawer (y / x * 100%)  -->
     <integer name="config_customizationDrawerDragSlopeThreshold">150</integer>
diff --git a/res/values-xlarge/dimens.xml b/res/values-xlarge/dimens.xml
index c4988e4..421c9e3 100644
--- a/res/values-xlarge/dimens.xml
+++ b/res/values-xlarge/dimens.xml
@@ -37,11 +37,6 @@
     <dimen name="allAppsSmallScreenVerticalMarginLandscape">30dip</dimen>
     <dimen name="allAppsSmallScreenVerticalMarginPortrait">60dip</dimen>
 
-    <!-- Vertical spacing between edge of screen and mini cell layouts when they
-         are minimized to the top when the customization drawer is showing -->
-    <dimen name="customizeSmallScreenVerticalMarginLandscape">90dip</dimen>
-    <dimen name="customizeSmallScreenVerticalMarginPortrait">180dip</dimen>
-
     <dimen name="delete_zone_drawable_padding">8dip</dimen>
     <dimen name="all_apps_button_drawable_padding">0dip</dimen>
     <dimen name="all_apps_button_vertical_padding">4dip</dimen>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index cd840c3..a3dc212 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"我的应用程序"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"未找到游戏。"</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"您没有下载任何应用程序。"</string>
+    <string name="market" msgid="2652226429823445833">"购买"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"无法将该项放到主屏幕上"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"选择窗口小部件进行创建"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"文件夹名称"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"主屏幕"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"删除"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"卸载"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"卸载更新"</string>
     <string name="menu_add" msgid="3065046628354640854">"添加"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"管理应用程序"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"壁纸"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 0622dde..2274274 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -39,6 +39,7 @@
     <string name="all_apps_tab_downloaded" msgid="1488049110598641387">"我的應用程式"</string>
     <string name="all_apps_no_games" msgid="5293893733372793696">"找不到遊戲。"</string>
     <string name="all_apps_no_downloads" msgid="2284720393234453761">"您沒有下載任何應用程式。"</string>
+    <string name="market" msgid="2652226429823445833">"商店"</string>
     <string name="external_drop_widget_error" msgid="4976816434597126575">"無法將項目拖放至主螢幕上"</string>
     <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"選取要建立的小工具"</string>
     <string name="rename_folder_label" msgid="5646236631298452787">"資料夾名稱"</string>
@@ -66,6 +67,7 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"主螢幕"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"移除"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"解除安裝"</string>
+    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"解除安裝更新"</string>
     <string name="menu_add" msgid="3065046628354640854">"新增"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"管理應用程式"</string>
     <string name="menu_wallpaper" msgid="5837429080911269832">"桌布"</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 5e6a2ab..2be5999 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -61,6 +61,16 @@
 
     </declare-styleable>
 
+    <!-- StrokedTextView specific attributes. -->
+    <declare-styleable name="StrokedTextView">
+        <!-- The color of the stroke outline -->
+        <attr name="strokeColor" format="color" />
+        <!-- The color of the text -->
+        <attr name="strokeTextColor" format="color" />
+        <!-- The width of the stroke -->
+        <attr name="strokeWidth" format="float" />
+    </declare-styleable>
+
     <!-- PagedViewIcon specific attributes. These attributes are used to customize
          a PagedViewIcon view in XML files. -->
     <declare-styleable name="PagedViewIcon">
diff --git a/res/values/config.xml b/res/values/config.xml
index 850c609..c56a8ce 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -25,12 +25,6 @@
     <!-- The alpha value at which to show the most recent drop visualization outline. -->
     <integer name="config_dragOutlineMaxAlpha">128</integer>
 
-    <!-- Workspace screens are cached to bitmaps only when they're smaller than a certain size
-         (maxScaleForUsingWorkspaceScreenBitmapCache), since the bitmap cache it self is smaller
-         than the view itself (workspaceScreenBitmapCacheScale)  -->
-    <integer name="config_workspaceScreenBitmapCacheScale">20</integer>
-    <integer name="config_maxScaleForUsingWorkspaceScreenBitmapCache">50</integer>
-
     <!-- Parameters controlling the animation for when an item is dropped on the home screen,
          and it animates from its old position to the new one. -->
 
@@ -39,6 +33,12 @@
     <!-- The distance at which the animation should take the max duration -->
     <integer name="config_dropAnimMaxDist">800</integer>
 
+    <!-- Workspace screens are cached to bitmaps only when they're smaller than a certain size
+         (maxScaleForUsingWorkspaceScreenBitmapCache), since the bitmap cache itself is smaller
+         than the view itself (workspaceScreenBitmapCacheScale)  -->
+    <integer name="config_workspaceScreenBitmapCacheScale">20</integer>
+    <integer name="config_maxScaleForUsingWorkspaceScreenBitmapCache">50</integer>
+
     <style name="config_orientation">
         <item name="@android:screenOrientation">nosensor</item>
     </style>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6dcaa57..eedbd6a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -72,6 +72,8 @@
     <string name="all_apps_no_games">No games found.</string>
     <!-- Message to show when there are no downloaded apps [CHAR_LIMIT=50] -->
     <string name="all_apps_no_downloads">You have no downloaded applications.</string>
+    <!-- Market button text [CHAR LIMIT=32] -->
+    <string name="market">Shop</string>
 
     <!-- Customization Drawer -->
     <!-- The format string for the dimensions of a widget in the drawer -->
@@ -149,6 +151,10 @@
          device. [CHAR_LIMIT=30]-->
     <string name="delete_zone_label_all_apps">Uninstall</string>
 
+    <!-- Label for trash icon in All Apps, when an updated system app is selected. The update will
+         be uninstalled. [CHAR_LIMIT=30] -->
+    <string name="delete_zone_label_all_apps_system_app">Uninstall update</string>
+
     <!-- Menus items: -->
     <skip />
     <!-- Verb, menu item used to add an item on the desktop -->
diff --git a/src/com/android/launcher2/AllApps2D.java b/src/com/android/launcher2/AllApps2D.java
index 66d9395..1cbb999 100644
--- a/src/com/android/launcher2/AllApps2D.java
+++ b/src/com/android/launcher2/AllApps2D.java
@@ -211,7 +211,7 @@
     }
 
     @Override
-    public void onDropCompleted(View target, boolean success) {
+    public void onDropCompleted(View target, Object dragInfo, boolean success) {
     }
 
     /**
@@ -313,19 +313,9 @@
         mVisibleAppsList.clear();
         if (appType == AppType.ALL) {
             mVisibleAppsList.addAll(mAllAppsList);
-        } else {
-            int searchFlags = 0;
-
-            if (appType == AppType.APP) {
-                searchFlags = ApplicationInfo.APP_FLAG;
-            } else if (appType == AppType.GAME) {
-                searchFlags = ApplicationInfo.GAME_FLAG;
-            } else if (appType == AppType.DOWNLOADED) {
-                searchFlags = ApplicationInfo.DOWNLOADED_FLAG;
-            }
-
+        } else if (appType == AppType.DOWNLOADED) {
             for (ApplicationInfo info : mAllAppsList) {
-                if ((info.flags & searchFlags) != 0) {
+                if ((info.flags & ApplicationInfo.DOWNLOADED_FLAG) != 0) {
                     mVisibleAppsList.add(info);
                 }
             }
diff --git a/src/com/android/launcher2/AllApps3D.java b/src/com/android/launcher2/AllApps3D.java
index 2ecf761..29f49af 100644
--- a/src/com/android/launcher2/AllApps3D.java
+++ b/src/com/android/launcher2/AllApps3D.java
@@ -685,16 +685,14 @@
                 && mCurrentIconIndex >= 0 && mCurrentIconIndex < mAllAppsList.size()) {
             ApplicationInfo app = mAllAppsList.get(mCurrentIconIndex);
 
-            Bitmap bmp = app.iconBitmap;
-            final int w = bmp.getWidth();
-            final int h = bmp.getHeight();
+            final Bitmap bmp = app.iconBitmap;
 
             // We don't really have an accurate location to use.  This will do.
-            int screenX = mMotionDownRawX - (w / 2);
-            int screenY = mMotionDownRawY - h;
+            int screenX = mMotionDownRawX - (bmp.getWidth() / 2);
+            int screenY = mMotionDownRawY - bmp.getHeight();
 
-            mDragController.startDrag(bmp, screenX, screenY,
-                    0, 0, w, h, this, app, DragController.DRAG_ACTION_COPY);
+            mDragController.startDrag(
+                    bmp, screenX, screenY, this, app, DragController.DRAG_ACTION_COPY);
 
             mLauncher.closeAllApps(true);
         }
@@ -748,7 +746,7 @@
     }
 
     @Override
-    public void onDropCompleted(View target, boolean success) {
+    public void onDropCompleted(View target, Object dragInfo, boolean success) {
     }
 
     /**
diff --git a/src/com/android/launcher2/AllAppsBackground.java b/src/com/android/launcher2/AllAppsBackground.java
new file mode 100644
index 0000000..5292d0a
--- /dev/null
+++ b/src/com/android/launcher2/AllAppsBackground.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import com.android.launcher.R;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * An implementation of PagedView that populates the pages of the workspace
+ * with all of the user's applications.
+ */
+public class AllAppsBackground extends View {
+    private Drawable mBackground;
+
+    public AllAppsBackground(Context context) {
+        this(context, null);
+    }
+
+    public AllAppsBackground(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public AllAppsBackground(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        mBackground = getResources().getDrawable(R.drawable.all_apps_bg_gradient);
+    }
+
+    @Override
+    public void onDraw(Canvas canvas) {
+        mBackground.setBounds(mScrollX, 0, mScrollX + getMeasuredWidth(),
+                getMeasuredHeight());
+        mBackground.draw(canvas);
+    }
+}
diff --git a/src/com/android/launcher2/AllAppsPagedView.java b/src/com/android/launcher2/AllAppsPagedView.java
index daa5d64..b9b38c3 100644
--- a/src/com/android/launcher2/AllAppsPagedView.java
+++ b/src/com/android/launcher2/AllAppsPagedView.java
@@ -63,6 +63,7 @@
     private int mAppFilter = ALL_APPS_FLAG;
 
     private final LayoutInflater mInflater;
+    private boolean mAllowHardwareLayerCreation;
 
 
     public AllAppsPagedView(Context context) {
@@ -79,6 +80,8 @@
         mCellCountX = a.getInt(R.styleable.PagedView_cellCountX, 6);
         mCellCountY = a.getInt(R.styleable.PagedView_cellCountY, 4);
         mInflater = LayoutInflater.from(context);
+        mApps = new ArrayList<ApplicationInfo>();
+        mFilteredApps = new ArrayList<ApplicationInfo>();
         a.recycle();
         setSoundEffectsEnabled(false);
 
@@ -93,6 +96,22 @@
         mCenterPagesVertically = false;
     }
 
+    void allowHardwareLayerCreation() {
+        // This is called after the first time we launch into All Apps. Before that point,
+        // there's no need for hardware layers here since there's a hardware layer set on the
+        // parent, AllAppsTabbed, during the AllApps transition -- creating hardware layers here
+        // before the animation is done slows down the animation
+        if (mAllowHardwareLayerCreation) {
+            return;
+        }
+        mAllowHardwareLayerCreation = true;
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            PagedViewCellLayout page = (PagedViewCellLayout) getChildAt(i);
+            page.allowHardwareLayerCreation();
+        }
+    }
+
     @Override
     public void setLauncher(Launcher launcher) {
         mLauncher = launcher;
@@ -119,8 +138,6 @@
         cancelLongPress();
 
         if (isVisible()) {
-            getParent().bringChildToFront(this);
-            setVisibility(View.VISIBLE);
             if (animate) {
                 startAnimation(AnimationUtils.loadAnimation(getContext(),
                         R.anim.all_apps_2d_fade_in));
@@ -139,7 +156,6 @@
 
     protected void onAnimationEnd() {
         if (!isVisible()) {
-            setVisibility(View.GONE);
             mZoom = 0.0f;
 
             endChoiceMode();
@@ -201,11 +217,21 @@
         }
     }
 
-    private void setupDragMode() {
+    private void setupDragMode(ApplicationInfo info) {
         mLauncher.getWorkspace().shrink(Workspace.ShrinkState.BOTTOM_VISIBLE);
-        DeleteZone allAppsDeleteZone = (DeleteZone)
-                mLauncher.findViewById(R.id.all_apps_delete_zone);
-        allAppsDeleteZone.setDragAndDropEnabled(true);
+
+        // Only show the uninstall button if the app is uninstallable.
+        if ((info.flags & ApplicationInfo.DOWNLOADED_FLAG) != 0) {
+            DeleteZone allAppsDeleteZone = (DeleteZone)
+                    mLauncher.findViewById(R.id.all_apps_delete_zone);
+            allAppsDeleteZone.setDragAndDropEnabled(true);
+
+            if ((info.flags & ApplicationInfo.UPDATED_SYSTEM_APP_FLAG) != 0) {
+                allAppsDeleteZone.setText(R.string.delete_zone_label_all_apps_system_app);
+            } else {
+                allAppsDeleteZone.setText(R.string.delete_zone_label_all_apps);
+            }
+        }
 
         ApplicationInfoDropTarget allAppsInfoButton =
                 (ApplicationInfoDropTarget) mLauncher.findViewById(R.id.all_apps_info_target);
@@ -238,12 +264,12 @@
         if (!v.isInTouchMode()) return false;
         if (!super.beginDragging(v)) return false;
 
-        // Start drag mode after the item is selected
-        setupDragMode();
-
         ApplicationInfo app = (ApplicationInfo) v.getTag();
         app = new ApplicationInfo(app);
 
+        // Start drag mode after the item is selected
+        setupDragMode(app);
+
         // get icon (top compound drawable, index is 1)
         final TextView tv = (TextView) v;
         final Drawable icon = tv.getCompoundDrawables()[1];
@@ -282,7 +308,7 @@
     }
 
     @Override
-    public void onDropCompleted(View target, boolean success) {
+    public void onDropCompleted(View target, Object dragInfo, boolean success) {
         // close the choice action mode if we have a proper drop
         if (target != this) {
             endChoiceMode();
@@ -376,6 +402,7 @@
         }
         mFilteredApps = rebuildFilteredApps(mApps);
     }
+
     @Override
     public void removeApps(ArrayList<ApplicationInfo> list) {
         removeAppsWithoutInvalidate(list);
@@ -390,12 +417,14 @@
     }
 
     private int findAppByComponent(ArrayList<ApplicationInfo> list, ApplicationInfo item) {
-        ComponentName removeComponent = item.intent.getComponent();
-        final int length = list.size();
-        for (int i = 0; i < length; ++i) {
-            ApplicationInfo info = list.get(i);
-            if (info.intent.getComponent().equals(removeComponent)) {
-                return i;
+        if (item != null && item.intent != null) {
+            ComponentName removeComponent = item.intent.getComponent();
+            final int length = list.size();
+            for (int i = 0; i < length; ++i) {
+                ApplicationInfo info = list.get(i);
+                if (info.intent.getComponent().equals(removeComponent)) {
+                    return i;
+                }
             }
         }
         return -1;
@@ -420,12 +449,15 @@
         // remove any extra pages after the "last" page
         int extraPageDiff = curNumPages - numPages;
         for (int i = 0; i < extraPageDiff; ++i) {
+            PagedViewCellLayout page = (PagedViewCellLayout) getChildAt(numPages);
             removeViewAt(numPages);
         }
         // add any necessary pages
         for (int i = curNumPages; i < numPages; ++i) {
             PagedViewCellLayout layout = new PagedViewCellLayout(getContext());
-            layout.enableHardwareLayers();
+            if (mAllowHardwareLayerCreation) {
+                layout.allowHardwareLayerCreation();
+            }
             layout.setCellCount(mCellCountX, mCellCountY);
             layout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop,
                     mPageLayoutPaddingRight, mPageLayoutPaddingBottom);
@@ -515,6 +547,7 @@
             layout.addViewToCellLayout(icon, -1, 0,
                     new PagedViewCellLayout.LayoutParams(0, 0, 4, 1));
         }
+        layout.createHardwareLayers();
     }
 
     /*
diff --git a/src/com/android/launcher2/AllAppsTabbed.java b/src/com/android/launcher2/AllAppsTabbed.java
index 47a5bf7..0dd56ac 100644
--- a/src/com/android/launcher2/AllAppsTabbed.java
+++ b/src/com/android/launcher2/AllAppsTabbed.java
@@ -29,16 +29,19 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.TabHost;
 import android.widget.TabWidget;
 import android.widget.TextView;
+import android.widget.TabHost.OnTabChangeListener;
+import android.widget.TabHost.TabContentFactory;
 
 import java.util.ArrayList;
 
 /**
  * Implements a tabbed version of AllApps2D.
  */
-public class AllAppsTabbed extends TabHost implements AllAppsView {
+public class AllAppsTabbed extends TabHost implements AllAppsView, LauncherTransitionable {
 
     private static final String TAG = "Launcher.AllAppsTabbed";
 
@@ -46,6 +49,8 @@
     private static final String TAG_DOWNLOADED = "DOWNLOADED";
 
     private AllAppsPagedView mAllApps;
+    private AllAppsBackground mBackground;
+    private Launcher mLauncher;
     private Context mContext;
     private final LayoutInflater mInflater;
     private boolean mFirstLayout = true;
@@ -64,6 +69,8 @@
         try {
             mAllApps = (AllAppsPagedView) findViewById(R.id.all_apps_paged_view);
             if (mAllApps == null) throw new Resources.NotFoundException();
+            mBackground = (AllAppsBackground) findViewById(R.id.all_apps_background);
+            if (mBackground == null) throw new Resources.NotFoundException();
         } catch (Resources.NotFoundException e) {
             Log.e(TAG, "Can't find necessary layout elements for AllAppsTabbed");
         }
@@ -120,6 +127,7 @@
     @Override
     public void setLauncher(Launcher launcher) {
         mAllApps.setLauncher(launcher);
+        mLauncher = launcher;
     }
 
     @Override
@@ -164,6 +172,44 @@
     }
 
     @Override
+    public void onLauncherTransitionStart(Animator animation) {
+        if (animation != null) {
+            // Turn on hardware layers for performance
+            setLayerType(LAYER_TYPE_HARDWARE, null);
+            // Re-enable the rendering of the dimmed background in All Apps for performance reasons
+            // if we're fading it in
+            if (mLauncher.getWorkspace().getBackgroundAlpha() == 0f) {
+                mLauncher.getWorkspace().disableBackground();
+                mBackground.setVisibility(VISIBLE);
+            }
+            // just a sanity check that we don't build a layer before a call to onLayout
+            if (!mFirstLayout) {
+                // force building the layer at the beginning of the animation, so you don't get a
+                // blip early in the animation
+                buildLayer();
+            }
+        }
+    }
+
+    @Override
+    public void onLauncherTransitionEnd(Animator animation) {
+        if (animation != null) {
+            setLayerType(LAYER_TYPE_NONE, null);
+            // To improve the performance of the first time All Apps is run, we initially keep
+            // hardware layers in AllAppsPagedView disabled since AllAppsTabbed itself is drawn in a
+            // hardware layer, and creating additional hardware layers slows down the animation. We
+            // create them here, after the animation is over.
+        }
+        // Move the rendering of the dimmed background to workspace after the all apps animation
+        // is done, so that the background is not rendered *above* the mini workspace screens
+        if (mBackground.getVisibility() != GONE) {
+            mLauncher.getWorkspace().enableBackground();
+            mBackground.setVisibility(GONE);
+        }
+        mAllApps.allowHardwareLayerCreation();
+    }
+
+    @Override
     public void setApps(ArrayList<ApplicationInfo> list) {
         mAllApps.setApps(list);
     }
diff --git a/src/com/android/launcher2/AppWidgetResizeFrame.java b/src/com/android/launcher2/AppWidgetResizeFrame.java
new file mode 100644
index 0000000..2b2662f
--- /dev/null
+++ b/src/com/android/launcher2/AppWidgetResizeFrame.java
@@ -0,0 +1,342 @@
+package com.android.launcher2;
+
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.view.Gravity;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.launcher.R;
+
+public class AppWidgetResizeFrame extends FrameLayout {
+
+    private ItemInfo mItemInfo;
+    private LauncherAppWidgetHostView mWidgetView;
+    private CellLayout mCellLayout;
+    private ImageView mLeftHandle;
+    private ImageView mRightHandle;
+    private ImageView mTopHandle;
+    private ImageView mBottomHandle;
+
+    private boolean mLeftBorderActive;
+    private boolean mRightBorderActive;
+    private boolean mTopBorderActive;
+    private boolean mBottomBorderActive;
+
+    private int mBaselineWidth;
+    private int mBaselineHeight;
+    private int mBaselineX;
+    private int mBaselineY;
+    private int mResizeMode;
+
+    private int mRunningHInc;
+    private int mRunningVInc;
+    private int mMinHSpan;
+    private int mMinVSpan;
+    private int mDeltaX;
+    private int mDeltaY;
+
+    private int mBackgroundPadding;
+    private int mTouchTargetWidth;
+
+    private int mExpandability[] = new int[4];
+
+    final int SNAP_DURATION = 150;
+    final int BACKGROUND_PADDING = 24;
+    final float DIMMED_HANDLE_ALPHA = 0f;
+    final float RESIZE_THRESHOLD = 0.66f;
+
+    public static final int LEFT = 0;
+    public static final int TOP = 1;
+    public static final int RIGHT = 2;
+    public static final int BOTTOM = 3;
+
+    public AppWidgetResizeFrame(Context context, ItemInfo itemInfo, 
+            LauncherAppWidgetHostView widgetView, CellLayout cellLayout) {
+
+        super(context);
+        mContext = context;
+        mItemInfo = itemInfo;
+        mCellLayout = cellLayout;
+        mWidgetView = widgetView;
+        mResizeMode = widgetView.getAppWidgetInfo().resizeMode;
+
+        final AppWidgetProviderInfo info = widgetView.getAppWidgetInfo();
+        int[] result = mCellLayout.rectToCell(info.minWidth, info.minHeight, null);
+        mMinHSpan = result[0];
+        mMinVSpan = result[1];
+
+        setBackgroundResource(R.drawable.widget_resize_frame_holo);
+        setPadding(0, 0, 0, 0);
+
+        LayoutParams lp;
+        mLeftHandle = new ImageView(context);
+        mLeftHandle.setImageResource(R.drawable.widget_resize_handle_left);
+        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 
+                Gravity.LEFT | Gravity.CENTER_VERTICAL);
+        addView(mLeftHandle, lp);
+
+        mRightHandle = new ImageView(context);
+        mRightHandle.setImageResource(R.drawable.widget_resize_handle_right);
+        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 
+                Gravity.RIGHT | Gravity.CENTER_VERTICAL);
+        addView(mRightHandle, lp);
+
+        mTopHandle = new ImageView(context);
+        mTopHandle.setImageResource(R.drawable.widget_resize_handle_top);
+        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 
+                Gravity.CENTER_HORIZONTAL | Gravity.TOP);
+        addView(mTopHandle, lp);
+
+        mBottomHandle = new ImageView(context);
+        mBottomHandle.setImageResource(R.drawable.widget_resize_handle_bottom);
+        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 
+                Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
+        addView(mBottomHandle, lp);
+
+        if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
+            mTopHandle.setVisibility(GONE);
+            mBottomHandle.setVisibility(GONE);
+        } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
+            mLeftHandle.setVisibility(GONE);
+            mRightHandle.setVisibility(GONE);
+        }
+
+        final float density = mContext.getResources().getDisplayMetrics().density;
+        mBackgroundPadding = (int) Math.ceil(density * BACKGROUND_PADDING);
+        mTouchTargetWidth = 2 * mBackgroundPadding;
+    }
+
+    public boolean beginResizeIfPointInRegion(int x, int y) {
+        boolean horizontalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0;
+        boolean verticalActive = (mResizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0;
+        mLeftBorderActive = (x < mTouchTargetWidth) && horizontalActive;
+        mRightBorderActive = (x > getWidth() - mTouchTargetWidth) && horizontalActive;
+        mTopBorderActive = (y < mTouchTargetWidth) && verticalActive;
+        mBottomBorderActive = (y > getHeight() - mTouchTargetWidth) && verticalActive;
+
+        boolean anyBordersActive = mLeftBorderActive || mRightBorderActive
+                || mTopBorderActive || mBottomBorderActive;
+
+        mBaselineWidth = getMeasuredWidth();
+        mBaselineHeight = getMeasuredHeight();
+        mBaselineX = getLeft();
+        mBaselineY = getTop();
+        mRunningHInc = 0;
+        mRunningVInc = 0;
+
+        if (anyBordersActive) {
+            mLeftHandle.setAlpha(mLeftBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
+            mRightHandle.setAlpha(mRightBorderActive ? 1.0f :DIMMED_HANDLE_ALPHA);
+            mTopHandle.setAlpha(mTopBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
+            mBottomHandle.setAlpha(mBottomBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA);
+        }
+        mCellLayout.getExpandabilityArrayForView(mWidgetView, mExpandability);
+
+        return anyBordersActive;
+    }
+
+    /**
+     *  Here we bound the deltas such that the frame cannot be stretched beyond the extents
+     *  of the CellLayout, and such that the frame's borders can't cross.
+     */
+    public void updateDeltas(int deltaX, int deltaY) {
+        if (mLeftBorderActive) {
+            mDeltaX = Math.max(-mBaselineX, deltaX); 
+            mDeltaX = Math.min(mBaselineWidth - 2 * mTouchTargetWidth, mDeltaX);
+        } else if (mRightBorderActive) {
+            mDeltaX = Math.min(mCellLayout.getWidth() - (mBaselineX + mBaselineWidth), deltaX);
+            mDeltaX = Math.max(-mBaselineWidth + 2 * mTouchTargetWidth, mDeltaX);
+        }
+
+        if (mTopBorderActive) {
+            mDeltaY = Math.max(-mBaselineY, deltaY);
+            mDeltaY = Math.min(mBaselineHeight - 2 * mTouchTargetWidth, mDeltaY);
+        } else if (mBottomBorderActive) {
+            mDeltaY = Math.min(mCellLayout.getHeight() - (mBaselineY + mBaselineHeight), deltaY);
+            mDeltaY = Math.max(-mBaselineHeight + 2 * mTouchTargetWidth, mDeltaY);
+        }
+    }
+
+    /**
+     *  Based on the deltas, we resize the frame, and, if needed, we resize the widget.
+     */
+    public void visualizeResizeForDelta(int deltaX, int deltaY) {
+        updateDeltas(deltaX, deltaY);
+        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
+        if (mLeftBorderActive) {
+            lp.x = mBaselineX + mDeltaX;
+            lp.width = mBaselineWidth - mDeltaX;
+        } else if (mRightBorderActive) {
+            lp.width = mBaselineWidth + mDeltaX;
+        }
+
+        if (mTopBorderActive) {
+            lp.y = mBaselineY + mDeltaY;
+            lp.height = mBaselineHeight - mDeltaY;
+        } else if (mBottomBorderActive) {
+            lp.height = mBaselineHeight + mDeltaY;
+        }
+
+        resizeWidgetIfNeeded();
+        requestLayout();
+    }
+
+    /**
+     *  Based on the current deltas, we determine if and how to resize the widget.
+     */
+    private void resizeWidgetIfNeeded() {
+        int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap();
+        int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap();
+
+        float hSpanIncF = 1.0f * mDeltaX / xThreshold - mRunningHInc;
+        float vSpanIncF = 1.0f * mDeltaY / yThreshold - mRunningVInc;
+
+        int hSpanInc = 0;
+        int vSpanInc = 0;
+        int cellXInc = 0;
+        int cellYInc = 0;
+
+        if (Math.abs(hSpanIncF) > RESIZE_THRESHOLD) {
+            hSpanInc = Math.round(hSpanIncF);
+        }
+        if (Math.abs(vSpanIncF) > RESIZE_THRESHOLD) {
+            vSpanInc = Math.round(vSpanIncF);
+        }
+
+        if (hSpanInc == 0 && vSpanInc == 0) return;
+
+        // Before we change the widget, we clear the occupied cells associated with it.
+        // The new set of occupied cells is marked below, once the layout params are updated.
+        mCellLayout.markCellsAsUnoccupiedForView(mWidgetView);
+
+        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams();
+
+        // For each border, we bound the resizing based on the minimum width, and the maximum
+        // expandability.
+        if (mLeftBorderActive) {
+            cellXInc = Math.max(-mExpandability[LEFT], hSpanInc);
+            cellXInc = Math.min(lp.cellHSpan - mMinHSpan, cellXInc);
+            hSpanInc *= -1;
+            hSpanInc = Math.min(mExpandability[LEFT], hSpanInc);
+            hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
+            mRunningHInc -= hSpanInc;
+        } else if (mRightBorderActive) {
+            hSpanInc = Math.min(mExpandability[RIGHT], hSpanInc);
+            hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc);
+            mRunningHInc += hSpanInc;
+        }
+
+        if (mTopBorderActive) {
+            cellYInc = Math.max(-mExpandability[TOP], vSpanInc);
+            cellYInc = Math.min(lp.cellVSpan - mMinVSpan, cellYInc);
+            vSpanInc *= -1;
+            vSpanInc = Math.min(mExpandability[TOP], vSpanInc);
+            vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
+            mRunningVInc -= vSpanInc;
+        } else if (mBottomBorderActive) {
+            vSpanInc = Math.min(mExpandability[BOTTOM], vSpanInc);
+            vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc);
+            mRunningVInc += vSpanInc;
+        }
+
+        // Update the widget's dimensions and position according to the deltas computed above
+        if (mLeftBorderActive || mRightBorderActive) {
+            lp.cellHSpan += hSpanInc;
+            lp.cellX += cellXInc;
+        }
+
+        if (mTopBorderActive || mBottomBorderActive) {
+            lp.cellVSpan += vSpanInc;
+            lp.cellY += cellYInc;
+        }
+
+        // Update the expandability array, as we have changed the widget's size.
+        mCellLayout.getExpandabilityArrayForView(mWidgetView, mExpandability);
+
+        // Update the cells occupied by this widget
+        mCellLayout.markCellsAsOccupiedForView(mWidgetView);
+    }
+
+    /**
+     * This is the final step of the resize. Here we save the new widget size and position
+     * to LauncherModel and animate the resize frame.
+     */
+    public void commitResizeForDelta(int deltaX, int deltaY) {
+        visualizeResizeForDelta(deltaX, deltaY);
+
+        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams();
+        LauncherModel.resizeItemInDatabase(getContext(), mItemInfo, lp.cellX, lp.cellY,
+                lp.cellHSpan, lp.cellVSpan);
+        mWidgetView.requestLayout();
+
+        // Once our widget resizes (hence the post), we want to snap the resize frame to it
+        post(new Runnable() {
+            public void run() {
+                snapToWidget(true);
+            }
+        });
+    }
+
+    public void snapToWidget(boolean animate) {
+        final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
+
+        int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding;
+        int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding;
+        int newX = mWidgetView.getLeft() - mBackgroundPadding;
+        int newY = mWidgetView.getTop() - mBackgroundPadding;
+
+        // We need to make sure the frame stays within the bounds of the CellLayout
+        if (newY < 0) {
+            newHeight -= -newY;
+            newY = 0;
+        }
+        if (newY + newHeight > mCellLayout.getHeight()) {
+            newHeight -= newY + newHeight - mCellLayout.getHeight();
+        }
+
+        if (!animate) {
+            lp.width = newWidth;
+            lp.height = newHeight;
+            lp.x = newX;
+            lp.y = newY;
+            mLeftHandle.setAlpha(1.0f);
+            mRightHandle.setAlpha(1.0f);
+            mTopHandle.setAlpha(1.0f);
+            mBottomHandle.setAlpha(1.0f);
+            requestLayout();
+        } else {
+            PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", lp.width, newWidth);
+            PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", lp.height,
+                    newHeight);
+            PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", lp.x, newX);
+            PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", lp.y, newY);
+            ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y);
+            ObjectAnimator leftOa = ObjectAnimator.ofFloat(mLeftHandle, "alpha", 1.0f);
+            ObjectAnimator rightOa = ObjectAnimator.ofFloat(mRightHandle, "alpha", 1.0f);
+            ObjectAnimator topOa = ObjectAnimator.ofFloat(mTopHandle, "alpha", 1.0f);
+            ObjectAnimator bottomOa = ObjectAnimator.ofFloat(mBottomHandle, "alpha", 1.0f);
+            oa.addUpdateListener(new AnimatorUpdateListener() {
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    requestLayout();
+                }
+            });
+            AnimatorSet set = new AnimatorSet();
+            if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) {
+                set.playTogether(oa, topOa, bottomOa);
+            } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
+                set.playTogether(oa, leftOa, rightOa);
+            } else {
+                set.playTogether(oa, leftOa, rightOa, topOa, bottomOa);
+            }
+
+            set.setDuration(SNAP_DURATION);
+            set.start();
+        }
+    }
+}
diff --git a/src/com/android/launcher2/ApplicationInfo.java b/src/com/android/launcher2/ApplicationInfo.java
index 3adea37..1d948b7 100644
--- a/src/com/android/launcher2/ApplicationInfo.java
+++ b/src/com/android/launcher2/ApplicationInfo.java
@@ -59,9 +59,9 @@
 
     ComponentName componentName;
 
-    static final int APP_FLAG = 1;
-    static final int GAME_FLAG = 2;
-    static final int DOWNLOADED_FLAG = 4;
+    static final int DOWNLOADED_FLAG = 1;
+    static final int UPDATED_SYSTEM_APP_FLAG = 2;
+
     int flags = 0;
 
     ApplicationInfo() {
@@ -83,17 +83,12 @@
             int appFlags = pm.getApplicationInfo(packageName, 0).flags;
             if ((appFlags & android.content.pm.ApplicationInfo.FLAG_SYSTEM) == 0) {
                 flags |= DOWNLOADED_FLAG;
-            }
-            if ((appFlags & android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
-                flags |= DOWNLOADED_FLAG;
+
+                if ((appFlags & android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
+                    flags |= UPDATED_SYSTEM_APP_FLAG;
+                }
             }
             firstInstallTime = pm.getPackageInfo(packageName, 0).firstInstallTime;
-            // TODO: Figure out how to determine what is a game
-
-            // If it's not a game, it's an app
-            if ((flags & GAME_FLAG) == 0) {
-                flags |= APP_FLAG;
-            }
         } catch (NameNotFoundException e) {
             Log.d(TAG, "PackageManager.getApplicationInfo failed for " + packageName);
         }
diff --git a/src/com/android/launcher2/BubbleTextView.java b/src/com/android/launcher2/BubbleTextView.java
index ad01fac..1464854 100644
--- a/src/com/android/launcher2/BubbleTextView.java
+++ b/src/com/android/launcher2/BubbleTextView.java
@@ -66,6 +66,8 @@
     private boolean mBackgroundSizeChanged;
     private Drawable mBackground;
 
+    private boolean mStayPressed;
+
     private VisibilityChangedListener mOnVisibilityChangedListener;
 
     public BubbleTextView(Context context) {
@@ -130,21 +132,30 @@
             // In this case, we have already created the pressed outline on ACTION_DOWN,
             // so we just need to do an invalidate to trigger draw
             if (!mDidInvalidateForPressedState) {
-                invalidate();
+                setCellLayoutPressedOrFocusedIcon();
             }
         } else {
             // Otherwise, either clear the pressed/focused background, or create a background
             // for the focused state
             final boolean backgroundEmptyBefore = mPressedOrFocusedBackground == null;
-            mPressedOrFocusedBackground = null;
+            if (!mStayPressed) {
+                mPressedOrFocusedBackground = null;
+            }
             if (isFocused()) {
-                mPressedOrFocusedBackground = createGlowingOutline(
-                        mTempCanvas, mFocusedGlowColor, mFocusedOutlineColor);
-                invalidate();
+                if (mLayout == null) {
+                    // In some cases, we get focus before we have been layed out. Set the
+                    // background to null so that it will get created when the view is drawn.
+                    mPressedOrFocusedBackground = null;
+                } else {
+                    mPressedOrFocusedBackground = createGlowingOutline(
+                            mTempCanvas, mFocusedGlowColor, mFocusedOutlineColor);
+                }
+                mStayPressed = false;
+                setCellLayoutPressedOrFocusedIcon();
             }
             final boolean backgroundEmptyNow = mPressedOrFocusedBackground == null;
             if (!backgroundEmptyBefore && backgroundEmptyNow) {
-                invalidate();
+                setCellLayoutPressedOrFocusedIcon();
             }
         }
 
@@ -156,9 +167,8 @@
     }
 
     /**
-     * Draw the View v into the given Canvas.
+     * Draw this BubbleTextView into the given Canvas.
      *
-     * @param v the view to draw
      * @param destCanvas the canvas to draw on
      * @param padding the horizontal and vertical padding to use when drawing
      */
@@ -244,22 +254,32 @@
         super.onVisibilityChanged(changedView, visibility);
     }
 
+    void setStayPressed(boolean stayPressed) {
+        mStayPressed = stayPressed;
+        if (!stayPressed) {
+            mPressedOrFocusedBackground = null;
+        }
+        setCellLayoutPressedOrFocusedIcon();
+    }
+
+    void setCellLayoutPressedOrFocusedIcon() {
+        CellLayoutChildren parent = (CellLayoutChildren) getParent();
+        if (parent != null) {
+            CellLayout layout = (CellLayout) parent.getParent();
+            layout.setPressedOrFocusedIcon((mPressedOrFocusedBackground != null) ? this : null);
+        }
+    }
+
+    Bitmap getPressedOrFocusedBackground() {
+        return mPressedOrFocusedBackground;
+    }
+
+    int getPressedOrFocusedBackgroundPadding() {
+        return HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS / 2;
+    }
+
     @Override
     public void draw(Canvas canvas) {
-        if (mPressedOrFocusedBackground != null && (isPressed() || isFocused())) {
-            // The blue glow can extend outside of our clip region, so we first temporarily expand
-            // the canvas's clip region
-            canvas.save(Canvas.CLIP_SAVE_FLAG);
-            int padding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS / 2;
-            canvas.clipRect(-padding + mScrollX, -padding + mScrollY,
-                    getWidth() + padding + mScrollX, getHeight() + padding + mScrollY,
-                    Region.Op.REPLACE);
-            // draw blue glow
-            canvas.drawBitmap(mPressedOrFocusedBackground,
-                    mScrollX - padding, mScrollY - padding, mTempPaint);
-            canvas.restore();
-        }
-
         final Drawable background = mBackground;
         if (background != null) {
             final int scrollX = mScrollX;
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 6691e64..1111c53 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -113,6 +113,8 @@
     private int mDragOutlineCurrent = 0;
     private final Paint mDragOutlinePaint = new Paint();
 
+    private BubbleTextView mPressedOrFocusedIcon;
+
     private Drawable mCrosshairsDrawable = null;
     private InterruptibleInOutAnimator mCrosshairsAnimator = null;
     private float mCrosshairsVisibility = 0.0f;
@@ -267,6 +269,27 @@
         addView(mChildren);
     }
 
+    private void invalidateBubbleTextView(BubbleTextView icon) {
+        final int padding = icon.getPressedOrFocusedBackgroundPadding();
+        invalidate(icon.getLeft() - padding,
+                icon.getTop() - padding,
+                icon.getRight() + padding,
+                icon.getBottom() + padding);
+    }
+
+    void setPressedOrFocusedIcon(BubbleTextView icon) {
+        // We draw the pressed or focused BubbleTextView's background in CellLayout because it
+        // requires an expanded clip rect (due to the glow's blur radius)
+        BubbleTextView oldIcon = mPressedOrFocusedIcon;
+        mPressedOrFocusedIcon = icon;
+        if (oldIcon != null) {
+            invalidateBubbleTextView(oldIcon);
+        }
+        if (mPressedOrFocusedIcon != null) {
+            invalidateBubbleTextView(mPressedOrFocusedIcon);
+        }
+    }
+
     public CellLayoutChildren getChildrenLayout() {
         if (getChildCount() > 0) {
             return (CellLayoutChildren) getChildAt(0);
@@ -457,6 +480,19 @@
                 canvas.drawBitmap(b, p.x, p.y, paint);
             }
         }
+
+        // We draw the pressed or focused BubbleTextView's background in CellLayout because it
+        // requires an expanded clip rect (due to the glow's blur radius)
+        if (mPressedOrFocusedIcon != null) {
+            final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding();
+            final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground();
+            if (b != null) {
+                canvas.drawBitmap(b,
+                        mPressedOrFocusedIcon.getLeft() - padding,
+                        mPressedOrFocusedIcon.getTop() - padding,
+                        null);
+            }
+        }
     }
 
     @Override
@@ -571,6 +607,10 @@
         mChildren.draw(canvas);
     }
 
+    void buildChildrenLayer() {
+        mChildren.buildLayer();
+    }
+
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
@@ -587,11 +627,12 @@
         boolean found = false;
         for (int i = count - 1; i >= 0; i--) {
             final View child = mChildren.getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
 
-            if ((child.getVisibility()) == VISIBLE || child.getAnimation() != null) {
+            if ((child.getVisibility() == VISIBLE || child.getAnimation() != null) &&
+                    lp.isLockedToGrid) {
                 child.getHitRect(frame);
                 if (frame.contains(x, y)) {
-                    final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                     cellInfo.cell = child;
                     cellInfo.cellX = lp.cellX;
                     cellInfo.cellY = lp.cellY;
@@ -703,6 +744,14 @@
         return mCellHeight;
     }
 
+    int getWidthGap() {
+        return mWidthGap;
+    }
+
+    int getHeightGap() {
+        return mHeightGap;
+    }
+
     int getLeftPadding() {
         return mLeftPadding;
     }
@@ -1332,19 +1381,69 @@
         }
     }
 
+    /**
+     * Given a view, determines how much that view can be expanded in all directions, in terms of
+     * whether or not there are other items occupying adjacent cells. Used by the
+     * AppWidgetResizeFrame to determine how the widget can be resized.
+     */
+    public void getExpandabilityArrayForView(View view, int[] expandability) {
+        final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+        boolean flag;
+
+        expandability[AppWidgetResizeFrame.LEFT] = 0;
+        for (int x = lp.cellX - 1; x >= 0; x--) {
+            flag = false;
+            for (int y = lp.cellY; y < lp.cellY + lp.cellVSpan; y++) {
+                if (mOccupied[x][y]) flag = true;
+            }
+            if (flag) break;
+            expandability[AppWidgetResizeFrame.LEFT]++;
+        }
+
+        expandability[AppWidgetResizeFrame.TOP] = 0;
+        for (int y = lp.cellY - 1; y >= 0; y--) {
+            flag = false;
+            for (int x = lp.cellX; x < lp.cellX + lp.cellHSpan; x++) {
+                if (mOccupied[x][y]) flag = true;
+            }
+            if (flag) break;
+            expandability[AppWidgetResizeFrame.TOP]++;
+        }
+
+        expandability[AppWidgetResizeFrame.RIGHT] = 0;
+        for (int x = lp.cellX + lp.cellHSpan; x < mCountX; x++) {
+            flag = false;
+            for (int y = lp.cellY; y < lp.cellY + lp.cellVSpan; y++) {
+                if (mOccupied[x][y]) flag = true;
+            }
+            if (flag) break;
+            expandability[AppWidgetResizeFrame.RIGHT]++;
+        }
+
+        expandability[AppWidgetResizeFrame.BOTTOM] = 0;
+        for (int y = lp.cellY + lp.cellVSpan; y < mCountY; y++) {
+            flag = false;
+            for (int x = lp.cellX; x < lp.cellX + lp.cellHSpan; x++) {
+                if (mOccupied[x][y]) flag = true;
+            }
+            if (flag) break;
+            expandability[AppWidgetResizeFrame.BOTTOM]++;
+        }
+    }
+
     public void onMove(View view, int newCellX, int newCellY) {
         LayoutParams lp = (LayoutParams) view.getLayoutParams();
         markCellsAsUnoccupiedForView(view);
         markCellsForView(newCellX, newCellY, lp.cellHSpan, lp.cellVSpan, true);
     }
 
-    private void markCellsAsOccupiedForView(View view) {
+    public void markCellsAsOccupiedForView(View view) {
         if (view == null || view.getParent() != mChildren) return;
         LayoutParams lp = (LayoutParams) view.getLayoutParams();
         markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, true);
     }
 
-    private void markCellsAsUnoccupiedForView(View view) {
+    public void markCellsAsUnoccupiedForView(View view) {
         if (view == null || view.getParent() != mChildren) return;
         LayoutParams lp = (LayoutParams) view.getLayoutParams();
         markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, false);
@@ -1410,6 +1509,12 @@
         public int cellVSpan;
 
         /**
+         * Indicates whether the item will set its x, y, width and height parameters freely,
+         * or whether these will be computed based on cellX, cellY, cellHSpan and cellVSpan.
+         */
+        public boolean isLockedToGrid = true;
+
+        /**
          * Is this item currently being dragged
          */
         public boolean isDragging;
@@ -1467,19 +1572,51 @@
 
         public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap,
                 int hStartPadding, int vStartPadding) {
+            if (isLockedToGrid) {
+                final int myCellHSpan = cellHSpan;
+                final int myCellVSpan = cellVSpan;
+                final int myCellX = cellX;
+                final int myCellY = cellY;
 
-            final int myCellHSpan = cellHSpan;
-            final int myCellVSpan = cellVSpan;
-            final int myCellX = cellX;
-            final int myCellY = cellY;
+                width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
+                        leftMargin - rightMargin;
+                height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
+                        topMargin - bottomMargin;
+                x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
+                y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
+            }
+        }
 
-            width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
-                    leftMargin - rightMargin;
-            height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
-                    topMargin - bottomMargin;
+        public void setWidth(int width) {
+            this.width = width;
+        }
 
-            x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
-            y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
+        public int getWidth() {
+            return width;
+        }
+
+        public void setHeight(int height) {
+            this.height = height;
+        }
+
+        public int getHeight() {
+            return height;
+        }
+
+        public void setX(int x) {
+            this.x = x;
+        }
+
+        public int getX() {
+            return x;
+        }
+
+        public void setY(int y) {
+            this.y = y;
+        }
+
+        public int getY() {
+            return y;
         }
 
         public String toString() {
diff --git a/src/com/android/launcher2/CellLayoutChildren.java b/src/com/android/launcher2/CellLayoutChildren.java
index 0d0a339..04996f3 100644
--- a/src/com/android/launcher2/CellLayoutChildren.java
+++ b/src/com/android/launcher2/CellLayoutChildren.java
@@ -16,12 +16,14 @@
 
 package com.android.launcher2;
 
+import java.util.ArrayList;
+
 import android.app.WallpaperManager;
 import android.content.Context;
 import android.graphics.Rect;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.View.MeasureSpec;
 
 public class CellLayoutChildren extends ViewGroup {
     static final String TAG = "CellLayoutChildren";
@@ -32,22 +34,25 @@
 
     private final WallpaperManager mWallpaperManager;
 
-    private int mCellWidth;
-    private int mCellHeight;
-
     private int mLeftPadding;
     private int mTopPadding;
 
+    private int mCellWidth;
+    private int mCellHeight;
+
     private int mWidthGap;
     private int mHeightGap;
 
+    // Variables relating to resizing widgets
+    private final ArrayList<AppWidgetResizeFrame> mResizeFrames =
+            new ArrayList<AppWidgetResizeFrame>();
+    private AppWidgetResizeFrame mCurrentResizeFrame;
+    private int mXDown, mYDown;
+
     public CellLayoutChildren(Context context) {
         super(context);
         mWallpaperManager = WallpaperManager.getInstance(context);
         setLayerType(LAYER_TYPE_HARDWARE, null);
-
-        // Disable multitouch for the workspace
-        setMotionEventSplittingEnabled(false);
     }
 
     public void setCellDimensions(int cellWidth, int cellHeight,
@@ -171,4 +176,95 @@
     protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
         super.setChildrenDrawnWithCacheEnabled(enabled);
     }
-}
\ No newline at end of file
+
+    public void clearAllResizeFrames() {
+        for (AppWidgetResizeFrame frame: mResizeFrames) {
+            removeView(frame);
+        }
+        mResizeFrames.clear();
+    }
+
+    public boolean hasResizeFrames() {
+        return mResizeFrames.size() > 0;
+    }
+
+    public boolean isWidgetBeingResized() {
+        return mCurrentResizeFrame != null;
+    }
+
+    private boolean handleTouchDown(MotionEvent ev) {
+        Rect hitRect = new Rect();
+
+        int x = (int) ev.getX();
+        int y = (int) ev.getY();
+
+        for (AppWidgetResizeFrame child: mResizeFrames) {
+            child.getHitRect(hitRect);
+            if (hitRect.contains(x, y)) {
+                if (child.beginResizeIfPointInRegion(x - child.getLeft(), y - child.getTop())) {
+                    mCurrentResizeFrame = child;
+                    mXDown = x;
+                    mYDown = y;
+                    requestDisallowInterceptTouchEvent(true);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            if (handleTouchDown(ev)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        boolean handled = false;
+        int action = ev.getAction();
+
+        int x = (int) ev.getX();
+        int y = (int) ev.getY();
+
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+                if (handleTouchDown(ev)) {
+                    return true;
+                }
+            }
+        }
+
+        if (mCurrentResizeFrame != null) {
+            handled = true;
+            switch (action) {
+                case MotionEvent.ACTION_MOVE:
+                    mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
+                    break;
+                case MotionEvent.ACTION_CANCEL:
+                case MotionEvent.ACTION_UP:
+                    mCurrentResizeFrame.commitResizeForDelta(x - mXDown, y - mYDown);
+                    mCurrentResizeFrame = null;
+            }
+        }
+        return handled;
+    }
+
+    public void addResizeFrame(ItemInfo itemInfo, LauncherAppWidgetHostView widget,
+            CellLayout cellLayout) {
+        AppWidgetResizeFrame resizeFrame = new AppWidgetResizeFrame(getContext(),
+                itemInfo, widget, cellLayout);
+
+        CellLayout.LayoutParams lp = new CellLayout.LayoutParams(-1, -1, -1, -1);
+        lp.isLockedToGrid = false;
+
+        addView(resizeFrame, lp);
+        mResizeFrames.add(resizeFrame);
+
+        resizeFrame.snapToWidget(false);
+    }
+}
diff --git a/src/com/android/launcher2/CustomizePagedView.java b/src/com/android/launcher2/CustomizePagedView.java
index d08bf54..5c61b0b 100644
--- a/src/com/android/launcher2/CustomizePagedView.java
+++ b/src/com/android/launcher2/CustomizePagedView.java
@@ -38,8 +38,10 @@
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Bitmap.Config;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -53,7 +55,7 @@
 import android.view.MenuItem;
 import android.view.View;
 import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
 import android.widget.Checkable;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -89,6 +91,10 @@
     // The mapping between the pages and the widgets that will be laid out on them
     private ArrayList<ArrayList<AppWidgetProviderInfo>> mWidgetPages;
 
+    // This is used if we want to set a min width on pages so that things inside them left align to
+    // a fixed size
+    private int mMinPageWidth;
+
     // The max dimensions for the ImageView we use for displaying a widget
     private int mMaxWidgetWidth;
 
@@ -120,9 +126,19 @@
 
     private final float mTmpFloatPos[] = new float[2];
     private final float ANIMATION_SCALE = 0.5f;
-    private final int ANIMATION_DURATION = 400;
+
+    // The duration of the translation animation that occurs during you drag and drop
+    private final int TRANSLATE_ANIM_DURATION = 400;
+
+    // The duration of the scale & alpha animation that occurs during drag and drop
+    private final int DROP_ANIM_DURATION = 200;
+
     private TimeInterpolator mQuintEaseOutInterpolator = new DecelerateInterpolator(2.5f);
-    private ScaleAlphaInterpolator mScaleAlphaInterpolator = new ScaleAlphaInterpolator();
+
+    // The Bitmap used to generate the drag view
+    private Bitmap mDragBitmap;
+
+    private int[] mDragViewOrigin = new int[2];
 
     public CustomizePagedView(Context context) {
         this(context, null, 0);
@@ -154,6 +170,7 @@
         final Resources r = context.getResources();
         setDragSlopeThreshold(
                 r.getInteger(R.integer.config_customizationDrawerDragSlopeThreshold) / 100.0f);
+        mMinPageWidth = r.getDimensionPixelSize(R.dimen.customization_drawer_content_min_width);
 
         setVisibility(View.GONE);
         setSoundEffectsEnabled(false);
@@ -324,38 +341,60 @@
         return mCustomizationType;
     }
 
-    @Override
-    public void onDropCompleted(View target, boolean success) {
-        resetCheckedGrandchildren();
+    /**
+     * Similar to resetCheckedGrandchildren, but allows us to specify that it's not animated.
+     */
+    private void resetCheckedItem(boolean animated) {
+        final Checkable checkable = getSingleCheckedGrandchild();
+        if (checkable != null) {
+            if (checkable instanceof PagedViewWidget) {
+                ((PagedViewWidget) checkable).setChecked(false, animated);
+            } else {
+                ((PagedViewIcon) checkable).setChecked(false, animated);
+            }
+        }
+    }
+
+    public void onDropCompleted(View target, Object dragInfo, boolean success) {
+        final DragLayer dragLayer = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
+
+        // Create a view, identical to the drag view, that is only used for animating the
+        // item onto the home screen (or back to its original position, if the drop failed).
+        final int[] pos = mDragController.getDragView().getPosition(null);
+        final View animView = dragLayer.createDragView(mDragBitmap, pos[0], pos[1]);
+        animView.setVisibility(View.VISIBLE);
+
+        if (success) {
+            resetCheckedItem(true);
+            animateDropOntoScreen(animView, (ItemInfo) dragInfo, DROP_ANIM_DURATION, 0);
+        } else {
+            // Animate the icon/widget back to its original position
+            animateIntoPosition(animView, mDragViewOrigin[0], mDragViewOrigin[1], new Runnable() {
+                public void run() {
+                   resetCheckedItem(false);
+                   dragLayer.removeView(animView);
+                }
+            });
+        }
         mLauncher.getWorkspace().onDragStopped(success);
         mLauncher.unlockScreenOrientation();
+        mDragBitmap = null;
     }
 
     @Override
     public void onDragViewVisible() {
     }
 
-    class ScaleAlphaInterpolator implements Interpolator {
-        public float getInterpolation(float input) {
-            float pivot = 0.5f;
-            if (input < pivot) {
-                return 0;
-            } else {
-                return (input - pivot)/(1 - pivot);
-            }
-        }
-    }
-
+    /**
+     * Animates the given item onto the center of a home screen, and then scales the item to
+     * look as though it's disappearing onto that screen.
+     */
     private void animateItemOntoScreen(View dragView,
             final CellLayout layout, final ItemInfo info) {
         mTmpFloatPos[0] = layout.getWidth() / 2;
         mTmpFloatPos[1] = layout.getHeight() / 2;
         mLauncher.getWorkspace().mapPointFromChildToSelf(layout, mTmpFloatPos);
 
-        final DragLayer dragLayer = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
-        final View dragCopy = dragLayer.createDragView(dragView);
-        dragCopy.setAlpha(1.0f);
-
         int dragViewWidth = dragView.getMeasuredWidth();
         int dragViewHeight = dragView.getMeasuredHeight();
         float heightOffset = 0;
@@ -374,37 +413,70 @@
                 widthOffset = ANIMATION_SCALE * (dragViewWidth - f * width) / 2;
             }
         }
+        final float toX = mTmpFloatPos[0] - dragView.getMeasuredWidth() / 2 + widthOffset;
+        final float toY = mTmpFloatPos[1] - dragView.getMeasuredHeight() / 2 + heightOffset;
 
-        float toX = mTmpFloatPos[0] - dragView.getMeasuredWidth() / 2 + widthOffset;
-        float toY = mTmpFloatPos[1] - dragView.getMeasuredHeight() / 2 + heightOffset;
+        final DragLayer dragLayer = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
+        final View dragCopy = dragLayer.createDragView(dragView);
+        dragCopy.setAlpha(1.0f);
 
-        ObjectAnimator posAnim = ObjectAnimator.ofPropertyValuesHolder(dragCopy,
-                PropertyValuesHolder.ofFloat("x", toX),
-                PropertyValuesHolder.ofFloat("y", toY));
-        posAnim.setInterpolator(mQuintEaseOutInterpolator);
-        posAnim.setDuration(ANIMATION_DURATION);
+        // Translate the item to the center of the appropriate home screen
+        animateIntoPosition(dragCopy, toX, toY, null);
 
-        posAnim.addListener(new AnimatorListenerAdapter() {
-            public void onAnimationEnd(Animator animation) {
-                dragLayer.removeView(dragCopy);
-                mLauncher.addExternalItemToScreen(info, layout);
-                post(new Runnable() {
-                    public void run() {
-                        layout.animateDrop();
-                    }
-                });
-            }
-        });
+        // The drop-onto-screen animation begins a bit later, but ends at the same time.
+        final int startDelay = TRANSLATE_ANIM_DURATION - DROP_ANIM_DURATION;
+        
+        // Scale down the icon and fade out the alpha
+        animateDropOntoScreen(dragCopy, info, DROP_ANIM_DURATION, startDelay);
+    }
 
-        ObjectAnimator scaleAlphaAnim = ObjectAnimator.ofPropertyValuesHolder(dragCopy,
+    /**
+     * Animation which scales the view down and animates its alpha, making it appear to disappear
+     * onto a home screen.
+     */
+    private void animateDropOntoScreen(
+            final View view, final ItemInfo info, int duration, int delay) {
+        final DragLayer dragLayer = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
+        final CellLayout layout = mLauncher.getWorkspace().getCurrentDropLayout();
+
+        ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(view,
                 PropertyValuesHolder.ofFloat("alpha", 1.0f, 0.0f),
                 PropertyValuesHolder.ofFloat("scaleX", ANIMATION_SCALE),
                 PropertyValuesHolder.ofFloat("scaleY", ANIMATION_SCALE));
-        scaleAlphaAnim.setInterpolator(mScaleAlphaInterpolator);
-        scaleAlphaAnim.setDuration(ANIMATION_DURATION);
+        anim.setInterpolator(new LinearInterpolator());
+        if (delay > 0) {
+            anim.setStartDelay(delay);
+        }
+        anim.setDuration(duration);
+        anim.addListener(new AnimatorListenerAdapter() {
+            public void onAnimationEnd(Animator animation) {
+                dragLayer.removeView(view);
+                mLauncher.addExternalItemToScreen(info, layout);
+                info.dropPos = null;
+            }
+        });
+        anim.start();
+    }
 
-        posAnim.start();
-        scaleAlphaAnim.start();
+    /**
+     * Animates the x,y position of the view, and optionally execute a Runnable on animation end.
+     */
+    private void animateIntoPosition(
+            View view, float toX, float toY, final Runnable endRunnable) {
+        ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(view,
+                PropertyValuesHolder.ofFloat("x", toX),
+                PropertyValuesHolder.ofFloat("y", toY));
+        anim.setInterpolator(mQuintEaseOutInterpolator);
+        anim.setDuration(TRANSLATE_ANIM_DURATION);
+        if (endRunnable != null) {
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    endRunnable.run();
+                }
+            });
+        }
+        anim.start();
     }
 
     @Override
@@ -479,12 +551,12 @@
         }
     }
 
-    Bitmap drawableToBitmap(Drawable d, View v, boolean clipHeight) {
-        int height = clipHeight ? v.getPaddingTop() + d.getIntrinsicHeight() : v.getHeight();
-        Bitmap b = Bitmap.createBitmap(v.getWidth(), height, Bitmap.Config.ARGB_8888);
-        Canvas c = new Canvas(b);
-        c.translate((v.getWidth() - d.getIntrinsicWidth()) / 2, v.getPaddingTop());
-        d.draw(c);
+    private Bitmap drawableToBitmap(Drawable d, float scaleX, float scaleY) {
+        final Rect bounds = d.getBounds();
+        final int w = bounds.width();
+        final int h = bounds.height();
+        Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+        renderDrawableToBitmap(d, b, 0, 0, w, h, scaleX, scaleY);
         return b;
     }
 
@@ -501,6 +573,7 @@
         if (isChoiceMode(CHOICE_MODE_SINGLE)) {
             endChoiceMode();
         }
+        final Workspace workspace = mLauncher.getWorkspace();
         boolean result = false;
         mLauncher.lockScreenOrientation();
         switch (mCustomizationType) {
@@ -509,50 +582,50 @@
                 // Get the widget preview as the drag representation
                 final LinearLayout l = (LinearLayout) v;
                 final ImageView i = (ImageView) l.findViewById(R.id.widget_preview);
-                Bitmap b = drawableToBitmap(i.getDrawable(), i, true);
+
+                // Calculate how much to scale the drag preview
+                RectF tmpScaleRect = new RectF(0,0,1,1);
+                i.getImageMatrix().mapRect(tmpScaleRect);
+
+                mDragBitmap = drawableToBitmap(i.getDrawable(), tmpScaleRect.right,
+                        tmpScaleRect.bottom);
+                i.getLocationOnScreen(mDragViewOrigin);
                 PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) v.getTag();
 
-                int[] spanXY = CellLayout.rectToCell(
-                        getResources(), createWidgetInfo.minWidth, createWidgetInfo.minHeight, null);
+                int[] spanXY = CellLayout.rectToCell(getResources(),
+                        createWidgetInfo.minWidth, createWidgetInfo.minHeight, null);
                 createWidgetInfo.spanX = spanXY[0];
                 createWidgetInfo.spanY = spanXY[1];
-                mLauncher.getWorkspace().onDragStartedWithItemSpans(spanXY[0], spanXY[1], b);
-                mDragController.startDrag(
-                        i, b, this, createWidgetInfo, DragController.DRAG_ACTION_COPY, null);
-                b.recycle();
+                workspace.onDragStartedWithItemSpans(spanXY[0], spanXY[1], mDragBitmap);
+                mDragController.startDrag(i, mDragBitmap, this, createWidgetInfo,
+                        DragController.DRAG_ACTION_COPY, null);
                 result = true;
             }
             break;
         }
-        case ShortcutCustomization: {
-            if (v instanceof PagedViewIcon) {
-                // get icon (top compound drawable, index is 1)
-                final TextView tv = (TextView) v;
-                final Drawable icon = tv.getCompoundDrawables()[1];
-                Bitmap b = drawableToBitmap(icon, tv, false);
-                PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
-
-                mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1, b);
-                mDragController.startDrag(v, b, this, createItemInfo, DragController.DRAG_ACTION_COPY,
-                        null);
-                b.recycle();
-                result = true;
-            }
-            break;
-        }
+        case ShortcutCustomization:
         case ApplicationCustomization: {
             if (v instanceof PagedViewIcon) {
-                // Pick up the application for dropping
                 // get icon (top compound drawable, index is 1)
                 final TextView tv = (TextView) v;
                 final Drawable icon = tv.getCompoundDrawables()[1];
-                Bitmap b = drawableToBitmap(icon, tv, false);
-                ApplicationInfo app = (ApplicationInfo) v.getTag();
-                app = new ApplicationInfo(app);
+                mDragBitmap = drawableToBitmap(icon, 1.0f, 1.0f);
 
-                mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1, b);
-                mDragController.startDrag(v, b, this, app, DragController.DRAG_ACTION_COPY, null);
-                b.recycle();
+                Object dragInfo = v.getTag();
+                if (mCustomizationType == CustomizationType.ApplicationCustomization) {
+                    // TODO: Not sure why we have to copy this
+                    dragInfo = new ApplicationInfo((ApplicationInfo) dragInfo);
+                }
+                workspace.onDragStartedWithItemSpans(1, 1, mDragBitmap);
+
+                // Calculate where to place the drag view in order to align the icon pixels with
+                // the original view.
+                v.getLocationOnScreen(mDragViewOrigin);
+                mDragViewOrigin[0] += (v.getWidth() - icon.getIntrinsicWidth()) / 2;
+                mDragViewOrigin[1] += v.getPaddingTop();
+
+                mDragController.startDrag(mDragBitmap, mDragViewOrigin[0], mDragViewOrigin[1],
+                        this, dragInfo, DragController.DRAG_ACTION_COPY);
                 result = true;
             }
             break;
@@ -619,11 +692,15 @@
     /**
      * Helper function to draw a drawable to the specified canvas with the specified bounds.
      */
-    private void renderDrawableToBitmap(Drawable d, Bitmap bitmap, int x, int y, int w, int h) {
+    private void renderDrawableToBitmap(Drawable d, Bitmap bitmap, int x, int y, int w, int h,
+            float scaleX, float scaleY) {
         if (bitmap != null) mCanvas.setBitmap(bitmap);
         mCanvas.save();
-        d.setBounds(x, y, x+w, y+h);
+        mCanvas.scale(scaleX, scaleY);
+        final Rect oldBounds = d.copyBounds();
+        d.setBounds(x, y, x + w, y + h);
         d.draw(mCanvas);
+        d.setBounds(oldBounds); // Restore the bounds
         mCanvas.restore();
     }
 
@@ -706,7 +783,7 @@
             background = resources.getDrawable(R.drawable.default_widget_preview);
         }
 
-        renderDrawableToBitmap(background, bitmap, 0, 0, width, height);
+        renderDrawableToBitmap(background, bitmap, 0, 0, width, height, 1.0f, 1.0f);
 
         // If we don't have a custom icon, we use the app icon on the default background
         if (!foundCustomDrawable) {
@@ -718,7 +795,7 @@
 
                 final int iconSize = minDim / 2;
                 final int offset = iconSize / 4;
-                renderDrawableToBitmap(icon, null, offset, offset, iconSize, iconSize);
+                renderDrawableToBitmap(icon, null, offset, offset, iconSize, iconSize, 1.0f, 1.0f);
             } catch (Resources.NotFoundException e) {
                 // if we can't find the icon, then just don't draw it
             }
@@ -758,7 +835,7 @@
             int height = (int) (Math.max(minDim, Math.min(maxDim, info.minHeight)) * sScaleFactor);
             final Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
             final Drawable background = resources.getDrawable(R.drawable.default_widget_preview);
-            renderDrawableToBitmap(background, bitmap, 0, 0, width, height);
+            renderDrawableToBitmap(background, bitmap, 0, 0, width, height, 1.0f, 1.0f);
 
             // Draw the icon flush left
             try {
@@ -772,7 +849,7 @@
 
                 final int iconSize = minDim / 2;
                 final int offset = iconSize / 4;
-                renderDrawableToBitmap(icon, null, offset, offset, iconSize, iconSize);
+                renderDrawableToBitmap(icon, null, offset, offset, iconSize, iconSize, 1.0f, 1.0f);
             } catch (Resources.NotFoundException e) {
                 // if we can't find the icon, then just don't draw it
             }
@@ -798,7 +875,7 @@
             }
 
             final Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
-            renderDrawableToBitmap(drawable, bitmap, 0, 0, width, height);
+            renderDrawableToBitmap(drawable, bitmap, 0, 0, width, height, 1.0f, 1.0f);
 
             newDrawable = new FastBitmapDrawable(bitmap);
         }
@@ -855,6 +932,7 @@
 
             PagedViewWidget l = (PagedViewWidget) mInflater.inflate(
                     R.layout.customize_paged_view_widget, layout, false);
+
             l.applyFromAppWidgetProviderInfo(info, icon, mMaxWidgetWidth, cellSpans,
                     mPageViewIconCache, (numPages > 1));
             l.setTag(createItemInfo);
@@ -1010,10 +1088,12 @@
 
     @Override
     public void syncPages() {
+        boolean enforceMinimumPagedWidths = false;
         boolean centerPagedViewCellLayouts = false;
         switch (mCustomizationType) {
         case WidgetCustomization:
             syncWidgetPages();
+            enforceMinimumPagedWidths = true;
             break;
         case ShortcutCustomization:
             syncListPages(mShortcutList);
@@ -1021,6 +1101,7 @@
             break;
         case WallpaperCustomization:
             syncWallpaperPages();
+            enforceMinimumPagedWidths = true;
             break;
         case ApplicationCustomization:
             syncAppPages();
@@ -1046,8 +1127,20 @@
             }
         }
 
-        // bound the current page
-        setCurrentPage(Math.max(0, Math.min(childCount - 1, getCurrentPage())));
+        // Set a min page width for PagedView layout if we have more than a single page
+        if (enforceMinimumPagedWidths) {
+            setMinimumWidthOverride((childCount > 1) ? mMinPageWidth : 0);
+        }
+
+        // Bound the current page index
+        requestLayout();
+        post(new Runnable() {
+            @Override
+            public void run() {
+                setCurrentPage(Math.max(0, Math.min(childCount - 1, getCurrentPage())));
+                forceUpdateAdjacentPagesAlpha();
+            }
+        });
     }
 
     @Override
diff --git a/src/com/android/launcher2/CustomizeTrayTabHost.java b/src/com/android/launcher2/CustomizeTrayTabHost.java
new file mode 100644
index 0000000..76cfc84
--- /dev/null
+++ b/src/com/android/launcher2/CustomizeTrayTabHost.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.animation.Animator;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.TabHost;
+
+public class CustomizeTrayTabHost extends TabHost implements LauncherTransitionable {
+    private boolean mFirstLayout = true;
+
+    public CustomizeTrayTabHost(Context context) {
+        super(context);
+    }
+
+    public CustomizeTrayTabHost(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public void onLauncherTransitionStart(Animator animation) {
+        if (animation != null) {
+            setLayerType(LAYER_TYPE_HARDWARE, null);
+            // just a sanity check that we don't build a layer before a call to onLayout
+            if (!mFirstLayout) {
+                // force building the layer at the beginning of the animation, so you don't get a
+                // blip early in the animation
+                buildLayer();
+            }
+        }
+    }
+
+    @Override
+    public void onLauncherTransitionEnd(Animator animation) {
+        if (animation != null) {
+            setLayerType(LAYER_TYPE_NONE, null);
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        mFirstLayout = false;
+        super.onLayout(changed, l, t, r, b);
+    }
+}
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index 45b359d..cb4509b 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -205,9 +205,7 @@
         int screenX = loc[0];
         int screenY = loc[1];
 
-        startDrag(b, screenX, screenY, 0, 0, b.getWidth(), b.getHeight(),
-                source, dragInfo, dragAction, dragRegion);
-
+        startDrag(b, screenX, screenY, source, dragInfo, dragAction, dragRegion);
         b.recycle();
 
         if (dragAction == DRAG_ACTION_MOVE) {
@@ -236,8 +234,7 @@
         int screenX = loc[0];
         int screenY = loc[1];
 
-        startDrag(bmp, screenX, screenY, 0, 0, bmp.getWidth(), bmp.getHeight(),
-                source, dragInfo, dragAction, dragRegion);
+        startDrag(bmp, screenX, screenY, source, dragInfo, dragAction, dragRegion);
 
         if (dragAction == DRAG_ACTION_MOVE) {
             v.setVisibility(View.GONE);
@@ -251,20 +248,14 @@
      *          enlarged size.
      * @param screenX The x position on screen of the left-top of the bitmap.
      * @param screenY The y position on screen of the left-top of the bitmap.
-     * @param textureLeft The left edge of the region inside b to use.
-     * @param textureTop The top edge of the region inside b to use.
-     * @param textureWidth The width of the region inside b to use.
-     * @param textureHeight The height of the region inside b to use.
      * @param source An object representing where the drag originated
      * @param dragInfo The data associated with the object that is being dragged
      * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
      *        {@link #DRAG_ACTION_COPY}
      */
     public void startDrag(Bitmap b, int screenX, int screenY,
-            int textureLeft, int textureTop, int textureWidth, int textureHeight,
             DragSource source, Object dragInfo, int dragAction) {
-        startDrag(b, screenX, screenY, textureLeft, textureTop, textureWidth, textureHeight,
-                source, dragInfo, dragAction, null);
+        startDrag(b, screenX, screenY, source, dragInfo, dragAction, null);
     }
 
     /**
@@ -274,10 +265,6 @@
      *          enlarged size.
      * @param screenX The x position on screen of the left-top of the bitmap.
      * @param screenY The y position on screen of the left-top of the bitmap.
-     * @param textureLeft The left edge of the region inside b to use.
-     * @param textureTop The top edge of the region inside b to use.
-     * @param textureWidth The width of the region inside b to use.
-     * @param textureHeight The height of the region inside b to use.
      * @param source An object representing where the drag originated
      * @param dragInfo The data associated with the object that is being dragged
      * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
@@ -286,7 +273,6 @@
      *          Makes dragging feel more precise, e.g. you can clip out a transparent border
      */
     public void startDrag(Bitmap b, int screenX, int screenY,
-            int textureLeft, int textureTop, int textureWidth, int textureHeight,
             DragSource source, Object dragInfo, int dragAction, Rect dragRegion) {
         if (PROFILE_DRAWING_DURING_DRAG) {
             android.os.Debug.startMethodTracing("Launcher");
@@ -318,7 +304,7 @@
         mVibrator.vibrate(VIBRATE_DURATION);
 
         DragView dragView = mDragView = new DragView(mContext, b, registrationX, registrationY,
-                textureLeft, textureTop, textureWidth, textureHeight);
+                0, 0, b.getWidth(), b.getHeight());
 
         final DragSource dragSource = source;
         dragView.setOnDrawRunnable(new Runnable() {
@@ -400,7 +386,7 @@
     public void cancelDrag() {
         if (mDragging) {
             // Should we also be calling onDragExit() here?
-            mDragSource.onDropCompleted(null, false);
+            mDragSource.onDropCompleted(null, mDragInfo, false);
         }
         endDrag();
     }
@@ -571,6 +557,9 @@
             handleMoveEvent(screenX, screenY);
             break;
         case MotionEvent.ACTION_UP:
+            // Ensure that we've processed a move event at the current pointer location.
+            handleMoveEvent(screenX, screenY);
+
             mHandler.removeCallbacks(mScrollRunnable);
             if (mDragging) {
                 drop(screenX, screenY);
@@ -585,10 +574,11 @@
         return true;
     }
 
-    private boolean drop(float x, float y) {
+    private void drop(float x, float y) {
         final int[] coordinates = mCoordinatesTemp;
-        DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates);
+        final DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates);
 
+        boolean accepted = false;
         if (dropTarget != null) {
             dropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
                     (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
@@ -596,16 +586,10 @@
                     (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo)) {
                 dropTarget.onDrop(mDragSource, coordinates[0], coordinates[1],
                         (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
-                mDragSource.onDropCompleted((View) dropTarget, true);
-                return true;
-            } else {
-                mDragSource.onDropCompleted((View) dropTarget, false);
-                return true;
+                accepted = true;
             }
-        } else {
-            mDragSource.onDropCompleted(null, false);
         }
-        return false;
+        mDragSource.onDropCompleted((View) dropTarget, mDragInfo, accepted);
     }
 
     private DropTarget findDropTarget(int x, int y, int[] dropCoordinates) {
@@ -716,6 +700,10 @@
         mDeleteRegion = region;
     }
 
+    DragView getDragView() {
+        return mDragView;
+    }
+
     private class ScrollRunnable implements Runnable {
         private int mDirection;
 
diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java
index a9dd7e3..eb53945 100644
--- a/src/com/android/launcher2/DragLayer.java
+++ b/src/com/android/launcher2/DragLayer.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher2;
 
+import com.android.launcher.R;
+
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.util.AttributeSet;
@@ -56,6 +58,24 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
+        // If the current CellLayoutChildren has a resize frame, we need to detect if any touch
+        // event has occurred which doesn't result in resizing a widget. In this case, we
+        // dismiss any visible resize frames.
+        final Workspace w = (Workspace) findViewById(R.id.workspace);
+        if (w != null) {
+            final CellLayout currentPage = (CellLayout) w.getChildAt(w.getCurrentPage());
+            final CellLayoutChildren childrenLayout = currentPage.getChildrenLayout();
+
+            if (childrenLayout.hasResizeFrames() && !childrenLayout.isWidgetBeingResized()) {
+                post(new Runnable() {
+                    public void run() {
+                        if (!childrenLayout.isWidgetBeingResized()) {
+                            childrenLayout.clearAllResizeFrames();
+                        }
+                    }
+                });
+            }
+        }
         return mDragController.onInterceptTouchEvent(ev);
     }
 
diff --git a/src/com/android/launcher2/DragScroller.java b/src/com/android/launcher2/DragScroller.java
index 6af9c30..6ef4bd8 100644
--- a/src/com/android/launcher2/DragScroller.java
+++ b/src/com/android/launcher2/DragScroller.java
@@ -26,6 +26,7 @@
 
     /**
      * The touch point has entered the scroll area; a scroll is imminent.
+     * This event will only occur while a drag is active.
      *
      * @param direction The scroll direction
      */
@@ -33,6 +34,7 @@
 
     /**
      * The touch point has left the scroll area.
+     * NOTE: This may not be called, if a drop occurs inside the scroll area.
      */
     void onExitScrollArea();
 }
diff --git a/src/com/android/launcher2/DragSource.java b/src/com/android/launcher2/DragSource.java
index 11cdcc9..4dbdaf7 100644
--- a/src/com/android/launcher2/DragSource.java
+++ b/src/com/android/launcher2/DragSource.java
@@ -31,5 +31,5 @@
      */
     void onDragViewVisible();
 
-    void onDropCompleted(View target, boolean success);
+    void onDropCompleted(View target, Object dragInfo, boolean success);
 }
diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java
index c0776a9..45620b9 100644
--- a/src/com/android/launcher2/DragView.java
+++ b/src/com/android/launcher2/DragView.java
@@ -245,5 +245,13 @@
     void remove() {
         mWindowManager.removeView(this);
     }
+
+    int[] getPosition(int[] result) {
+        WindowManager.LayoutParams lp = mLayoutParams;
+        if (result == null) result = new int[2];
+        result[0] = lp.x;
+        result[1] = lp.y;
+        return result;
+    }
 }
 
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index cb450b9..059e73d 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -114,7 +114,7 @@
     }
 
     @Override
-    public void onDropCompleted(View target, boolean success) {
+    public void onDropCompleted(View target, Object dragInfo, boolean success) {
     }
 
     @Override
diff --git a/src/com/android/launcher2/HolographicOutlineHelper.java b/src/com/android/launcher2/HolographicOutlineHelper.java
index 1efc123..80548fb 100644
--- a/src/com/android/launcher2/HolographicOutlineHelper.java
+++ b/src/com/android/launcher2/HolographicOutlineHelper.java
@@ -32,6 +32,7 @@
     private final Paint mAlphaClipPaint = new Paint();
 
     public static final int MAX_OUTER_BLUR_RADIUS;
+    public static final int MIN_OUTER_BLUR_RADIUS;
 
     private static final BlurMaskFilter sExtraThickOuterBlurMaskFilter;
     private static final BlurMaskFilter sThickOuterBlurMaskFilter;
@@ -48,6 +49,7 @@
     static {
         final float scale = LauncherApplication.getScreenDensity();
 
+        MIN_OUTER_BLUR_RADIUS = (int) (scale * 1.0f);
         MAX_OUTER_BLUR_RADIUS = (int) (scale * 12.0f);
 
         sExtraThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 12.0f, BlurMaskFilter.Blur.OUTER);
diff --git a/src/com/android/launcher2/IconCache.java b/src/com/android/launcher2/IconCache.java
index 2e47adc..0c26bf0 100644
--- a/src/com/android/launcher2/IconCache.java
+++ b/src/com/android/launcher2/IconCache.java
@@ -68,11 +68,13 @@
                 com.android.internal.R.mipmap.sym_def_app_icon);
     }
 
-    public Drawable getFullResIcon(Resources resources, int iconId) {
+    public Drawable getFullResIcon(Resources resources, int iconId)
+            throws Resources.NotFoundException {
         return resources.getDrawableForDensity(iconId, mIconDpi);
     }
 
-    public Drawable getFullResIcon(ResolveInfo info, PackageManager packageManager) {
+    public Drawable getFullResIcon(ResolveInfo info, PackageManager packageManager)
+            throws Resources.NotFoundException {
         Resources resources;
         try {
             resources = packageManager.getResourcesForApplication(
@@ -174,8 +176,14 @@
             if (entry.title == null) {
                 entry.title = info.activityInfo.name;
             }
-            entry.icon = Utilities.createIconBitmap(
-                    getFullResIcon(info, mPackageManager), mContext);
+
+            Drawable icon;
+            try {
+                icon = getFullResIcon(info, mPackageManager);
+            } catch (Resources.NotFoundException e) {
+                icon = getFullResDefaultActivityIcon();
+            }
+            entry.icon = Utilities.createIconBitmap(icon, mContext);
         }
         return entry;
     }
diff --git a/src/com/android/launcher2/ItemInfo.java b/src/com/android/launcher2/ItemInfo.java
index dc45750..b361214 100644
--- a/src/com/android/launcher2/ItemInfo.java
+++ b/src/com/android/launcher2/ItemInfo.java
@@ -81,6 +81,11 @@
      */
     boolean isGesture = false;
 
+    /**
+     * The position of the item in a drag-and-drop operation.
+     */
+    int[] dropPos = null;
+
     ItemInfo() {
     }
 
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index df6ff36..d7a360d 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -26,7 +26,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.app.Activity;
@@ -88,6 +87,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.view.View.OnClickListener;
 import android.view.View.OnLongClickListener;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.DecelerateInterpolator;
@@ -181,7 +181,7 @@
     private static final String TOOLBAR_ICON_METADATA_NAME = "com.android.launcher.toolbar_icon";
 
     /** The different states that Launcher can be in. */
-    private enum State { WORKSPACE, ALL_APPS, CUSTOMIZE, OVERVIEW,
+    private enum State { WORKSPACE, ALL_APPS, CUSTOMIZE,
         CUSTOMIZE_SPRING_LOADED, ALL_APPS_SPRING_LOADED };
     private State mState = State.WORKSPACE;
     private AnimatorSet mStateAnimation;
@@ -217,6 +217,11 @@
     private TabHost mHomeCustomizationDrawer;
     private boolean mAutoAdvanceRunning = false;
 
+    private View mButtonCluster;
+    private View mAllAppsButton;
+    private View mDivider;
+    private View mConfigureButton;
+
     private AllAppsPagedView mAllAppsPagedView = null;
     private CustomizePagedView mCustomizePagedView = null;
 
@@ -245,6 +250,7 @@
 
     private static HashMap<Long, FolderInfo> sFolders = new HashMap<Long, FolderInfo>();
 
+    // The "signpost" images along the bottom of the screen (only in some layouts)
     private ImageView mPreviousView;
     private ImageView mNextView;
 
@@ -274,6 +280,19 @@
     private static Drawable.ConstantState sVoiceSearchIcon;
     private static Drawable.ConstantState sAppMarketIcon;
 
+    private BubbleTextView mWaitingForResume;
+
+    private static ArrayList<PendingAddArguments> sPendingAddList
+            = new ArrayList<PendingAddArguments>();
+
+    private static class PendingAddArguments {
+        int requestCode;
+        Intent intent;
+        int screen;
+        int cellX;
+        int cellY;
+    }
+
     private CustomizationType getCustomizeFilterForTabTag(String tag) {
         if (tag.equals(WIDGETS_TAG)) {
             return CustomizationType.WidgetCustomization;
@@ -321,7 +340,7 @@
 
             // share the same customization workspace across all the tabs
             mCustomizePagedView = (CustomizePagedView) mInflater.inflate(
-                    R.layout.customization_drawer, mHomeCustomizationDrawer, false);
+                    R.layout.customization_drawer_tab_contents, mHomeCustomizationDrawer, false);
             TabContentFactory contentFactory = new TabContentFactory() {
                 public View createTabContent(String tag) {
                     return mCustomizePagedView;
@@ -409,8 +428,11 @@
 
         // If we have a saved version of these external icons, we load them up immediately
         if (LauncherApplication.isScreenXLarge()) {
+            if (sGlobalSearchIcon == null || sVoiceSearchIcon == null || sAppMarketIcon == null) {
+                updateIconsAffectedByPackageManagerChanges();
+            }
             if (sGlobalSearchIcon != null) {
-                updateGlobalSearchIcon(sGlobalSearchIcon);
+                 updateGlobalSearchIcon(sGlobalSearchIcon);
             }
             if (sVoiceSearchIcon != null) {
                 updateVoiceSearchIcon(sVoiceSearchIcon);
@@ -695,8 +717,38 @@
         }
     }
 
+    private void completeAdd(PendingAddArguments args) {
+        switch (args.requestCode) {
+            case REQUEST_PICK_APPLICATION:
+                completeAddApplication(args.intent, args.screen, args.cellX, args.cellY);
+                break;
+            case REQUEST_PICK_SHORTCUT:
+                processShortcut(args.intent);
+                break;
+            case REQUEST_CREATE_SHORTCUT:
+                completeAddShortcut(args.intent, args.screen, args.cellX, args.cellY);
+                break;
+            case REQUEST_PICK_LIVE_FOLDER:
+                addLiveFolder(args.intent);
+                break;
+            case REQUEST_CREATE_LIVE_FOLDER:
+                completeAddLiveFolder(args.intent, args.screen, args.cellX, args.cellY);
+                break;
+            case REQUEST_PICK_APPWIDGET:
+                addAppWidgetFromPick(args.intent);
+                break;
+            case REQUEST_CREATE_APPWIDGET:
+                int appWidgetId = args.intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
+                completeAddAppWidget(appWidgetId, args.screen);
+                break;
+            case REQUEST_PICK_WALLPAPER:
+                // We just wanted the activity result here so we can clear mWaitingForResult
+                break;
+        }
+    }
+
     @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+    protected void onActivityResult(final int requestCode, int resultCode, final Intent data) {
         mWaitingForResult = false;
 
         // The pattern used here is that a user PICKs a specific application,
@@ -706,33 +758,18 @@
         // launch over to the Music app to actually CREATE_SHORTCUT.
 
         if (resultCode == RESULT_OK && mAddScreen != -1) {
-            switch (requestCode) {
-                case REQUEST_PICK_APPLICATION:
-                    completeAddApplication(
-                            this, data, mAddScreen, mAddIntersectCellX, mAddIntersectCellY);
-                    break;
-                case REQUEST_PICK_SHORTCUT:
-                    processShortcut(data);
-                    break;
-                case REQUEST_CREATE_SHORTCUT:
-                    completeAddShortcut(data, mAddScreen, mAddIntersectCellX, mAddIntersectCellY);
-                    break;
-                case REQUEST_PICK_LIVE_FOLDER:
-                    addLiveFolder(data);
-                    break;
-                case REQUEST_CREATE_LIVE_FOLDER:
-                    completeAddLiveFolder(data, mAddScreen, mAddIntersectCellX, mAddIntersectCellY);
-                    break;
-                case REQUEST_PICK_APPWIDGET:
-                    addAppWidgetFromPick(data);
-                    break;
-                case REQUEST_CREATE_APPWIDGET:
-                    int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
-                    completeAddAppWidget(appWidgetId, mAddScreen);
-                    break;
-                case REQUEST_PICK_WALLPAPER:
-                    // We just wanted the activity result here so we can clear mWaitingForResult
-                    break;
+            final PendingAddArguments args = new PendingAddArguments();
+            args.requestCode = requestCode;
+            args.intent = data;
+            args.screen = mAddScreen;
+            args.cellX = mAddIntersectCellX;
+            args.cellY = mAddIntersectCellY;
+
+            // If the loader is still running, defer the add until it is done.
+            if (isWorkspaceLocked()) {
+                sPendingAddList.add(args);
+            } else {
+                completeAdd(args);
             }
         } else if ((requestCode == REQUEST_PICK_APPWIDGET ||
                 requestCode == REQUEST_CREATE_APPWIDGET) && resultCode == RESULT_CANCELED &&
@@ -755,6 +792,9 @@
             mRestoring = false;
             mOnResumeNeedsLoad = false;
         }
+        if (mWaitingForResume != null) {
+            mWaitingForResume.setStayPressed(false);
+        }
         // When we resume Launcher, a different Activity might be responsible for the app
         // market intent, so refresh the icon
         updateAppMarketIcon();
@@ -1027,6 +1067,11 @@
             View marketButton = findViewById(R.id.market_button);
             if (marketButton != null) {
                 allAppsInfoTarget.setOverlappingView(marketButton);
+                marketButton.setOnClickListener(new OnClickListener() {
+                    public void onClick(View v) {
+                        onClickAppMarketButton(v);
+                    }
+                });
             }
         }
 
@@ -1043,6 +1088,36 @@
         if (allAppsDeleteZone != null) {
             dragController.addDropTarget(allAppsDeleteZone);
         }
+        mButtonCluster = findViewById(R.id.all_apps_button_cluster);
+
+        mAllAppsButton = findViewById(R.id.all_apps_button);
+        mDivider = findViewById(R.id.divider);
+        mConfigureButton = findViewById(R.id.configure_button);
+
+        // We had previously set these click handlers in XML, but the first time we launched
+        // Configure or All Apps we had an extra 50ms of delay while the java reflection methods
+        // found the right handler. Setting the handlers directly here eliminates that cost.
+        if (mConfigureButton != null) {
+            mConfigureButton.setOnClickListener(new OnClickListener() {
+                public void onClick(View v) {
+                    onClickConfigureButton(v);
+                }
+            });
+        }
+        if (mDivider != null) {
+            mDivider.setOnClickListener(new OnClickListener() {
+                public void onClick(View v) {
+                    onClickAllAppsButton(v);
+                }
+            });
+        }
+        if (mAllAppsButton != null) {
+            mAllAppsButton.setOnClickListener(new OnClickListener() {
+                public void onClick(View v) {
+                    onClickAllAppsButton(v);
+                }
+            });
+        }
     }
 
     @SuppressWarnings({"UnusedDeclaration"})
@@ -1114,7 +1189,7 @@
      * @param data The intent describing the application.
      * @param cellInfo The position on screen where to create the shortcut.
      */
-    void completeAddApplication(Context context, Intent data, int screen,
+    void completeAddApplication(Intent data, int screen,
             int intersectCellX, int intersectCellY) {
         final int[] cellXY = mTmpAddItemCellCoordinates;
         final CellLayout layout = (CellLayout) mWorkspace.getChildAt(screen);
@@ -1124,8 +1199,7 @@
             return;
         }
 
-        final ShortcutInfo info = mModel.getShortcutInfo(context.getPackageManager(),
-                data, context);
+        final ShortcutInfo info = mModel.getShortcutInfo(getPackageManager(), data, this);
 
         if (info != null) {
             info.setActivity(data.getComponent(), Intent.FLAG_ACTIVITY_NEW_TASK |
@@ -1182,7 +1256,7 @@
      * @param appWidgetId The app widget id
      * @param cellInfo The position on screen where to create the widget.
      */
-    private void completeAddAppWidget(int appWidgetId, int screen) {
+    private void completeAddAppWidget(final int appWidgetId, int screen) {
         AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
 
         // Calculate the grid spans needed to fit this widget
@@ -1212,7 +1286,16 @@
         }
 
         if (!foundCellSpan) {
-            if (appWidgetId != -1) mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+            if (appWidgetId != -1) {
+                // Deleting an app widget ID is a void call but writes to disk before returning
+                // to the caller...
+                final LauncherAppWidgetHost appWidgetHost = mAppWidgetHost;
+                new Thread("deleteAppWidgetId") {
+                    public void run() {
+                        mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+                    }
+                }.start();
+            }
             showOutOfSpaceMessage();
             return;
         }
@@ -1402,16 +1485,15 @@
             boolean alreadyOnHome = ((intent.getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT)
                         != Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
 
-            // in all these cases, only animate if we're already on home
+            // In all these cases, only animate if we're already on home
+
             if (LauncherApplication.isScreenXLarge()) {
                 mWorkspace.unshrink(alreadyOnHome);
             }
-            if (!mWorkspace.isDefaultPageShowing()) {
-                // on the phone, we don't animate the change to the workspace if all apps is visible
-                boolean animate = alreadyOnHome &&
-                    (LauncherApplication.isScreenXLarge() || mState != State.ALL_APPS);
-                mWorkspace.moveToDefaultScreen(animate);
-                if (!animate) mWorkspace.updateWallpaperOffsetImmediately();
+
+            mWorkspace.exitWidgetResizeMode();
+            if (alreadyOnHome && mState == State.WORKSPACE && !mWorkspace.isTouchActive()) {
+                mWorkspace.moveToDefaultScreen(true);
             }
             showWorkspace(alreadyOnHome);
 
@@ -1643,6 +1725,12 @@
         return mWorkspaceLoading || mWaitingForResult;
     }
 
+    // Is the workspace preview (brought up by long-pressing on a signpost icon) visible?
+    private boolean isPreviewVisible() {
+        return (mPreviousView != null && mPreviousView.getTag() != null) ||
+                (mNextView != null && mNextView.getTag() != null);
+    }
+
     private void addItems() {
         if (LauncherApplication.isScreenXLarge()) {
             // Animate the widget chooser up from the bottom of the screen
@@ -1936,13 +2024,16 @@
     public void onBackPressed() {
         if (mState == State.ALL_APPS || mState == State.CUSTOMIZE) {
             showWorkspace(true);
-        } else {
+        } else if (mWorkspace.getOpenFolder() != null) {
             closeFolder();
-        }
-        // Some launcher layouts don't have a previous and next view
-        if (mPreviousView != null) {
+        } else if (isPreviewVisible()) {
             dismissPreview(mPreviousView);
             dismissPreview(mNextView);
+        } else {
+            mWorkspace.exitWidgetResizeMode();
+
+            // Back button is a no-op here, but give at least some feedback for the button press
+            mWorkspace.showOutlinesTemporarily();
         }
     }
 
@@ -1971,7 +2062,9 @@
      * Re-listen when widgets are reset.
      */
     private void onAppWidgetReset() {
-        mAppWidgetHost.startListening();
+        if (mAppWidgetHost != null) {
+            mAppWidgetHost.startListening();
+        }
     }
 
     /**
@@ -1999,7 +2092,12 @@
             v.getLocationOnScreen(pos);
             intent.setSourceBounds(new Rect(pos[0], pos[1],
                     pos[0] + v.getWidth(), pos[1] + v.getHeight()));
-            startActivitySafely(intent, tag);
+            boolean success = startActivitySafely(intent, tag);
+
+            if (success && v instanceof BubbleTextView) {
+                mWaitingForResume = (BubbleTextView) v;
+                mWaitingForResume.setStayPressed(true);
+            }
         } else if (tag instanceof FolderInfo) {
             handleFolderClick((FolderInfo) tag);
         } else if (v == mHandleView) {
@@ -2092,10 +2190,11 @@
         }
     }
 
-    void startActivitySafely(Intent intent, Object tag) {
+    boolean startActivitySafely(Intent intent, Object tag) {
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         try {
             startActivity(intent);
+            return true;
         } catch (ActivityNotFoundException e) {
             Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
             Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
@@ -2106,6 +2205,7 @@
                     "or use the exported attribute for this activity. "
                     + "tag="+ tag + " intent=" + intent, e);
         }
+        return false;
     }
 
     void startActivityForResultSafely(Intent intent, int requestCode) {
@@ -2175,6 +2275,10 @@
     }
 
     public boolean onLongClick(View v) {
+        if (mState != State.WORKSPACE) {
+            return false;
+        }
+
         switch (v.getId()) {
             case R.id.previous_screen:
                 if (mState != State.ALL_APPS) {
@@ -2207,7 +2311,6 @@
             v = (View) v.getParent().getParent();
         }
 
-
         resetAddInfo();
         CellLayout.CellInfo longClickCellInfo = (CellLayout.CellInfo) v.getTag();
         // This happens when long clicking an item with the dpad/trackball
@@ -2379,6 +2482,10 @@
         return mWorkspace;
     }
 
+    TabHost getCustomizationDrawer() {
+        return mHomeCustomizationDrawer;
+    }
+
     @Override
     protected Dialog onCreateDialog(int id) {
         switch (id) {
@@ -2536,7 +2643,7 @@
         }
     }
     
-    private void showToolbarButton(View button) {
+    private void showAndEnableToolbarButton(View button) {
         button.setVisibility(View.VISIBLE);
         button.setFocusable(true);
         button.setClickable(true);
@@ -2546,6 +2653,9 @@
         button.setAlpha(0.0f);
         // We can't set it to GONE, otherwise the RelativeLayout gets screwed up
         button.setVisibility(View.INVISIBLE);
+    }
+
+    private void disableToolbarButton(View button) {
         button.setFocusable(false);
         button.setClickable(false);
     }
@@ -2567,12 +2677,18 @@
                 getResources().getInteger(R.integer.config_toolbarButtonFadeOutTime);
 
         if (seq != null) {
-            Animator anim = ObjectAnimator.ofFloat(view, "alpha", show ? 1.0f : 0.0f);
+            ValueAnimator anim = ValueAnimator.ofFloat(view.getAlpha(), show ? 1.0f : 0.0f);
             anim.setDuration(duration);
+            anim.addUpdateListener(new AnimatorUpdateListener() {
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    view.setAlpha((Float) animation.getAnimatedValue());
+                }
+            });
             anim.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationStart(Animator animation) {
-                    if (showing) showToolbarButton(view);
+                    if (showing) showAndEnableToolbarButton(view);
+                    if (hiding) disableToolbarButton(view);
                 }
                 @Override
                 public void onAnimationEnd(Animator animation) {
@@ -2582,9 +2698,10 @@
             seq.play(anim);
         } else {
             if (showing) {
-                showToolbarButton(view);
+                showAndEnableToolbarButton(view);
                 view.setAlpha(1f);
             } else {
+                disableToolbarButton(view);
                 hideToolbarButton(view);
             }
         }
@@ -2599,26 +2716,21 @@
      * @param hideSeq AnimatorSet in which to put "hide" animations, or null.
      */
     private void hideAndShowToolbarButtons(State newState, AnimatorSet showSeq, AnimatorSet hideSeq) {
-        final View buttonCluster = findViewById(R.id.all_apps_button_cluster);
-
-        final View allAppsButton = findViewById(R.id.all_apps_button);
-        final View divider = findViewById(R.id.divider);
-        final View configureButton = findViewById(R.id.configure_button);
-
         switch (newState) {
         case WORKSPACE:
-            hideOrShowToolbarButton(true, buttonCluster, showSeq);
-            mDeleteZone.setOverlappingViews(new View[] { allAppsButton, divider, configureButton });
+            hideOrShowToolbarButton(true, mButtonCluster, showSeq);
+            mDeleteZone.setOverlappingViews(
+                    new View[] { mAllAppsButton, mDivider, mConfigureButton });
             mDeleteZone.setDragAndDropEnabled(true);
             mDeleteZone.setText(getResources().getString(R.string.delete_zone_label_workspace));
             break;
         case ALL_APPS:
-            hideOrShowToolbarButton(false, buttonCluster, hideSeq);
+            hideOrShowToolbarButton(false, mButtonCluster, hideSeq);
             mDeleteZone.setDragAndDropEnabled(false);
             mDeleteZone.setText(getResources().getString(R.string.delete_zone_label_all_apps));
             break;
         case CUSTOMIZE:
-            hideOrShowToolbarButton(false, buttonCluster, hideSeq);
+            hideOrShowToolbarButton(false, mButtonCluster, hideSeq);
             mDeleteZone.setDragAndDropEnabled(false);
             break;
         }
@@ -2659,6 +2771,9 @@
         final int duration = toAllApps ?
                 res.getInteger(R.integer.config_allAppsZoomInTime) :
                 res.getInteger(R.integer.config_customizeZoomInTime);
+        final int fadeDuration = toAllApps ?
+                res.getInteger(R.integer.config_allAppsFadeInTime) :
+                res.getInteger(R.integer.config_customizeFadeInTime);
 
         final float scale = toAllApps ?
                 (float) res.getInteger(R.integer.config_allAppsZoomScaleFactor) :
@@ -2675,7 +2790,7 @@
         }
 
         if (animated) {
-            ValueAnimator scaleAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(duration);
+            final ValueAnimator scaleAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(duration);
             scaleAnim.setInterpolator(new Workspace.ZoomOutInterpolator());
             scaleAnim.addUpdateListener(new AnimatorUpdateListener() {
                 public void onAnimationUpdate(ValueAnimator animation) {
@@ -2688,8 +2803,8 @@
             });
 
             if (toAllApps) {
-                toView.setAlpha(0f);
-                ValueAnimator alphaAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(duration);
+                toView.setFastAlpha(0f);
+                ValueAnimator alphaAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(fadeDuration);
                 alphaAnim.setInterpolator(new DecelerateInterpolator(1.5f));
                 alphaAnim.addUpdateListener(new AnimatorUpdateListener() {
                     public void onAnimationUpdate(ValueAnimator animation) {
@@ -2702,9 +2817,8 @@
                 alphaAnim.start();
             }
 
-            // Only use hardware layers in portrait mode, they don't give any gains in landscape
-            if (mWorkspace.getWidth() < mWorkspace.getHeight()) {
-                toView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            if (toView instanceof LauncherTransitionable) {
+                ((LauncherTransitionable) toView).onLauncherTransitionStart(scaleAnim);
             }
             scaleAnim.addListener(new AnimatorListenerAdapter() {
                 @Override
@@ -2714,7 +2828,7 @@
                     toView.setTranslationY(0.0f);
                     toView.setVisibility(View.VISIBLE);
                     if (!toAllApps) {
-                        toView.setAlpha(1.0f);
+                        toView.setFastAlpha(1.0f);
                     }
                 }
                 @Override
@@ -2722,9 +2836,11 @@
                     // If we don't set the final scale values here, if this animation is cancelled
                     // it will have the wrong scale value and subsequent cameraPan animations will
                     // not fix that
-                    toView.setLayerType(View.LAYER_TYPE_NONE, null);
                     toView.setScaleX(1.0f);
                     toView.setScaleY(1.0f);
+                    if (toView instanceof LauncherTransitionable) {
+                        ((LauncherTransitionable) toView).onLauncherTransitionEnd(scaleAnim);
+                    }
                 }
             });
 
@@ -2750,6 +2866,10 @@
             toView.setScaleX(1.0f);
             toView.setScaleY(1.0f);
             toView.setVisibility(View.VISIBLE);
+            if (toView instanceof LauncherTransitionable) {
+                ((LauncherTransitionable) toView).onLauncherTransitionStart(null);
+                ((LauncherTransitionable) toView).onLauncherTransitionEnd(null);
+            }
             hideAndShowToolbarButtons(toState, null, null);
         }
     }
@@ -2805,7 +2925,7 @@
                     fromView.setFastScaleY(a * oldScaleY + b * scaleFactor);
                 }
             });
-            ValueAnimator alphaAnim = ValueAnimator.ofFloat(0f, 1f);
+            final ValueAnimator alphaAnim = ValueAnimator.ofFloat(0f, 1f);
             alphaAnim.setDuration(res.getInteger(R.integer.config_allAppsFadeOutTime));
             alphaAnim.setInterpolator(new DecelerateInterpolator(1.5f));
             alphaAnim.addUpdateListener(new AnimatorUpdateListener() {
@@ -2816,13 +2936,16 @@
                     fromView.setFastAlpha(a * 1f + b * 0f);
                 }
             });
-
-            fromView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            if (fromView instanceof LauncherTransitionable) {
+                ((LauncherTransitionable) fromView).onLauncherTransitionStart(alphaAnim);
+            }
             alphaAnim.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
                     fromView.setVisibility(View.GONE);
-                    fromView.setLayerType(View.LAYER_TYPE_NONE, null);
+                    if (fromView instanceof LauncherTransitionable) {
+                        ((LauncherTransitionable) fromView).onLauncherTransitionEnd(alphaAnim);
+                    }
                 }
             });
 
@@ -2841,100 +2964,23 @@
             mStateAnimation.start();
         } else {
             fromView.setVisibility(View.GONE);
+            if (fromView instanceof LauncherTransitionable) {
+                ((LauncherTransitionable) fromView).onLauncherTransitionStart(null);
+                ((LauncherTransitionable) fromView).onLauncherTransitionEnd(null);
+            }
             if (!springLoaded) {
                 hideAndShowToolbarButtons(State.WORKSPACE, null, null);
             }
         }
     }
 
-    /**
-     * Pan the camera in the vertical plane between 'fromView' and 'toView'.
-     * This is the transition used on xlarge screens to go between all apps and
-     * the home customization drawer.
-     * @param fromState The view to pan away from. Must be ALL_APPS or CUSTOMIZE.
-     * @param toState The view to pan into the frame. Must be ALL_APPS or CUSTOMIZE.
-     * @param animated If true, the transition will be animated.
-     */
-    private void cameraPan(State fromState, State toState, boolean animated) {
-        final Resources res = getResources();
-        final int duration = res.getInteger(R.integer.config_allAppsCameraPanTime);
-        final int workspaceHeight = mWorkspace.getHeight();
-
-        final boolean fromAllApps = (fromState == State.ALL_APPS);
-        final View fromView = fromAllApps ? (View) mAllAppsGrid : mHomeCustomizationDrawer;
-        final View toView = fromAllApps ? mHomeCustomizationDrawer : (View) mAllAppsGrid;
-
-        final float fromViewStartY = fromAllApps ? 0.0f : fromView.getY();
-        final float fromViewEndY = fromAllApps ? -fromView.getHeight() * 2 : workspaceHeight * 2;
-        final float toViewStartY = fromAllApps ? workspaceHeight * 2 : -toView.getHeight() * 2;
-        final float toViewEndY = fromAllApps ? workspaceHeight - toView.getHeight() : 0.0f;
-
-        mCustomizePagedView.endChoiceMode();
-        mAllAppsPagedView.endChoiceMode();
-
-        if (toState == State.ALL_APPS) {
-            mWorkspace.shrink(Workspace.ShrinkState.BOTTOM_HIDDEN, animated);
-        } else {
-            mWorkspace.shrink(Workspace.ShrinkState.TOP, animated);
-        }
-
-        if (animated) {
-            if (mStateAnimation != null) mStateAnimation.cancel();
-            mStateAnimation = new AnimatorSet();
-            mStateAnimation.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    toView.setVisibility(View.VISIBLE);
-                    toView.setY(toViewStartY);
-                    toView.setAlpha(1.0f);
-                }
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    fromView.setVisibility(View.GONE);
-                }
-            });
-
-            AnimatorSet toolbarHideAnim = new AnimatorSet();
-            AnimatorSet toolbarShowAnim = new AnimatorSet();
-            hideAndShowToolbarButtons(toState, toolbarShowAnim, toolbarHideAnim);
-
-            ObjectAnimator fromAnim = ObjectAnimator.ofFloat(fromView, "y",
-                    fromViewStartY, fromViewEndY);
-            fromAnim.setDuration(duration);
-            ObjectAnimator toAnim = ObjectAnimator.ofPropertyValuesHolder(toView,
-                    PropertyValuesHolder.ofFloat("y", toViewStartY, toViewEndY),
-                    PropertyValuesHolder.ofFloat("scaleX", toView.getScaleX(), 1.0f),
-                    PropertyValuesHolder.ofFloat("scaleY", toView.getScaleY(), 1.0f)
-                    );
-            fromAnim.setDuration(duration);
-            mStateAnimation.playTogether(toolbarHideAnim, fromAnim, toAnim);
-
-            // Show the new toolbar buttons just as the main animation is ending
-            final int fadeInTime = res.getInteger(R.integer.config_toolbarButtonFadeInTime);
-            mStateAnimation.play(toolbarShowAnim).after(duration - fadeInTime);
-            mStateAnimation.start();
-        } else {
-            fromView.setY(fromViewEndY);
-            fromView.setVisibility(View.GONE);
-            toView.setY(toViewEndY);
-            toView.setScaleX(1.0f);
-            toView.setScaleY(1.0f);
-            toView.setVisibility(View.VISIBLE);
-            hideAndShowToolbarButtons(toState, null, null);
-        }
-    }
-
     void showAllApps(boolean animated) {
-        if (mState == State.ALL_APPS) {
+        if (mState != State.WORKSPACE) {
             return;
         }
 
         if (LauncherApplication.isScreenXLarge()) {
-            if (mState == State.CUSTOMIZE) {
-                cameraPan(State.CUSTOMIZE, State.ALL_APPS, animated);
-            } else {
-                cameraZoomOut(State.ALL_APPS, animated);
-            }
+            cameraZoomOut(State.ALL_APPS, animated);
         } else {
             mAllAppsGrid.zoom(1.0f, animated);
         }
@@ -3074,11 +3120,12 @@
 
     // Show the customization drawer (only exists in x-large configuration)
     private void showCustomizationDrawer(boolean animated) {
-        if (mState == State.ALL_APPS) {
-            cameraPan(State.ALL_APPS, State.CUSTOMIZE, animated);
-        } else {
-            cameraZoomOut(State.CUSTOMIZE, animated);
+        if (mState != State.WORKSPACE) {
+            return;
         }
+
+        cameraZoomOut(State.CUSTOMIZE, animated);
+
         // Change the state *after* we've called all the transition code
         mState = State.CUSTOMIZE;
 
@@ -3094,9 +3141,15 @@
         }
     }
 
-    void addExternalItemToScreen(ItemInfo itemInfo, CellLayout layout) {
+    /**
+     * Add an item from all apps or customize onto the given workspace screen.
+     * If layout is null, add to the current screen.
+     */
+    void addExternalItemToScreen(ItemInfo itemInfo, final CellLayout layout) {
         if (!mWorkspace.addExternalItemToScreen(itemInfo, layout)) {
             showOutOfSpaceMessage();
+        } else {
+            layout.animateDrop();
         }
     }
 
@@ -3104,11 +3157,7 @@
         showWorkspace(true, layout);
     }
 
-    // if successful in getting icon, return it; otherwise, set button to use default drawable
-    private Drawable.ConstantState updateButtonWithIconFromExternalActivity(
-            int buttonId, ComponentName activityName, int fallbackDrawableId) {
-        ImageView button = (ImageView) findViewById(buttonId);
-        Drawable toolbarIcon = null;
+    private Drawable getExternalPackageToolbarIcon(ComponentName activityName) {
         try {
             PackageManager packageManager = getPackageManager();
             // Look for the toolbar icon specified in the activity meta-data
@@ -3118,12 +3167,37 @@
                 int iconResId = metaData.getInt(TOOLBAR_ICON_METADATA_NAME);
                 if (iconResId != 0) {
                     Resources res = packageManager.getResourcesForActivity(activityName);
-                    toolbarIcon = res.getDrawable(iconResId);
+                    return res.getDrawable(iconResId);
                 }
             }
         } catch (NameNotFoundException e) {
             // Do nothing
         }
+        return null;
+    }
+
+    // if successful in getting icon, return it; otherwise, set button to use default drawable
+    private Drawable.ConstantState updateTextButtonWithIconFromExternalActivity(
+            int buttonId, ComponentName activityName, int fallbackDrawableId) {
+        TextView button = (TextView) findViewById(buttonId);
+        Drawable toolbarIcon = getExternalPackageToolbarIcon(activityName);
+
+        // If we were unable to find the icon via the meta-data, use a generic one
+        if (toolbarIcon == null) {
+            button.setCompoundDrawablesWithIntrinsicBounds(fallbackDrawableId, 0, 0, 0);
+            return null;
+        } else {
+            button.setCompoundDrawablesWithIntrinsicBounds(toolbarIcon, null, null, null);
+            return toolbarIcon.getConstantState();
+        }
+    }
+
+    // if successful in getting icon, return it; otherwise, set button to use default drawable
+    private Drawable.ConstantState updateButtonWithIconFromExternalActivity(
+            int buttonId, ComponentName activityName, int fallbackDrawableId) {
+        ImageView button = (ImageView) findViewById(buttonId);
+        Drawable toolbarIcon = getExternalPackageToolbarIcon(activityName);
+
         // If we were unable to find the icon via the meta-data, use a generic one
         if (toolbarIcon == null) {
             button.setImageResource(fallbackDrawableId);
@@ -3134,6 +3208,11 @@
         }
     }
 
+    private void updateTextButtonWithDrawable(int buttonId, Drawable.ConstantState d) {
+        TextView button = (TextView) findViewById(buttonId);
+        button.setCompoundDrawables(d.newDrawable(getResources()), null, null, null);
+    }
+
     private void updateButtonWithDrawable(int buttonId, Drawable.ConstantState d) {
         ImageView button = (ImageView) findViewById(buttonId);
         button.setImageDrawable(d.newDrawable(getResources()));
@@ -3185,14 +3264,14 @@
             ComponentName activityName = intent.resolveActivity(getPackageManager());
             if (activityName != null) {
                 mAppMarketIntent = intent;
-                sAppMarketIcon = updateButtonWithIconFromExternalActivity(
+                sAppMarketIcon = updateTextButtonWithIconFromExternalActivity(
                         R.id.market_button, activityName, R.drawable.app_market_generic);
             }
         }
     }
 
     private void updateAppMarketIcon(Drawable.ConstantState d) {
-        updateButtonWithDrawable(R.id.market_button, d);
+        updateTextButtonWithDrawable(R.id.market_button, d);
     }
 
     /**
@@ -3536,6 +3615,13 @@
         }
 
         mWorkspaceLoading = false;
+
+        // If we received the result of any pending adds while the loader was running (e.g. the
+        // widget configuration forced an orientation change), process them now.
+        for (int i = 0; i < sPendingAddList.size(); i++) {
+            completeAdd(sPendingAddList.get(i));
+        }
+        sPendingAddList.clear();
     }
 
     /**
@@ -3584,8 +3670,12 @@
     public void bindAppsUpdated(ArrayList<ApplicationInfo> apps) {
         setLoadOnResume();
         removeDialog(DIALOG_CREATE_SHORTCUT);
-        mWorkspace.updateShortcuts(apps);
-        mAllAppsGrid.updateApps(apps);
+        if (mWorkspace != null) {
+            mWorkspace.updateShortcuts(apps);
+        }
+        if (mAllAppsGrid != null) {
+            mAllAppsGrid.updateApps(apps);
+        }
         if (mCustomizePagedView != null) {
             mCustomizePagedView.updateApps(apps);
         }
@@ -3679,3 +3769,8 @@
         Log.d(TAG, "END launcher2 dump state");
     }
 }
+
+interface LauncherTransitionable {
+    void onLauncherTransitionStart(Animator animation);
+    void onLauncherTransitionEnd(Animator animation);
+}
diff --git a/src/com/android/launcher2/LauncherAppWidgetHostView.java b/src/com/android/launcher2/LauncherAppWidgetHostView.java
index 85a80f9..7f60cac 100644
--- a/src/com/android/launcher2/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher2/LauncherAppWidgetHostView.java
@@ -72,7 +72,7 @@
         // Otherwise continue letting touch events fall through to children
         return false;
     }
-    
+
     class CheckForLongPress implements Runnable {
         private int mOriginalWindowAttachCount;
 
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index 0052737..c098749 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -44,6 +44,7 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.net.Uri;
+import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Parcelable;
@@ -65,6 +66,7 @@
     static final String TAG = "Launcher.Model";
 
     private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons
+    private final boolean mAppsCanBeOnExternalStorage;
     private int mBatchSize; // 0 is all apps at once
     private int mAllAppsLoadDelay; // milliseconds between batches
 
@@ -115,6 +117,7 @@
     }
 
     LauncherModel(LauncherApplication app, IconCache iconCache) {
+        mAppsCanBeOnExternalStorage = !Environment.isExternalStorageEmulated();
         mApp = app;
         mAllAppsList = new AllAppsList(iconCache);
         mIconCache = iconCache;
@@ -174,6 +177,33 @@
     }
 
     /**
+     * Resize an item in the DB to a new <spanX, spanY, cellX, cellY>
+     */
+    static void resizeItemInDatabase(Context context, ItemInfo item, int cellX, int cellY,
+            int spanX, int spanY) {
+        item.spanX = spanX;
+        item.spanY = spanY;
+        item.cellX = cellX;
+        item.cellY = cellY;
+
+        final Uri uri = LauncherSettings.Favorites.getContentUri(item.id, false);
+        final ContentValues values = new ContentValues();
+        final ContentResolver cr = context.getContentResolver();
+
+        values.put(LauncherSettings.Favorites.CONTAINER, item.container);
+        values.put(LauncherSettings.Favorites.SPANX, spanX);
+        values.put(LauncherSettings.Favorites.SPANY, spanY);
+        values.put(LauncherSettings.Favorites.CELLX, cellX);
+        values.put(LauncherSettings.Favorites.CELLY, cellY);
+
+        sWorker.post(new Runnable() {
+                public void run() {
+                    cr.update(uri, values, null, null);
+                }
+            });
+    }
+
+    /**
      * Returns true if the shortcuts already exists in the database.
      * we identify a shortcut by its title and intent.
      */
@@ -794,8 +824,6 @@
                             }
 
                             if (info != null) {
-                                updateSavedIcon(context, info, c, iconIndex);
-
                                 info.intent = intent;
                                 info.id = c.getLong(idIndex);
                                 container = c.getInt(containerIndex);
@@ -820,6 +848,10 @@
                                     folderInfo.add(info);
                                     break;
                                 }
+
+                                // now that we've loaded everthing re-save it with the
+                                // icon in case it disappears somehow.
+                                updateSavedIcon(context, info, c, iconIndex);
                             } else {
                                 // Failed to load the shortcut, probably because the
                                 // activity manager couldn't resolve it (maybe the app
@@ -1669,6 +1701,10 @@
     }
 
     void updateSavedIcon(Context context, ShortcutInfo info, Cursor c, int iconIndex) {
+        // If apps can't be on SD, don't even bother.
+        if (!mAppsCanBeOnExternalStorage) {
+            return;
+        }
         // If this icon doesn't have a custom icon, check to see
         // what's stored in the DB, and if it doesn't match what
         // we're going to show, store what we are going to show back
@@ -1691,9 +1727,8 @@
             }
             if (needSave) {
                 Log.d(TAG, "going to save icon bitmap for info=" + info);
-                // This is slower than is ideal, but this only happens either
-                // after the froyo OTA or when the app is updated with a new
-                // icon.
+                // This is slower than is ideal, but this only happens once
+                // or when the app is updated with a new icon.
                 updateItemInDatabase(context, info);
             }
         }
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index e4cdd59..e7ecb99 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -30,6 +30,8 @@
 import android.os.Parcelable;
 import android.util.AttributeSet;
 import android.view.ActionMode;
+import android.view.InputDevice;
+import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
@@ -61,6 +63,7 @@
     private static final float OVERSCROLL_DAMP_FACTOR = 0.08f;
     private static final int MINIMUM_SNAP_VELOCITY = 2200;
     private static final int MIN_FLING_VELOCITY = 250;
+    private static final float RETURN_TO_ORIGINAL_PAGE_THRESHOLD = 0.33f;
 
     // the velocity at which a fling gesture will cause us to snap to the next page
     protected int mSnapVelocity = 500;
@@ -81,6 +84,7 @@
     protected float mLastMotionX;
     protected float mLastMotionXRemainder;
     protected float mLastMotionY;
+    protected float mTotalMotionX;
     private int mLastScreenCenter = -1;
 
     protected final static int TOUCH_STATE_REST = 0;
@@ -98,6 +102,7 @@
     protected int mTouchSlop;
     private int mPagingTouchSlop;
     private int mMaximumVelocity;
+    private int mMinimumWidth;
     protected int mPageSpacing;
     protected int mPageLayoutPaddingTop;
     protected int mPageLayoutPaddingBottom;
@@ -173,13 +178,13 @@
                 R.styleable.PagedView, defStyle, 0);
         mPageSpacing = a.getDimensionPixelSize(R.styleable.PagedView_pageSpacing, 0);
         mPageLayoutPaddingTop = a.getDimensionPixelSize(
-                R.styleable.PagedView_pageLayoutPaddingTop, 10);
+                R.styleable.PagedView_pageLayoutPaddingTop, 0);
         mPageLayoutPaddingBottom = a.getDimensionPixelSize(
-                R.styleable.PagedView_pageLayoutPaddingBottom, 10);
+                R.styleable.PagedView_pageLayoutPaddingBottom, 0);
         mPageLayoutPaddingLeft = a.getDimensionPixelSize(
-                R.styleable.PagedView_pageLayoutPaddingLeft, 10);
+                R.styleable.PagedView_pageLayoutPaddingLeft, 0);
         mPageLayoutPaddingRight = a.getDimensionPixelSize(
-                R.styleable.PagedView_pageLayoutPaddingRight, 10);
+                R.styleable.PagedView_pageLayoutPaddingRight, 0);
         mPageLayoutWidthGap = a.getDimensionPixelSize(
                 R.styleable.PagedView_pageLayoutWidthGap, -1);
         mPageLayoutHeightGap = a.getDimensionPixelSize(
@@ -498,6 +503,11 @@
         }
     }
 
+    protected void forceUpdateAdjacentPagesAlpha() {
+        mDirtyPageAlpha = true;
+        updateAdjacentPagesAlpha();
+    }
+
     protected void updateAdjacentPagesAlpha() {
         if (mFadeInAdjacentScreens) {
             if (mDirtyPageAlpha || (mTouchState == TOUCH_STATE_SCROLLING) || !mScroller.isFinished()) {
@@ -544,6 +554,11 @@
                         alpha = 1.0f;
                     }
 
+                    // Due to the way we're setting alpha on our children in PagedViewCellLayout,
+                    // this optimization causes alpha to not be properly updated sometimes (repro
+                    // case: in xlarge mode, swipe to second page in All Apps, then click on "My
+                    // Apps" tab. the page will have alpha 0 until you swipe it). Removing
+                    // optimization fixes the issue, but we should fix this in a better manner
                     //if (Float.compare(alpha, layout.getAlpha()) != 0) {
                         layout.setAlpha(alpha);
                     //}
@@ -596,21 +611,7 @@
             canvas.clipRect(mScrollX, mScrollY, mScrollX + mRight - mLeft,
                     mScrollY + mBottom - mTop);
 
-            for (int i = 0; i < pageCount; i++) {
-                View child = getChildAt(i);
-                if (child != null && child instanceof PagedViewCellLayout) {
-                    boolean willBeDrawn = i >= leftScreen && i <= rightScreen;
-                    if (!willBeDrawn) {
-                        ((PagedViewCellLayout)child).destroyHardwareLayers();
-                    }
-                }
-            }
-
             for (int i = leftScreen; i <= rightScreen; i++) {
-                View child = getChildAt(i);
-                if (child != null && child instanceof PagedViewCellLayout) {
-                    ((PagedViewCellLayout)child).createHardwareLayers();
-                }
                 drawChild(canvas, getChildAt(i), drawingTime);
             }
             canvas.restore();
@@ -737,6 +738,7 @@
          * If we return true, onTouchEvent will be called and we do the actual
          * scrolling there.
          */
+        acquireVelocityTrackerAndAddMovement(ev);
 
         // Skip touch handling if there are no pages to swipe
         if (getChildCount() <= 0) return super.onInterceptTouchEvent(ev);
@@ -777,6 +779,7 @@
                 mLastMotionX = x;
                 mLastMotionY = y;
                 mLastMotionXRemainder = 0;
+                mTotalMotionX = 0;
                 mActivePointerId = ev.getPointerId(0);
                 mAllowLongPress = true;
 
@@ -814,10 +817,12 @@
                 mTouchState = TOUCH_STATE_REST;
                 mAllowLongPress = false;
                 mActivePointerId = INVALID_POINTER;
+                releaseVelocityTracker();
                 break;
 
             case MotionEvent.ACTION_POINTER_UP:
                 onSecondaryPointerUp(ev);
+                releaseVelocityTracker();
                 break;
         }
 
@@ -869,6 +874,7 @@
             if (mUsePagingTouchSlop ? xPaged : xMoved) {
                 // Scroll if the user moved far enough along the X axis
                 mTouchState = TOUCH_STATE_SCROLLING;
+                mTotalMotionX += Math.abs(mLastMotionX - x);
                 mLastMotionX = x;
                 mLastMotionXRemainder = 0;
                 mTouchX = mScrollX;
@@ -952,6 +958,7 @@
             // Remember where the motion event started
             mDownMotionX = mLastMotionX = ev.getX();
             mLastMotionXRemainder = 0;
+            mTotalMotionX = 0;
             mActivePointerId = ev.getPointerId(0);
             if (mTouchState == TOUCH_STATE_SCROLLING) {
                 pageBeginMoving();
@@ -965,6 +972,8 @@
                 final float x = ev.getX(pointerIndex);
                 final float deltaX = mLastMotionX + mLastMotionXRemainder - x;
 
+                mTotalMotionX += Math.abs(deltaX);
+
                 // Only scroll and update mLastMotionX if we have moved some discrete amount.  We
                 // keep the remainder because we are actually testing if we've moved from the last
                 // scrolled position (which is discrete).
@@ -995,17 +1004,37 @@
                 velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                 int velocityX = (int) velocityTracker.getXVelocity(activePointerId);
                 final int deltaX = (int) (x - mDownMotionX);
-                boolean isfling = Math.abs(deltaX) > MIN_LENGTH_FOR_FLING;
                 boolean isSignificantMove = Math.abs(deltaX) > MIN_LENGTH_FOR_MOVE;
-
                 final int snapVelocity = mSnapVelocity;
-                if ((isSignificantMove && deltaX > 0 ||
-                        (isfling && velocityX > snapVelocity)) && mCurrentPage > 0) {
-                    snapToPageWithVelocity(mCurrentPage - 1, velocityX);
-                } else if ((isSignificantMove && deltaX < 0 ||
-                        (isfling && velocityX < -snapVelocity)) &&
+
+                mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x);
+
+                // In the case that the page is moved far to one direction and then is flung
+                // in the opposite direction, we use a threshold to determine whether we should
+                // just return to the starting page, or if we should skip one further.
+                boolean returnToOriginalPage = false;
+                final int pageWidth = getScaledMeasuredWidth(getChildAt(mCurrentPage));
+                if (Math.abs(deltaX) > pageWidth * RETURN_TO_ORIGINAL_PAGE_THRESHOLD &&
+                        Math.signum(velocityX) != Math.signum(deltaX)) {
+                    returnToOriginalPage = true;
+                }
+
+                boolean isFling = mTotalMotionX > MIN_LENGTH_FOR_FLING &&
+                        Math.abs(velocityX) > snapVelocity;
+
+                int finalPage;
+                // We give flings precedence over large moves, which is why we short-circuit our
+                // test for a large move if a fling has been registered. That is, a large
+                // move to the left and fling to the right will register as a fling to the right.
+                if (((isSignificantMove && deltaX > 0 && !isFling) ||
+                        (isFling && velocityX > 0)) && mCurrentPage > 0) {
+                    finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
+                    snapToPageWithVelocity(finalPage, velocityX);
+                } else if (((isSignificantMove && deltaX < 0 && !isFling) ||
+                        (isFling && velocityX < 0)) &&
                         mCurrentPage < getChildCount() - 1) {
-                    snapToPageWithVelocity(mCurrentPage + 1, velocityX);
+                    finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage + 1;
+                    snapToPageWithVelocity(finalPage, velocityX);
                 } else {
                     snapToDestination();
                 }
@@ -1054,6 +1083,35 @@
         return true;
     }
 
+    @Override
+    public boolean onGenericMotionEvent(MotionEvent event) {
+        if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+            switch (event.getAction()) {
+                case MotionEvent.ACTION_SCROLL: {
+                    // Handle mouse (or ext. device) by shifting the page depending on the scroll
+                    final float vscroll;
+                    final float hscroll;
+                    if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) {
+                        vscroll = 0;
+                        hscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+                    } else {
+                        vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+                        hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
+                    }
+                    if (hscroll != 0 || vscroll != 0) {
+                        if (hscroll > 0 || vscroll > 0) {
+                            scrollRight();
+                        } else {
+                            scrollLeft();
+                        }
+                        return true;
+                    }
+                }
+            }
+        }
+        return super.onGenericMotionEvent(event);
+    }
+
     private void acquireVelocityTrackerAndAddMovement(MotionEvent ev) {
         if (mVelocityTracker == null) {
             mVelocityTracker = VelocityTracker.obtain();
@@ -1116,8 +1174,16 @@
         return -1;
     }
 
+    protected void setMinimumWidthOverride(int minimumWidth) {
+        mMinimumWidth = minimumWidth;
+    }
+
+    protected int getChildWidth(int index) {
+        return Math.max(mMinimumWidth, getChildAt(index).getMeasuredWidth());
+    }
+
     protected int getRelativeChildOffset(int index) {
-        return (getMeasuredWidth() - getChildAt(index).getMeasuredWidth()) / 2;
+        return (getMeasuredWidth() - getChildWidth(index)) / 2;
     }
 
     protected int getChildOffset(int index) {
@@ -1132,7 +1198,7 @@
     }
 
     protected int getScaledMeasuredWidth(View child) {
-        return (int) (child.getMeasuredWidth() * mLayoutScale + 0.5f);
+        return (int) (Math.max(mMinimumWidth, child.getMeasuredWidth()) * mLayoutScale + 0.5f);
     }
 
     int getPageNearestToCenterOfScreen() {
@@ -1398,7 +1464,7 @@
      * Otherwise, returns null.
      */
     protected Checkable getSingleCheckedGrandchild() {
-        if (mChoiceMode == CHOICE_MODE_SINGLE) {
+        if (mChoiceMode != CHOICE_MODE_MULTIPLE) {
             final int childCount = getChildCount();
             for (int i = 0; i < childCount; ++i) {
                 Page layout = (Page) getChildAt(i);
@@ -1414,14 +1480,6 @@
         return null;
     }
 
-    public Object getChosenItem() {
-        View checkedView = (View) getSingleCheckedGrandchild();
-        if (checkedView != null) {
-            return checkedView.getTag();
-        }
-        return null;
-    }
-
     protected void resetCheckedGrandchildren() {
         // loop through children, and set all of their children to _not_ be checked
         final ArrayList<Checkable> checked = getCheckedGrandchildren();
diff --git a/src/com/android/launcher2/PagedViewCellLayout.java b/src/com/android/launcher2/PagedViewCellLayout.java
index d64f3c9..28bb78b 100644
--- a/src/com/android/launcher2/PagedViewCellLayout.java
+++ b/src/com/android/launcher2/PagedViewCellLayout.java
@@ -40,7 +40,8 @@
     private static int sDefaultCellDimensions = 96;
     protected PagedViewCellLayoutChildren mChildren;
     private PagedViewCellLayoutChildren mHolographicChildren;
-    private boolean mUseHardwareLayers = false;
+    private boolean mAllowHardwareLayerCreation = false;
+    private boolean mCreateHardwareLayersIfAllowed = false;
 
     public PagedViewCellLayout(Context context) {
         this(context, null);
@@ -74,8 +75,17 @@
         addView(mHolographicChildren);
     }
 
-    public void enableHardwareLayers() {
-        mUseHardwareLayers = true;
+    public void allowHardwareLayerCreation() {
+        // This is called after the first time we launch into All Apps. Before that point,
+        // there's no need for hardware layers here since there's a hardware layer set on the
+        // parent, AllAppsTabbed, during the AllApps transition -- creating hardware layers here
+        // before the animation is done slows down the animation
+        if (!mAllowHardwareLayerCreation) {
+            mAllowHardwareLayerCreation = true;
+            if (mCreateHardwareLayersIfAllowed) {
+                createHardwareLayers();
+            }
+        }
     }
 
     @Override
@@ -85,13 +95,18 @@
     }
 
     void destroyHardwareLayers() {
-        if (mUseHardwareLayers) {
+        // called when a page is no longer visible (triggered by loadAssociatedPages ->
+        // removeAllViewsOnPage)
+        mCreateHardwareLayersIfAllowed = false;
+        if (mAllowHardwareLayerCreation) {
             mChildren.destroyHardwareLayer();
             mHolographicChildren.destroyHardwareLayer();
         }
     }
     void createHardwareLayers() {
-        if (mUseHardwareLayers) {
+        // called when a page is visible (triggered by loadAssociatedPages -> syncPageItems)
+        mCreateHardwareLayersIfAllowed = true;
+        if (mAllowHardwareLayerCreation) {
             mChildren.createHardwareLayer();
             mHolographicChildren.createHardwareLayer();
         }
@@ -127,7 +142,7 @@
 
             if (child instanceof PagedViewIcon) {
                 PagedViewIcon pagedViewIcon = (PagedViewIcon) child;
-                if (mUseHardwareLayers) {
+                if (mAllowHardwareLayerCreation) {
                     pagedViewIcon.disableCache();
                 }
                 mHolographicChildren.addView(pagedViewIcon.getHolographicOutlineView(), index, lp);
@@ -141,6 +156,7 @@
     public void removeAllViewsOnPage() {
         mChildren.removeAllViews();
         mHolographicChildren.removeAllViews();
+        destroyHardwareLayers();
     }
 
     @Override
diff --git a/src/com/android/launcher2/PagedViewCellLayoutChildren.java b/src/com/android/launcher2/PagedViewCellLayoutChildren.java
index 27da02a..92ff461 100644
--- a/src/com/android/launcher2/PagedViewCellLayoutChildren.java
+++ b/src/com/android/launcher2/PagedViewCellLayoutChildren.java
@@ -139,12 +139,12 @@
     }
 
     void destroyHardwareLayer() {
-        if (getLayerType() == LAYER_TYPE_HARDWARE) {
+        if (getLayerType() != LAYER_TYPE_NONE) {
             setLayerType(LAYER_TYPE_NONE, null);
         }
     }
     void createHardwareLayer() {
-        if (getLayerType() == LAYER_TYPE_NONE) {
+        if (getLayerType() != LAYER_TYPE_HARDWARE) {
             setLayerType(LAYER_TYPE_HARDWARE, null);
         }
     }
diff --git a/src/com/android/launcher2/PagedViewIcon.java b/src/com/android/launcher2/PagedViewIcon.java
index 1366619..bde6559 100644
--- a/src/com/android/launcher2/PagedViewIcon.java
+++ b/src/com/android/launcher2/PagedViewIcon.java
@@ -141,13 +141,15 @@
         return mHolographicOutline;
     }
 
-    private void queueHolographicOutlineCreation() {
+    private boolean queueHolographicOutlineCreation() {
         // Generate the outline in the background
         if (mHolographicOutline == null) {
             Message m = sWorker.obtainMessage(MESSAGE_CREATE_HOLOGRAPHIC_OUTLINE);
             m.obj = this;
             sWorker.sendMessage(m);
+            return true;
         }
+        return false;
     }
 
     public void applyFromApplicationInfo(ApplicationInfo info, PagedViewIconCache cache,
@@ -161,7 +163,9 @@
             mIconCache = cache;
             mIconCacheKey = new PagedViewIconCache.Key(info);
             mHolographicOutline = mIconCache.getOutline(mIconCacheKey);
-            queueHolographicOutlineCreation();
+            if (!queueHolographicOutlineCreation()) {
+                getHolographicOutlineView().invalidate();
+            }
         }
     }
 
@@ -177,7 +181,9 @@
             mIconCache = cache;
             mIconCacheKey = new PagedViewIconCache.Key(info);
             mHolographicOutline = mIconCache.getOutline(mIconCacheKey);
-            queueHolographicOutlineCreation();
+            if (!queueHolographicOutlineCreation()) {
+                getHolographicOutlineView().invalidate();
+            }
         }
     }
 
@@ -243,8 +249,7 @@
         return mIsChecked;
     }
 
-    @Override
-    public void setChecked(boolean checked) {
+    void setChecked(boolean checked, boolean animate) {
         if (mIsChecked != checked) {
             mIsChecked = checked;
 
@@ -262,15 +267,24 @@
             if (mCheckedAlphaAnimator != null) {
                 mCheckedAlphaAnimator.cancel();
             }
-            mCheckedAlphaAnimator = ObjectAnimator.ofFloat(this, "alpha", getAlpha(), alpha);
-            mCheckedAlphaAnimator.setDuration(duration);
-            mCheckedAlphaAnimator.start();
+            if (animate) {
+                mCheckedAlphaAnimator = ObjectAnimator.ofFloat(this, "alpha", getAlpha(), alpha);
+                mCheckedAlphaAnimator.setDuration(duration);
+                mCheckedAlphaAnimator.start();
+            } else {
+                setAlpha(alpha);
+            }
 
             invalidate();
         }
     }
 
     @Override
+    public void setChecked(boolean checked) {
+        setChecked(checked, true);
+    }
+
+    @Override
     public void toggle() {
         setChecked(!mIsChecked);
     }
diff --git a/src/com/android/launcher2/PagedViewWidget.java b/src/com/android/launcher2/PagedViewWidget.java
index 9b83f48..72f928b 100644
--- a/src/com/android/launcher2/PagedViewWidget.java
+++ b/src/com/android/launcher2/PagedViewWidget.java
@@ -27,7 +27,11 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
+import android.graphics.PorterDuff;
 import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.RectF;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
@@ -52,6 +56,10 @@
     private Bitmap mHolographicOutline;
     private final Canvas mHolographicOutlineCanvas = new Canvas();
     private FastBitmapDrawable mPreview;
+    private ImageView mPreviewImageView;
+    private final RectF mTmpScaleRect = new RectF();
+    private final Rect mEraseStrokeRect = new Rect();
+    private final Paint mEraseStrokeRectPaint = new Paint();
 
     private PagedViewIconCache.Key mIconCacheKey;
     private PagedViewIconCache mIconCache;
@@ -81,8 +89,11 @@
         public void handleMessage(Message msg) {
             final PagedViewWidget widget = (PagedViewWidget) msg.obj;
             final int prevAlpha = widget.mPreview.getAlpha();
-            final Bitmap outline = Bitmap.createBitmap(widget.getWidth(), widget.getHeight(),
-                    Bitmap.Config.ARGB_8888);
+            final int width = Math.max(widget.mPreview.getIntrinsicWidth(),
+                    widget.getMeasuredWidth());
+            final int height = Math.max(widget.mPreview.getIntrinsicHeight(),
+                    widget.getMeasuredHeight());
+            final Bitmap outline = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
 
             widget.mHolographicOutlineCanvas.setBitmap(outline);
             widget.mHolographicOutlineCanvas.save();
@@ -94,6 +105,12 @@
             widget.mHolographicOutlineCanvas.drawColor(Color.argb(156, 0, 0, 0), Mode.SRC_OVER);
             widget.mHolographicOutlineCanvas.restore();
 
+            // To account for the fact that some previews run up straight to the edge (we subtract
+            // the edge from the holographic preview (before we apply the holograph)
+            widget.mEraseStrokeRect.set(0, 0, width, height);
+            widget.mHolographicOutlineCanvas.drawRect(widget.mEraseStrokeRect,
+                    widget.mEraseStrokeRectPaint);
+
             sHolographicOutlineHelper.applyThickExpensiveOutlineWithBlur(outline,
                     widget.mHolographicOutlineCanvas, widget.mHoloBlurColor,
                     widget.mHoloOutlineColor);
@@ -123,6 +140,11 @@
                 defStyle, 0);
         mHoloBlurColor = a.getColor(R.styleable.PagedViewWidget_blurColor, 0);
         mHoloOutlineColor = a.getColor(R.styleable.PagedViewWidget_outlineColor, 0);
+        mEraseStrokeRectPaint.setStyle(Paint.Style.STROKE);
+        mEraseStrokeRectPaint.setStrokeWidth(HolographicOutlineHelper.MIN_OUTER_BLUR_RADIUS);
+        mEraseStrokeRectPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
+        mEraseStrokeRectPaint.setFilterBitmap(true);
+        mEraseStrokeRectPaint.setAntiAlias(true);
         a.recycle();
 
         if (sHolographicOutlineHelper == null) {
@@ -158,6 +180,7 @@
         final ImageView image = (ImageView) findViewById(R.id.widget_preview);
         image.setMaxWidth(maxWidth);
         image.setImageDrawable(preview);
+        mPreviewImageView = image;
         final TextView name = (TextView) findViewById(R.id.widget_name);
         name.setText(info.label);
         name.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
@@ -179,6 +202,7 @@
         ImageView image = (ImageView) findViewById(R.id.wallpaper_preview);
         image.setMaxWidth(maxWidth);
         image.setImageDrawable(preview);
+        mPreviewImageView = image;
         TextView name = (TextView) findViewById(R.id.wallpaper_name);
         name.setText(info.loadLabel(packageManager));
         name.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
@@ -211,8 +235,15 @@
 
         // draw any blended overlays
         if (mHolographicOutline != null && mHolographicAlpha > 0) {
+            // Calculate how much to scale the holographic preview
+            mTmpScaleRect.set(0,0,1,1);
+            mPreviewImageView.getImageMatrix().mapRect(mTmpScaleRect);
+
             mPaint.setAlpha(mHolographicAlpha);
+            canvas.save();
+            canvas.scale(mTmpScaleRect.right, mTmpScaleRect.bottom);
             canvas.drawBitmap(mHolographicOutline, 0, 0, mPaint);
+            canvas.restore();
         }
     }
 
@@ -257,8 +288,7 @@
         sWorker.removeMessages(MESSAGE_CREATE_HOLOGRAPHIC_OUTLINE, this);
     }
 
-    @Override
-    public void setChecked(boolean checked) {
+    void setChecked(boolean checked, boolean animate) {
         if (mIsChecked != checked) {
             mIsChecked = checked;
 
@@ -276,15 +306,24 @@
             if (mCheckedAlphaAnimator != null) {
                 mCheckedAlphaAnimator.cancel();
             }
-            mCheckedAlphaAnimator = ObjectAnimator.ofFloat(this, "alpha", getAlpha(), alpha);
-            mCheckedAlphaAnimator.setDuration(duration);
-            mCheckedAlphaAnimator.start();
+            if (animate) {
+                mCheckedAlphaAnimator = ObjectAnimator.ofFloat(this, "alpha", getAlpha(), alpha);
+                mCheckedAlphaAnimator.setDuration(duration);
+                mCheckedAlphaAnimator.start();
+            } else {
+                setAlpha(alpha);
+            }
 
             invalidate();
         }
     }
 
     @Override
+    public void setChecked(boolean checked) {
+        setChecked(checked, true);
+    }
+
+    @Override
     public boolean isChecked() {
         return mIsChecked;
     }
diff --git a/src/com/android/launcher2/StrokedTextView.java b/src/com/android/launcher2/StrokedTextView.java
new file mode 100644
index 0000000..20f9f48
--- /dev/null
+++ b/src/com/android/launcher2/StrokedTextView.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+import com.android.launcher.R;
+
+/**
+ * This class adds a stroke to the generic TextView allowing the text to stand out better against
+ * the background (ie. in the AllApps button).
+ */
+public class StrokedTextView extends TextView {
+    private final Canvas mCanvas = new Canvas();
+    private final Paint mPaint = new Paint();
+    private Bitmap mCache;
+    private boolean mUpdateCachedBitmap;
+    private int mStrokeColor;
+    private float mStrokeWidth;
+    private int mTextColor;
+
+    public StrokedTextView(Context context) {
+        super(context);
+        init(context, null, 0);
+    }
+
+    public StrokedTextView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(context, attrs, 0);
+    }
+
+    public StrokedTextView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        init(context, attrs, defStyle);
+    }
+
+    private void init(Context context, AttributeSet attrs, int defStyle) {
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.StrokedTextView,
+                defStyle, 0);
+        mStrokeColor = a.getColor(R.styleable.StrokedTextView_strokeColor, 0xFF000000);
+        mStrokeWidth = a.getFloat(R.styleable.StrokedTextView_strokeWidth, 0.0f);
+        mTextColor = a.getColor(R.styleable.StrokedTextView_strokeTextColor, 0xFFFFFFFF);
+        a.recycle();
+        mUpdateCachedBitmap = true;
+
+        // Setup the text paint
+        mPaint.setAntiAlias(true);
+        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+    }
+
+    protected void onTextChanged(CharSequence text, int start, int before, int after) {
+        super.onTextChanged(text, start, before, after);
+        mUpdateCachedBitmap = true;
+    }
+
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        if (w > 0 && h > 0) {
+            mUpdateCachedBitmap = true;
+            mCache = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+        } else {
+            mCache = null;
+        }
+    }
+
+    protected void onDraw(Canvas canvas) {
+        if (mCache != null) {
+            if (mUpdateCachedBitmap) {
+                final int gap = getCompoundDrawablePadding();
+                final int w = getMeasuredWidth();
+                final int h = getMeasuredHeight();
+                final String text = getText().toString();
+                final Rect textBounds = new Rect();
+                final Paint textPaint = getPaint();
+                final int textWidth = (int) textPaint.measureText(text);
+                textPaint.getTextBounds("x", 0, 1, textBounds);
+
+                // Clear the old cached image
+                mCanvas.setBitmap(mCache);
+                mCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
+
+                // Draw the drawable
+                final int drawableLeft = getPaddingLeft();
+                final int drawableTop = getPaddingTop();
+                final Drawable[] drawables = getCompoundDrawables();
+                for (int i = 0; i < drawables.length; ++i) {
+                    if (drawables[i] != null) {
+                        drawables[i].setBounds(drawableLeft, drawableTop,
+                                drawableLeft + drawables[i].getIntrinsicWidth(),
+                                drawableTop + drawables[i].getIntrinsicHeight());
+                        drawables[i].draw(mCanvas);
+                    }
+                }
+
+                final int left = w - getPaddingRight() - textWidth;
+                final int bottom = (h + textBounds.height()) / 2;
+
+                // Draw the outline of the text
+                mPaint.setStrokeWidth(mStrokeWidth);
+                mPaint.setColor(mStrokeColor);
+                mPaint.setTextSize(getTextSize());
+                mCanvas.drawText(text, left, bottom, mPaint);
+
+                // Draw the text itself
+                mPaint.setStrokeWidth(0);
+                mPaint.setColor(mTextColor);
+                mCanvas.drawText(text, left, bottom, mPaint);
+
+                mUpdateCachedBitmap = false;
+            }
+            canvas.drawBitmap(mCache, 0, 0, mPaint);
+        } else {
+            super.onDraw(canvas);
+        }
+    }
+}
diff --git a/src/com/android/launcher2/UserFolder.java b/src/com/android/launcher2/UserFolder.java
index b362fbd..251b3f9 100644
--- a/src/com/android/launcher2/UserFolder.java
+++ b/src/com/android/launcher2/UserFolder.java
@@ -64,7 +64,7 @@
     }
 
     @Override
-    public void onDropCompleted(View target, boolean success) {
+    public void onDropCompleted(View target, Object dragInfo, boolean success) {
         if (success) {
             ShortcutsAdapter adapter = (ShortcutsAdapter)mContent.getAdapter();
             adapter.remove(mDragItem);
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 0daed37..e7865d2 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -23,7 +23,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.animation.Animator.AnimatorListener;
@@ -62,6 +61,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.DecelerateInterpolator;
+import android.widget.TabHost;
+import android.widget.TabWidget;
 import android.widget.TextView;
 import android.widget.Toast;
 
@@ -75,7 +76,8 @@
  * interact with. A workspace is meant to be used with a fixed width only.
  */
 public class Workspace extends SmoothPagedView
-        implements DropTarget, DragSource, DragScroller, View.OnTouchListener {
+        implements DropTarget, DragSource, DragScroller, View.OnTouchListener,
+        View.OnClickListener {
     @SuppressWarnings({"UnusedDeclaration"})
     private static final String TAG = "Launcher.Workspace";
 
@@ -108,10 +110,11 @@
     private float mChildrenOutlineAlpha = 0;
 
     // These properties refer to the background protection gradient used for AllApps and Customize
-    private ObjectAnimator mBackgroundFadeInAnimation;
-    private ObjectAnimator mBackgroundFadeOutAnimation;
+    private ValueAnimator mBackgroundFadeInAnimation;
+    private ValueAnimator mBackgroundFadeOutAnimation;
     private Drawable mBackground;
     private Drawable mCustomizeTrayBackground;
+    boolean mDrawBackground = true;
     private boolean mDrawCustomizeTrayBackground;
     private float mBackgroundAlpha = 0;
     private float mOverScrollMaxBackgroundAlpha = 0.0f;
@@ -123,6 +126,7 @@
     private float[] mCustomizationDrawerTransformedPos = new float[2];
 
     private final WallpaperManager mWallpaperManager;
+    private IBinder mWindowToken;
 
     private int mDefaultPage;
 
@@ -224,9 +228,6 @@
     final static float MAX_SWIPE_ANGLE = (float) Math.PI / 3;
     final static float TOUCH_SLOP_DAMPING_FACTOR = 4;
 
-    int mSpringLoadedDropX;
-    int mSpringLoadedDropY;
-
     /**
      * Used to inflate the Workspace from XML.
      *
@@ -265,6 +266,9 @@
         setHapticFeedbackEnabled(false);
 
         initWorkspace();
+
+        // Disable multitouch across the workspace/all apps/customize tray
+        setMotionEventSplittingEnabled(true);
     }
 
     /**
@@ -342,6 +346,8 @@
             throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
         }
         ((CellLayout) child).setOnInterceptTouchListener(this);
+        child.setOnClickListener(this);
+        child.setClickable(true);
         super.addView(child, index, params);
     }
 
@@ -351,6 +357,8 @@
             throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
         }
         ((CellLayout) child).setOnInterceptTouchListener(this);
+        child.setOnClickListener(this);
+        child.setClickable(true);
         super.addView(child);
     }
 
@@ -360,6 +368,8 @@
             throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
         }
         ((CellLayout) child).setOnInterceptTouchListener(this);
+        child.setOnClickListener(this);
+        child.setClickable(true);
         super.addView(child, index);
     }
 
@@ -369,6 +379,8 @@
             throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
         }
         ((CellLayout) child).setOnInterceptTouchListener(this);
+        child.setOnClickListener(this);
+        child.setClickable(true);
         super.addView(child, width, height);
     }
 
@@ -378,6 +390,8 @@
             throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
         }
         ((CellLayout) child).setOnInterceptTouchListener(this);
+        child.setOnClickListener(this);
+        child.setClickable(true);
         super.addView(child, params);
     }
 
@@ -418,8 +432,8 @@
         return folders;
     }
 
-    boolean isDefaultPageShowing() {
-        return mCurrentPage == mDefaultPage;
+    boolean isTouchActive() {
+        return mTouchState != TOUCH_STATE_REST;
     }
 
     /**
@@ -520,16 +534,25 @@
         return hitsPage(current + 1, x, y);
     }
 
+    /**
+     * Called directly from a CellLayout (not by the framework), after we've been added as a
+     * listener via setOnInterceptTouchEventListener(). This allows us to tell the CellLayout
+     * that it should intercept touch events, which is not something that is normally supported.
+     */
+    @Override
     public boolean onTouch(View v, MotionEvent event) {
-        // this is an intercepted event being forwarded from a cell layout
-        if (mIsSmall || mIsInUnshrinkAnimation) {
-            // Only allow clicks on a CellLayout if it is visible
-            if (mShrinkState != ShrinkState.BOTTOM_HIDDEN) {
-                mLauncher.onWorkspaceClick((CellLayout) v);
-            }
-            return true;
+        return (mIsSmall || mIsInUnshrinkAnimation);
+    }
+
+    /**
+     * Handle a click event on a CellLayout.
+     */
+    @Override
+    public void onClick(View cellLayout) {
+        // Only allow clicks on a CellLayout if it is shrunken and visible.
+        if ((mIsSmall || mIsInUnshrinkAnimation) && mShrinkState != ShrinkState.BOTTOM_HIDDEN) {
+            mLauncher.onWorkspaceClick((CellLayout) cellLayout);
         }
-        return false;
     }
 
     protected void onWindowVisibilityChanged (int visibility) {
@@ -553,8 +576,7 @@
         }
 
         if (mIsSmall || mIsInUnshrinkAnimation) {
-            if (mLauncher.isAllAppsVisible() &&
-                    mShrinkState == ShrinkState.BOTTOM_HIDDEN) {
+            if (mLauncher.isAllAppsVisible() && mShrinkState == ShrinkState.BOTTOM_HIDDEN) {
                 // Intercept this event so we can show the workspace in full view
                 // when it is clicked on and it is small
                 AllAppsPagedView allApps = (AllAppsPagedView)
@@ -689,7 +711,11 @@
         // parallax effects
         mWallpaperWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim));
         mWallpaperHeight = (int)(maxDim * wallpaperTravelToScreenHeightRatio(maxDim, minDim));
-        mWallpaperManager.suggestDesiredDimensions(mWallpaperWidth, mWallpaperHeight);
+        new Thread("setWallpaperDimension") {
+            public void run() {
+                mWallpaperManager.suggestDesiredDimensions(mWallpaperWidth, mWallpaperHeight);
+            }
+        }.start();
     }
 
     public void setVerticalWallpaperOffset(float offset) {
@@ -707,11 +733,15 @@
 
     private float wallpaperOffsetForCurrentScroll() {
         Display display = mLauncher.getWindowManager().getDefaultDisplay();
+        final boolean isStaticWallpaper = (mWallpaperManager.getWallpaperInfo() == null);
         // The wallpaper travel width is how far, from left to right, the wallpaper will move
         // at this orientation (for example, in portrait mode we don't move all the way to the
         // edges of the wallpaper, or otherwise the parallax effect would be too strong)
         int wallpaperTravelWidth = (int) (display.getWidth() *
                 wallpaperTravelToScreenWidthRatio(display.getWidth(), display.getHeight()));
+        if (!isStaticWallpaper) {
+            wallpaperTravelWidth = mWallpaperWidth;
+        }
 
         // Set wallpaper offset steps (1 / (number of screens - 1))
         // We have 3 vertical offset states (centered, and then top/bottom aligned
@@ -725,7 +755,6 @@
         // you overscroll as far as you can in landscape mode. Only do this for static wallpapers
         // because live wallpapers (and probably 3rd party wallpaper providers) rely on the offset
         // being even intervals from 0 to 1 (eg [0, 0.25, 0.5, 0.75, 1])
-        final boolean isStaticWallpaper = (mWallpaperManager.getWallpaperInfo() == null);
         if (isStaticWallpaper) {
             int overscrollOffset = (int) (maxOverScroll() * display.getWidth());
             scrollProgressOffset += overscrollOffset / (float) getScrollRange();
@@ -735,7 +764,7 @@
         float scrollProgress =
             mScrollX / (float) scrollRange + scrollProgressOffset;
         float offsetInDips = wallpaperTravelWidth * scrollProgress +
-            (mWallpaperWidth - wallpaperTravelWidth) / 2;
+            (mWallpaperWidth - wallpaperTravelWidth) / 2; // center it
         float offset = offsetInDips / (float) mWallpaperWidth;
         return offset;
     }
@@ -761,14 +790,13 @@
             updateNow = keepUpdating = mWallpaperOffset.computeScrollOffset();
         }
         if (updateNow) {
-            IBinder token = getWindowToken();
-            if (token != null) {
-                mWallpaperManager.setWallpaperOffsets(getWindowToken(),
+            if (mWindowToken != null) {
+                mWallpaperManager.setWallpaperOffsets(mWindowToken,
                         mWallpaperOffset.getCurrX(), mWallpaperOffset.getCurrY());
             }
         }
         if (keepUpdating) {
-            invalidate();
+            fastInvalidate();
         }
     }
 
@@ -891,7 +919,7 @@
         }
     }
 
-    public void showOutlines() {
+    void showOutlines() {
         if (!mIsSmall && !mIsInUnshrinkAnimation) {
             if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
             if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
@@ -901,7 +929,7 @@
         }
     }
 
-    public void hideOutlines() {
+    void hideOutlines() {
         if (!mIsSmall && !mIsInUnshrinkAnimation) {
             if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
             if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
@@ -912,6 +940,12 @@
         }
     }
 
+    public void showOutlinesTemporarily() {
+        if (!mIsPageMoving && !isTouchActive()) {
+            snapToPage(mCurrentPage);
+        }
+    }
+
     public void setChildrenOutlineAlpha(float alpha) {
         mChildrenOutlineAlpha = alpha;
         for (int i = 0; i < getChildCount(); i++) {
@@ -924,6 +958,13 @@
         return mChildrenOutlineAlpha;
     }
 
+    void disableBackground() {
+        mDrawBackground = false;
+    }
+    void enableBackground() {
+        mDrawBackground = true;
+    }
+
     private void showBackgroundGradientForAllApps() {
         showBackgroundGradient();
         mDrawCustomizeTrayBackground = false;
@@ -938,7 +979,12 @@
         if (mBackground == null) return;
         if (mBackgroundFadeOutAnimation != null) mBackgroundFadeOutAnimation.cancel();
         if (mBackgroundFadeInAnimation != null) mBackgroundFadeInAnimation.cancel();
-        mBackgroundFadeInAnimation = ObjectAnimator.ofFloat(this, "backgroundAlpha", 1.0f);
+        mBackgroundFadeInAnimation = ValueAnimator.ofFloat(getBackgroundAlpha(), 1f);
+        mBackgroundFadeInAnimation.addUpdateListener(new AnimatorUpdateListener() {
+            public void onAnimationUpdate(ValueAnimator animation) {
+                setBackgroundAlpha(((Float) animation.getAnimatedValue()).floatValue());
+            }
+        });
         mBackgroundFadeInAnimation.setInterpolator(new DecelerateInterpolator(1.5f));
         mBackgroundFadeInAnimation.setDuration(BACKGROUND_FADE_IN_DURATION);
         mBackgroundFadeInAnimation.start();
@@ -948,15 +994,22 @@
         if (mBackground == null) return;
         if (mBackgroundFadeInAnimation != null) mBackgroundFadeInAnimation.cancel();
         if (mBackgroundFadeOutAnimation != null) mBackgroundFadeOutAnimation.cancel();
-        mBackgroundFadeOutAnimation = ObjectAnimator.ofFloat(this, "backgroundAlpha", 0.0f);
+        mBackgroundFadeOutAnimation = ValueAnimator.ofFloat(getBackgroundAlpha(), 0f);
+        mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() {
+            public void onAnimationUpdate(ValueAnimator animation) {
+                setBackgroundAlpha(((Float) animation.getAnimatedValue()).floatValue());
+            }
+        });
         mBackgroundFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5f));
         mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION);
         mBackgroundFadeOutAnimation.start();
     }
 
     public void setBackgroundAlpha(float alpha) {
-        mBackgroundAlpha = alpha;
-        invalidate();
+        if (alpha != mBackgroundAlpha) {
+            mBackgroundAlpha = alpha;
+            invalidate();
+        }
     }
 
     public float getBackgroundAlpha() {
@@ -1050,8 +1103,13 @@
 
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
+        mWindowToken = getWindowToken();
         computeScroll();
-        mDragController.setWindowToken(getWindowToken());
+        mDragController.setWindowToken(mWindowToken);
+    }
+
+    protected void onDetachedFromWindow() {
+        mWindowToken = null;
     }
 
     @Override
@@ -1086,7 +1144,7 @@
         updateWallpaperOffsets();
 
         // Draw the background gradient if necessary
-        if (mBackground != null && mBackgroundAlpha > 0.0f) {
+        if (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground) {
             int alpha = (int) (mBackgroundAlpha * 255);
             if (mDrawCustomizeTrayBackground) {
                 // Find out where to offset the gradient for the customization tray content
@@ -1126,9 +1184,11 @@
             final int pageCount = getChildCount();
             final long drawingTime = getDrawingTime();
             for (int i = 0; i < pageCount; i++) {
-                final View page = (View) getChildAt(i);
-
-                drawChild(canvas, page, drawingTime);
+                final CellLayout page = (CellLayout) getChildAt(i);
+                if (page.getVisibility() == VISIBLE
+                        && (page.getAlpha() != 0f || page.getBackgroundAlpha() != 0f)) {
+                    drawChild(canvas, page, drawingTime);
+                }
             }
         } else {
             super.dispatchDraw(canvas);
@@ -1317,6 +1377,19 @@
         shrink(shrinkState, true);
     }
 
+    private int getCustomizeDrawerHeight() {
+        TabHost customizationDrawer = mLauncher.getCustomizationDrawer();
+        int height = customizationDrawer.getHeight();
+        TabWidget tabWidget = (TabWidget)
+            customizationDrawer.findViewById(com.android.internal.R.id.tabs);
+        if (tabWidget.getTabCount() > 0) {
+            TextView tabText = (TextView) tabWidget.getChildTabViewAt(0);
+            // subtract the empty space above the tab text
+            height -= ((tabWidget.getHeight() - tabText.getLineHeight())) / 2;
+        }
+        return height;
+    }
+
     // we use this to shrink the workspace for the all apps view and the customize view
     public void shrink(ShrinkState shrinkState, boolean animated) {
         // In the launcher interaction model, we're never in the state where we're shrunken and
@@ -1393,9 +1466,7 @@
             y = screenHeight / 2 - scaledPageHeight / 2;
             finalAlpha = 1.0f;
         } else if (shrinkState == ShrinkState.TOP) {
-            y = (isPortrait ?
-                getResources().getDimension(R.dimen.customizeSmallScreenVerticalMarginPortrait) :
-                getResources().getDimension(R.dimen.customizeSmallScreenVerticalMarginLandscape));
+            y = (screenHeight - getCustomizeDrawerHeight() - scaledPageHeight) / 2;
         }
 
         int duration;
@@ -1446,6 +1517,11 @@
 
             oldAlphas[i] = cl.getAlpha();
             newAlphas[i] = finalAlpha;
+            if (animated && (oldAlphas[i] != 0f || newAlphas[i] != 0f)) {
+                // if the CellLayout will be visible during the animation, force building its
+                // hardware layer immediately so we don't see a blip later in the animation
+                cl.buildChildrenLayer();
+            }
             if (animated) {
                 oldXs[i] = cl.getX();
                 oldYs[i] = cl.getY();
@@ -1517,9 +1593,13 @@
             final float newVerticalWallpaperOffset = wallpaperOffset;
             animWithInterpolator.addUpdateListener(new AnimatorUpdateListener() {
                 public void onAnimationUpdate(ValueAnimator animation) {
-                    fastInvalidate();
                     final float b = (Float) animation.getAnimatedValue();
                     final float a = 1f - b;
+                    if (b == 0f) {
+                        // an optimization, and required for correct behavior.
+                        return;
+                    }
+                    fastInvalidate();
                     setHorizontalWallpaperOffset(
                             a * oldHorizontalWallpaperOffset + b * newHorizontalWallpaperOffset);
                     setVerticalWallpaperOffset(
@@ -1719,6 +1799,11 @@
         }
     }
 
+    public void exitWidgetResizeMode() {
+        final CellLayout currentLayout = (CellLayout) getChildAt(getCurrentPage());
+        currentLayout.getChildrenLayout().clearAllResizeFrames();
+    }
+
     void unshrink(boolean animated) {
         unshrink(animated, false);
     }
@@ -1847,9 +1932,13 @@
                 final float newVerticalWallpaperOffset = 0.5f;
                 animWithInterpolator.addUpdateListener(new AnimatorUpdateListener() {
                     public void onAnimationUpdate(ValueAnimator animation) {
-                        fastInvalidate();
                         final float b = (Float) animation.getAnimatedValue();
                         final float a = 1f - b;
+                        if (b == 0f) {
+                            // an optimization, but not required
+                            return;
+                        }
+                        fastInvalidate();
                         setHorizontalWallpaperOffset(
                                 a * oldHorizontalWallpaperOffset + b * newHorizontalWallpaperOffset);
                         setVerticalWallpaperOffset(
@@ -1880,6 +1969,10 @@
                         // don't invalidate workspace because we did it above
                         final float b = (Float) animation.getAnimatedValue();
                         final float a = 1f - b;
+                        if (b == 0f) {
+                            // an optimization, but not required
+                            return;
+                        }
                         for (int i = 0; i < screenCount; i++) {
                             final CellLayout cl = (CellLayout) getChildAt(i);
                             cl.setFastRotationY(a * oldRotationYs[i] + b * newRotationYs[i]);
@@ -2051,8 +2144,8 @@
         final int screenX = (int) mTempXY[0] + (child.getWidth() - bmpWidth) / 2;
         final int screenY = (int) mTempXY[1] + (child.getHeight() - bmpHeight) / 2;
         mLauncher.lockScreenOrientation();
-        mDragController.startDrag(b, screenX, screenY, 0, 0, bmpWidth, bmpHeight, this,
-                child.getTag(), DragController.DRAG_ACTION_MOVE, null);
+        mDragController.startDrag(
+                b, screenX, screenY, this, child.getTag(), DragController.DRAG_ACTION_MOVE);
         b.recycle();
     }
 
@@ -2180,9 +2273,9 @@
 
     public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
             DragView dragView, Object dragInfo) {
-
-        int originX = x - xOffset;
-        int originY = y - yOffset;
+        boolean largeOrSpringLoaded = !mIsSmall || mWasSpringLoadedOnDragExit;
+        int originX = largeOrSpringLoaded ? x - xOffset : x - xOffset + dragView.getWidth() / 2;
+        int originY = largeOrSpringLoaded ? y - yOffset : y - yOffset + dragView.getHeight() / 2;
 
         if (mIsSmall || mIsInUnshrinkAnimation) {
             // get originX and originY in the local coordinate system of the screen
@@ -2191,6 +2284,10 @@
             mapPointFromSelfToChild(mDragTargetLayout, mTempOriginXY);
             originX = (int)mTempOriginXY[0];
             originY = (int)mTempOriginXY[1];
+            if (!largeOrSpringLoaded) {
+               originX -= mDragTargetLayout.getCellWidth() / 2;
+               originY -= mDragTargetLayout.getCellHeight() / 2;
+            }
         }
 
         // When you are in customization mode and drag to a particular screen, make that the
@@ -2203,13 +2300,14 @@
         }
 
         if (source != this) {
-            if (!mIsSmall || mWasSpringLoadedOnDragExit) {
-                onDropExternal(originX, originY, dragInfo, mDragTargetLayout, false);
-            } else {
-                // if we drag and drop to small screens, don't pass the touch x/y coords (when we
-                // enable spring-loaded adding, however, we do want to pass the touch x/y coords)
-                onDropExternal(-1, -1, dragInfo, mDragTargetLayout, false);
+            final int[] touchXY = new int[] { originX, originY };
+            if ((mIsSmall || mIsInUnshrinkAnimation) && !mLauncher.isAllAppsVisible()) {
+                // When the workspace is shrunk and the drop comes from customize, don't actually
+                // add the item to the screen -- customize will do this itself
+                ((ItemInfo) dragInfo).dropPos = touchXY;
+                return;
             }
+            onDropExternal(touchXY, dragInfo, mDragTargetLayout, false);
         } else if (mDragInfo != null) {
             final View cell = mDragInfo.cell;
             CellLayout dropTargetLayout = mDragTargetLayout;
@@ -2254,6 +2352,24 @@
                     cell.setId(LauncherModel.getCellLayoutChildId(-1, mDragInfo.screen,
                             mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY));
 
+                    if (cell instanceof LauncherAppWidgetHostView) {
+                        final CellLayoutChildren children = dropTargetLayout.getChildrenLayout();
+                        final CellLayout cellLayout = dropTargetLayout;
+                        // We post this call so that the widget has a chance to be placed
+                        // in its final location
+
+                        final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) cell;
+                        AppWidgetProviderInfo pinfo = hostView.getAppWidgetInfo();
+                        if (pinfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) {
+                            post(new Runnable() {
+                                public void run() {
+                                    children.addResizeFrame(info, hostView, 
+                                            cellLayout);
+                                }
+                            });
+                        }
+                    }
+
                     LauncherModel.moveItemInDatabase(mLauncher, info,
                             LauncherSettings.Favorites.CONTAINER_DESKTOP, screen,
                             lp.cellX, lp.cellY);
@@ -2292,7 +2408,7 @@
         // would land in a cell occupied by a DragTarget (e.g. a Folder),
         // then drag events should be handled by that child.
 
-        ItemInfo item = (ItemInfo)dragInfo;
+        ItemInfo item = (ItemInfo) dragInfo;
         CellLayout currentLayout = getCurrentDropLayout();
 
         int dragPointX, dragPointY;
@@ -2418,7 +2534,7 @@
                 if (isShortcut) {
                     final Intent intent = data.getItemAt(index).getIntent();
                     Object info = model.infoFromShortcutIntent(mContext, intent, data.getIcon());
-                    onDropExternal(x, y, info, layout, false);
+                    onDropExternal(new int[] { x, y }, info, layout, false);
                 } else {
                     if (widgets.size() == 1) {
                         // If there is only one item, then go ahead and add and configure
@@ -2622,7 +2738,13 @@
                         mSpringLoadedDragController.onDragExit();
                     }
                     mDragTargetLayout = layout;
-                    if (mDragTargetLayout != null && mDragTargetLayout.getAcceptsDrops()) {
+                    // In spring-loaded mode, we still want the user to be able to hover over a
+                    // full screen (which is traditionally set to not accept drops) if they want to
+                    // get to pages beyond the screen that is full.
+                    boolean allowDragOver = (mDragTargetLayout != null) &&
+                            (mDragTargetLayout.getAcceptsDrops() ||
+                                    (mShrinkState == ShrinkState.SPRING_LOADED));
+                    if (allowDragOver) {
                         mDragTargetLayout.setIsDragOverlapping(true);
                         mSpringLoadedDragController.onDragEnter(
                                 mDragTargetLayout, mShrinkState == ShrinkState.SPRING_LOADED);
@@ -2681,8 +2803,6 @@
                     final View child = (mDragInfo == null) ? null : mDragInfo.cell;
                     float[] localOrigin = { originX, originY };
                     mapPointFromSelfToChild(mDragTargetLayout, localOrigin, null);
-                    mSpringLoadedDropX = (int) localOrigin[0];
-                    mSpringLoadedDropY = (int) localOrigin[1];
                     mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
                             (int) localOrigin[0], (int) localOrigin[1], item.spanX, item.spanY);
                 }
@@ -2723,7 +2843,7 @@
      */
     public boolean addExternalItemToScreen(ItemInfo dragInfo, CellLayout layout) {
         if (layout.findCellForSpan(mTempEstimate, dragInfo.spanX, dragInfo.spanY)) {
-            onDropExternal(-1, -1, (ItemInfo) dragInfo, (CellLayout) layout, false);
+            onDropExternal(dragInfo.dropPos, (ItemInfo) dragInfo, (CellLayout) layout, false);
             return true;
         }
         mLauncher.showOutOfSpaceMessage();
@@ -2738,17 +2858,13 @@
      * NOTE: This can also be called when we are outside of a drag event, when we want
      * to add an item to one of the workspace screens.
      */
-    private void onDropExternal(int x, int y, Object dragInfo,
+    private void onDropExternal(int[] touchXY, Object dragInfo,
             CellLayout cellLayout, boolean insertAtFirst) {
         int screen = indexOfChild(cellLayout);
         if (dragInfo instanceof PendingAddItemInfo) {
             PendingAddItemInfo info = (PendingAddItemInfo) dragInfo;
             // When dragging and dropping from customization tray, we deal with creating
             // widgets/shortcuts/folders in a slightly different way
-            // Only set touchXY if you are supporting spring loaded adding of items
-            int[] touchXY = new int[2];
-            touchXY[0] = mSpringLoadedDropX;
-            touchXY[1] = mSpringLoadedDropY;
             switch (info.itemType) {
                 case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
                     mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) info, screen, touchXY);
@@ -2787,14 +2903,9 @@
             }
 
             mTargetCell = new int[2];
-            if (x != -1 && y != -1) {
+            if (touchXY != null) {
                 // when dragging and dropping, just find the closest free spot
-
-                // When we get a drop in Spring Loaded mode, at this point we've already called
-                // onDragExit, which starts us shrinking again and screws up the transforms we
-                // need to get the right value. Instead, as a temporary solution, we've saved the
-                // proper point, mSpringLoadedDropX/Y, from the last onDragOver
-                cellLayout.findNearestVacantArea(mSpringLoadedDropX, mSpringLoadedDropY, 1, 1, mTargetCell);
+                cellLayout.findNearestVacantArea(touchXY[0], touchXY[1], 1, 1, mTargetCell);
             } else {
                 cellLayout.findCellForSpan(mTargetCell, 1, 1);
             }
@@ -2815,11 +2926,8 @@
      * Return the current {@link CellLayout}, correctly picking the destination
      * screen while a scroll is in progress.
      */
-    private CellLayout getCurrentDropLayout() {
-        // if we're currently small, use findMatchingPageForDragOver instead
-        if (mIsSmall) return null;
-        int index = mScroller.isFinished() ? mCurrentPage : mNextPage;
-        return (CellLayout) getChildAt(index);
+    public CellLayout getCurrentDropLayout() {
+        return (CellLayout) getChildAt(mNextPage == INVALID_PAGE ? mCurrentPage : mNextPage);
     }
 
     /**
@@ -2864,7 +2972,7 @@
     /**
      * Called at the end of a drag which originated on the workspace.
      */
-    public void onDropCompleted(View target, boolean success) {
+    public void onDropCompleted(View target, Object dragInfo, boolean success) {
         if (success) {
             if (target != this && mDragInfo != null) {
                 final CellLayout cellLayout = (CellLayout) getChildAt(mDragInfo.screen);
@@ -2931,6 +3039,10 @@
                     mDragTargetLayout.onDragExit();
                     mDragTargetLayout = null;
                 }
+                // In portrait, need to redraw the edge glow when entering the scroll area
+                if (getHeight() > getWidth()) {
+                    invalidate();
+                }
             }
         }
     }
@@ -2941,6 +3053,12 @@
             ((CellLayout) getChildAt(i)).setIsDragOverlapping(false);
         }
         mSpringLoadedDragController.onDragExit();
+
+        // In portrait, workspace is responsible for drawing the edge glow on adjacent pages,
+        // so we need to redraw the workspace when this may have changed.
+        if (getHeight() > getWidth()) {
+            invalidate();
+        }
     }
 
     @Override