Merge "Little fix for folders"
diff --git a/res/layout/apps_customize_application.xml b/res/layout-land/apps_customize_application.xml
similarity index 95%
copy from res/layout/apps_customize_application.xml
copy to res/layout-land/apps_customize_application.xml
index 37a8df7..bface6b 100644
--- a/res/layout/apps_customize_application.xml
+++ b/res/layout-land/apps_customize_application.xml
@@ -18,7 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
 
-    style="@style/WorkspaceIcon.AppsCustomize"
+    style="@style/WorkspaceIcon.Landscape.AppsCustomize"
 
     android:id="@+id/application_icon"
     android:layout_width="match_parent"
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index c120de8..4aa4870 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -31,7 +31,8 @@
         android:fadeScrollbars="true"
         launcher:defaultScreen="2"
         launcher:cellCountX="4"
-        launcher:cellCountY="4">
+        launcher:cellCountY="4"
+        launcher:pageSpacing="@dimen/workspace_page_spacing">
 
         <include android:id="@+id/cell1" layout="@layout/workspace_screen" />
         <include android:id="@+id/cell2" layout="@layout/workspace_screen" />
diff --git a/res/layout-large-port/workspace.xml b/res/layout-large-port/workspace.xml
deleted file mode 100644
index ccd7d33..0000000
--- a/res/layout-large-port/workspace.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<!-- The workspace contains 5 screens of cells -->
-<com.android.launcher2.Workspace
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
-    android:paddingTop="?android:attr/actionBarSize"
-    android:paddingBottom="10dp"
-    launcher:defaultScreen="2"
-    launcher:pageSpacing="@dimen/workspace_page_spacing_port">
-      <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>
\ No newline at end of file
diff --git a/res/layout-large/tab_widget_indicator.xml b/res/layout-large/tab_widget_indicator.xml
deleted file mode 100644
index c09c853..0000000
--- a/res/layout-large/tab_widget_indicator.xml
+++ /dev/null
@@ -1,19 +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.AccessibleTabView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TabIndicator.Wide" />
diff --git a/res/layout-large-land/workspace.xml b/res/layout-large/workspace.xml
similarity index 95%
rename from res/layout-large-land/workspace.xml
rename to res/layout-large/workspace.xml
index e8ea782..abed5a8 100644
--- a/res/layout-large-land/workspace.xml
+++ b/res/layout-large/workspace.xml
@@ -21,7 +21,7 @@
     android:paddingTop="?android:attr/actionBarSize"
     android:paddingBottom="10dp"
     launcher:defaultScreen="2"
-    launcher:pageSpacing="@dimen/workspace_page_spacing_land">
+    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" />
diff --git a/res/layout/apps_customize_application.xml b/res/layout-port/apps_customize_application.xml
similarity index 95%
rename from res/layout/apps_customize_application.xml
rename to res/layout-port/apps_customize_application.xml
index 37a8df7..37b4185 100644
--- a/res/layout/apps_customize_application.xml
+++ b/res/layout-port/apps_customize_application.xml
@@ -18,7 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
 
-    style="@style/WorkspaceIcon.AppsCustomize"
+    style="@style/WorkspaceIcon.Portrait.AppsCustomize"
 
     android:id="@+id/application_icon"
     android:layout_width="match_parent"
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index db074d7..73051ba 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -29,7 +29,8 @@
         android:layout_height="match_parent"
         launcher:defaultScreen="2"
         launcher:cellCountX="4"
-        launcher:cellCountY="4">
+        launcher:cellCountY="4"
+        launcher:pageSpacing="@dimen/workspace_page_spacing">
 
         <include android:id="@+id/cell1" layout="@layout/workspace_screen" />
         <include android:id="@+id/cell2" layout="@layout/workspace_screen" />
diff --git a/res/layout/apps_customize_pane.xml b/res/layout/apps_customize_pane.xml
index 00c87cb..adb0a6d 100644
--- a/res/layout/apps_customize_pane.xml
+++ b/res/layout/apps_customize_pane.xml
@@ -25,7 +25,7 @@
         <FrameLayout
             android:id="@+id/tabs_container"
             android:layout_width="wrap_content"
-            android:layout_height="@dimen/qsb_bar_height"
+            android:layout_height="@dimen/apps_customize_tab_bar_height"
             android:layout_gravity="center_horizontal">
             <com.android.launcher2.FocusOnlyTabWidget
                 android:id="@android:id/tabs"
@@ -64,14 +64,14 @@
                 android:id="@+id/apps_customize_pane_content"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
-                launcher:cellCountX="@integer/all_apps_view_cellCountX"
-                launcher:cellCountY="@integer/all_apps_view_cellCountY"
-                launcher:pageLayoutWidthGap="@dimen/all_apps_view_pageLayoutWidthGap"
-                launcher:pageLayoutHeightGap="@dimen/all_apps_view_pageLayoutHeightGap"
-                launcher:pageLayoutPaddingTop="@dimen/all_apps_view_pageLayoutPaddingTop"
-                launcher:pageLayoutPaddingBottom="@dimen/all_apps_view_pageLayoutPaddingBottom"
-                launcher:pageLayoutPaddingLeft="@dimen/all_apps_view_pageLayoutPaddingLeft"
-                launcher:pageLayoutPaddingRight="@dimen/all_apps_view_pageLayoutPaddingRight"
+                launcher:cellCountX="@integer/apps_customize_cellCountX"
+                launcher:cellCountY="@integer/apps_customize_cellCountY"
+                launcher:pageLayoutWidthGap="@dimen/apps_customize_pageLayoutWidthGap"
+                launcher:pageLayoutHeightGap="@dimen/apps_customize_pageLayoutHeightGap"
+                launcher:pageLayoutPaddingTop="@dimen/apps_customize_pageLayoutPaddingTop"
+                launcher:pageLayoutPaddingBottom="@dimen/apps_customize_pageLayoutPaddingBottom"
+                launcher:pageLayoutPaddingLeft="@dimen/apps_customize_pageLayoutPaddingLeft"
+                launcher:pageLayoutPaddingRight="@dimen/apps_customize_pageLayoutPaddingRight"
                 launcher:widgetCellWidthGap="@dimen/apps_customize_widget_cell_width_gap"
                 launcher:widgetCellHeightGap="@dimen/apps_customize_widget_cell_height_gap"
                 launcher:widgetCountX="@integer/apps_customize_widget_cell_count_x"
diff --git a/res/layout/tab_widget_indicator.xml b/res/layout/tab_widget_indicator.xml
index b3694fe..df43d3d 100644
--- a/res/layout/tab_widget_indicator.xml
+++ b/res/layout/tab_widget_indicator.xml
@@ -16,4 +16,4 @@
 
 <com.android.launcher2.AccessibleTabView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TabIndicator" />
+    style="@style/TabIndicator.AppsCustomize" />
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 278da54..463cd17 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -24,21 +24,25 @@
     <dimen name="workspace_right_padding">@dimen/button_bar_height</dimen>
     <dimen name="workspace_top_padding">0dp</dimen>
     <dimen name="workspace_bottom_padding">0dp</dimen>
+    <dimen name="workspace_page_spacing">8dp</dimen>
 
     <dimen name="folder_cell_width">100dip</dimen>
     <dimen name="folder_cell_height">74dip</dimen>
     <dimen name="button_bar_height">62dip</dimen>
 
-    <integer name="all_apps_view_cellCountX">6</integer>
-    <integer name="all_apps_view_cellCountY">3</integer>
-    <dimen name="all_apps_view_pageLayoutWidthGap">-1dp</dimen>
-    <dimen name="all_apps_view_pageLayoutHeightGap">-1dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingTop">5dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingBottom">5dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingLeft">5dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingRight">5dp</dimen>
-
 <!-- AppsCustomize -->
+    <dimen name="apps_customize_cell_width">80dp</dimen>
+    <!-- The width can be 76dp because we don't have B padding -->
+    <dimen name="apps_customize_cell_height">76dp</dimen>
+    <integer name="apps_customize_cellCountX">6</integer>
+    <integer name="apps_customize_cellCountY">3</integer>
+    <dimen name="apps_customize_pageLayoutWidthGap">-1dp</dimen>
+    <dimen name="apps_customize_pageLayoutHeightGap">-1dp</dimen>
+    <dimen name="apps_customize_pageLayoutPaddingTop">5dp</dimen>
+    <dimen name="apps_customize_pageLayoutPaddingBottom">5dp</dimen>
+    <dimen name="apps_customize_pageLayoutPaddingLeft">5dp</dimen>
+    <dimen name="apps_customize_pageLayoutPaddingRight">5dp</dimen>
+    <dimen name="apps_customize_tab_bar_height">42dp</dimen>
     <dimen name="apps_customize_widget_cell_width_gap">30dp</dimen>
     <dimen name="apps_customize_widget_cell_height_gap">5dp</dimen>
     <integer name="apps_customize_widget_cell_count_x">3</integer>
diff --git a/res/values-land/styles.xml b/res/values-land/styles.xml
index 659947b..e8d767c 100644
--- a/res/values-land/styles.xml
+++ b/res/values-land/styles.xml
@@ -51,6 +51,11 @@
         <item name="android:paddingRight">@dimen/toolbar_button_horizontal_padding</item>
     </style>
 
+    <style name="TabIndicator.AppsCustomize">
+        <item name="android:paddingTop">5dp</item>
+        <item name="android:paddingBottom">10dp</item>
+    </style>
+
     <style name="HotseatButton">
         <item name="android:paddingTop">12dip</item>
         <item name="android:paddingBottom">12dip</item>
diff --git a/res/values-large-land/dimens.xml b/res/values-large-land/dimens.xml
index ee4c70b..d14a8df 100644
--- a/res/values-large-land/dimens.xml
+++ b/res/values-large-land/dimens.xml
@@ -22,15 +22,16 @@
     <dimen name="workspace_bottom_padding">15dip</dimen>
     <dimen name="workspace_width_gap">32dp</dimen>
     <dimen name="workspace_height_gap">2dp</dimen>
+    <dimen name="workspace_page_spacing">50dp</dimen>
 
     <!-- the area at the edge of the screen that makes the workspace go left
          or right while you're dragging. -->
     <dimen name="scroll_zone">100dip</dimen>
 
-    <dimen name="all_apps_view_pageLayoutWidthGap">28dp</dimen>
-    <dimen name="all_apps_view_pageLayoutHeightGap">8dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingTop">20dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingBottom">14dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingLeft">40dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingRight">40dp</dimen>
+    <dimen name="apps_customize_pageLayoutWidthGap">28dp</dimen>
+    <dimen name="apps_customize_pageLayoutHeightGap">8dp</dimen>
+    <dimen name="apps_customize_pageLayoutPaddingTop">20dp</dimen>
+    <dimen name="apps_customize_pageLayoutPaddingBottom">14dp</dimen>
+    <dimen name="apps_customize_pageLayoutPaddingLeft">40dp</dimen>
+    <dimen name="apps_customize_pageLayoutPaddingRight">40dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/res/values-large-port/dimens.xml b/res/values-large-port/dimens.xml
index c1525ea..e0651b2 100644
--- a/res/values-large-port/dimens.xml
+++ b/res/values-large-port/dimens.xml
@@ -22,6 +22,7 @@
          calculating the number of columns to fit a page.
          In portrait/large we use apps_customize_cell_width / 8. -->
     <dimen name="apps_customize_peek_width">12dp</dimen>
+    <dimen name="workspace_page_spacing">64dp</dimen>
 
 <!-- Workspace -->
     <!-- the area at the edge of the screen that makes the workspace go left
@@ -35,10 +36,10 @@
     <dimen name="workspace_width_gap">0dp</dimen>
     <dimen name="workspace_height_gap">32dp</dimen>
 
-    <dimen name="all_apps_view_pageLayoutWidthGap">24dp</dimen>
-    <dimen name="all_apps_view_pageLayoutHeightGap">36dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingTop">25dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingBottom">10dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingLeft">20dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingRight">20dp</dimen>
+    <dimen name="apps_customize_pageLayoutWidthGap">24dp</dimen>
+    <dimen name="apps_customize_pageLayoutHeightGap">36dp</dimen>
+    <dimen name="apps_customize_pageLayoutPaddingTop">25dp</dimen>
+    <dimen name="apps_customize_pageLayoutPaddingBottom">10dp</dimen>
+    <dimen name="apps_customize_pageLayoutPaddingLeft">20dp</dimen>
+    <dimen name="apps_customize_pageLayoutPaddingRight">20dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/res/values-large/dimens.xml b/res/values-large/dimens.xml
index 7da10db..59aaa41 100644
--- a/res/values-large/dimens.xml
+++ b/res/values-large/dimens.xml
@@ -25,10 +25,8 @@
     <dimen name="workspace_cell_width">96dip</dimen>
     <dimen name="workspace_cell_height">96dip</dimen>
 
-    <dimen name="workspace_page_spacing_land">50dp</dimen>
-    <dimen name="workspace_page_spacing_port">64dp</dimen>
-
 <!-- AppsCustomize -->
+    <dimen name="apps_customize_tab_bar_height">56dp</dimen>
     <dimen name="apps_customize_cell_width">96dp</dimen>
     <dimen name="apps_customize_cell_height">96dp</dimen>
     <!-- The amount of space to account for the next/prev pages when
diff --git a/res/values-large/styles.xml b/res/values-large/styles.xml
index 25b8195..bd4efe7 100644
--- a/res/values-large/styles.xml
+++ b/res/values-large/styles.xml
@@ -77,7 +77,7 @@
         <item name="android:screenOrientation">unspecified</item>
     </style>
 
-    <style name="TabIndicator.Wide">
+    <style name="TabIndicator.AppsCustomize">
         <item name="android:paddingLeft">40dp</item>
         <item name="android:paddingRight">40dp</item>
         <item name="android:paddingTop">10dp</item>
@@ -115,5 +115,9 @@
         <item name="android:drawablePadding">7.5dp</item>
         <item name="android:textColor">#FFFFFFFF</item>
         <item name="android:textSize">16sp</item>
+        <item name="android:shadowColor">#393939</item>
+        <item name="android:shadowDx">0.0</item>
+        <item name="android:shadowDy">0.0</item>
+        <item name="android:shadowRadius">2.0</item>
     </style>
 </resources>
diff --git a/res/values-port/dimens.xml b/res/values-port/dimens.xml
index 945699b..c5fdd68 100644
--- a/res/values-port/dimens.xml
+++ b/res/values-port/dimens.xml
@@ -23,18 +23,19 @@
     <!-- NOTE: This padding is the @dimen/button_bar_height + some padding
          for signposting -->
     <dimen name="workspace_bottom_padding">64dp</dimen>
+    <dimen name="workspace_page_spacing">8dp</dimen>
 
     <dimen name="folder_cell_width">74dip</dimen>
     <dimen name="folder_cell_height">86dip</dimen>
 
-    <integer name="all_apps_view_cellCountX">4</integer>
-    <integer name="all_apps_view_cellCountY">5</integer>
-    <dimen name="all_apps_view_pageLayoutWidthGap">-1dp</dimen>
-    <dimen name="all_apps_view_pageLayoutHeightGap">-1dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingTop">15dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingBottom">15dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingLeft">5dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingRight">5dp</dimen>
+    <integer name="apps_customize_cellCountX">4</integer>
+    <integer name="apps_customize_cellCountY">5</integer>
+    <dimen name="apps_customize_pageLayoutWidthGap">-1dp</dimen>
+    <dimen name="apps_customize_pageLayoutHeightGap">-1dp</dimen>
+    <dimen name="apps_customize_pageLayoutPaddingTop">15dp</dimen>
+    <dimen name="apps_customize_pageLayoutPaddingBottom">15dp</dimen>
+    <dimen name="apps_customize_pageLayoutPaddingLeft">5dp</dimen>
+    <dimen name="apps_customize_pageLayoutPaddingRight">5dp</dimen>
 
     <dimen name="apps_customize_widget_cell_width_gap">20dp</dimen>
     <dimen name="apps_customize_widget_cell_height_gap">10dp</dimen>
diff --git a/res/values-xlarge-port/dimens.xml b/res/values-xlarge-port/dimens.xml
index 31db0b3..4f53280 100644
--- a/res/values-xlarge-port/dimens.xml
+++ b/res/values-xlarge-port/dimens.xml
@@ -22,5 +22,5 @@
 
     <!-- We can also afford to have a slightly wider portrait layout in
          xlarge -->
-    <dimen name="all_apps_view_pageLayoutWidthGap">36dp</dimen>
+    <dimen name="apps_customize_pageLayoutWidthGap">36dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/res/values/config.xml b/res/values/config.xml
index 497011c..f03ded7 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -1,6 +1,8 @@
 <resources>
     <bool name="config_hardwareAccelerated">true</bool>
 <!-- AllApps/Customize/AppsCustomize -->
+    <!-- The alpha of the AppsCustomize bg in spring loaded mode -->
+    <integer name="config_appsCustomizeSpringLoadedBgAlpha">45</integer>
     <!-- Fade in/out duration of icons being dragged from the trays -->
     <integer name="config_dragAppsCustomizeIconFadeInDuration">150</integer>
     <integer name="config_dragAppsCustomizeIconFadeOutDuration">200</integer>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 7353eda..c04dd8e 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -29,19 +29,17 @@
     <dimen name="toolbar_button_horizontal_padding">12dip</dimen>
 
 <!-- AllApps/Customize/AppsCustomize -->
-    <!-- Size of icons in Workspace/AppsCustomize -->
+    <dimen name="apps_customize_tab_bar_height">56dp</dimen>
     <dimen name="app_icon_size">56dp</dimen>
+    <!-- The width can be 72dp because we don't have L/R padding -->
     <dimen name="apps_customize_cell_width">72dp</dimen>
-    <dimen name="apps_customize_cell_height">72dp</dimen>
+    <dimen name="apps_customize_cell_height">80dp</dimen>
     <dimen name="apps_customize_peek_width">0dp</dimen>
     <dimen name="apps_customize_max_gap">18dp</dimen>
     <dimen name="apps_customize_widget_cell_width_gap">10dp</dimen>
     <dimen name="apps_customize_widget_cell_height_gap">10dp</dimen>
     <dimen name="title_texture_width">120px</dimen>
 
-    <!-- height of the tab bar in AppsCustomize -->
-    <dimen name="apps_customize_tab_bar_height">56dp</dimen>
-
     <!-- height of the bottom row of controls -->
     <dimen name="button_bar_height">56dip</dimen>
 
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 06f6ed0..46e5f95 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -51,12 +51,6 @@
         <item name="android:shadowColor">#B0000000</item>
     </style>
 
-    <style name="WorkspaceIcon.AppsCustomize">
-        <item name="android:background">@null</item>
-        <item name="android:drawablePadding">0dp</item>
-        <item name="android:includeFontPadding">false</item>
-    </style>
-
     <style name="WorkspaceIcon.Portrait">
         <item name="android:drawablePadding">4dp</item>
         <item name="android:paddingLeft">4dp</item>
@@ -72,16 +66,30 @@
         <item name="android:paddingTop">2dp</item>
         <item name="android:paddingBottom">4dp</item>
     </style>
+
     <style name="WorkspaceIcon.Portrait.Folder">
         <item name="android:drawablePadding">0dp</item>
         <item name="android:paddingTop">0dp</item>
     </style>
-
     <style name="WorkspaceIcon.Landscape.Folder">
         <item name="android:drawablePadding">0dp</item>
         <item name="android:paddingTop">0dp</item>
     </style>
 
+    <style name="WorkspaceIcon.Portrait.AppsCustomize">
+        <item name="android:background">@null</item>
+        <item name="android:paddingLeft">0dp</item>
+        <item name="android:paddingRight">0dp</item>
+        <item name="android:drawablePadding">0dp</item>
+        <item name="android:includeFontPadding">false</item>
+    </style>
+    <style name="WorkspaceIcon.Landscape.AppsCustomize">
+        <item name="android:background">@null</item>
+        <item name="android:paddingBottom">0dp</item>
+        <item name="android:drawablePadding">0dp</item>
+        <item name="android:includeFontPadding">false</item>
+    </style>
+
     <style name="SearchDropTargetBar">
         <item name="android:orientation">horizontal</item>
         <item name="android:layout_width">match_parent</item>
@@ -111,6 +119,10 @@
         <item name="android:drawablePadding">7.5dp</item>
         <item name="android:textColor">#FFFFFFFF</item>
         <item name="android:textSize">16sp</item>
+        <item name="android:shadowColor">#393939</item>
+        <item name="android:shadowDx">0.0</item>
+        <item name="android:shadowDy">0.0</item>
+        <item name="android:shadowRadius">2.0</item>
     </style>
 
     <style name="TabIndicator">
@@ -129,6 +141,9 @@
         <item name="android:shadowDy">1.0</item>
         <item name="android:shadowRadius">1.0</item>
     </style>
+    <style name="TabIndicator.AppsCustomize">
+        <!-- Overridden in values-land -->
+    </style>
 
     <style name="MarketButton">
         <item name="android:paddingLeft">5dp</item>
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java
index 90f2815..f5874bf 100644
--- a/src/com/android/launcher2/AppsCustomizePagedView.java
+++ b/src/com/android/launcher2/AppsCustomizePagedView.java
@@ -472,9 +472,13 @@
         }
         return true;
     }
-    private void endDragging(boolean success) {
+    private void endDragging(View target, boolean success) {
         mLauncher.getWorkspace().onDragStopped(success);
-        mLauncher.exitSpringLoadedDragMode();
+        if (!success || target != mLauncher.getWorkspace()) {
+            // Exit spring loaded mode if we have not successfully dropped or have not handled the
+            // drop in Workspace
+            mLauncher.exitSpringLoadedDragMode();
+        }
         mLauncher.unlockScreenOrientation();
 
     }
@@ -486,7 +490,7 @@
     public void onDragViewVisible() {}
     @Override
     public void onDropCompleted(View target, DragObject d, boolean success) {
-        endDragging(success);
+        endDragging(target, success);
 
         // Display an error message if the drag failed due to there not being enough space on the
         // target layout we were dropping on.
@@ -765,7 +769,7 @@
         layout.measure(widthSpec, heightSpec);
         setVisibilityOnChildren(layout, View.VISIBLE);
     }
-    private synchronized 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) {
             Canvas c = new Canvas(bitmap);
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index b8515fc..22516cc 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -29,7 +29,6 @@
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
-import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Point;
 import android.graphics.PointF;
diff --git a/src/com/android/launcher2/DeleteDropTarget.java b/src/com/android/launcher2/DeleteDropTarget.java
index 6e01bc0..afa2654 100644
--- a/src/com/android/launcher2/DeleteDropTarget.java
+++ b/src/com/android/launcher2/DeleteDropTarget.java
@@ -72,11 +72,14 @@
     private boolean isAllAppsWidget(DragSource source, Object info) {
         return (source instanceof AppsCustomizePagedView) && (info instanceof PendingAddWidgetInfo);
     }
-    private boolean isWorkspaceApplication(DragObject d) {
-        return (d.dragSource instanceof Workspace) && (d.dragInfo instanceof ShortcutInfo);
+    private boolean isDragSourceWorkspaceOrFolder(DragObject d) {
+        return (d.dragSource instanceof Workspace) || (d.dragSource instanceof Folder);
     }
-    private boolean isWorkspaceWidget(DragObject d) {
-        return (d.dragSource instanceof Workspace) && (d.dragInfo instanceof LauncherAppWidgetInfo);
+    private boolean isWorkspaceOrFolderApplication(DragObject d) {
+        return isDragSourceWorkspaceOrFolder(d) && (d.dragInfo instanceof ShortcutInfo);
+    }
+    private boolean isWorkspaceOrFolderWidget(DragObject d) {
+        return isDragSourceWorkspaceOrFolder(d) && (d.dragInfo instanceof LauncherAppWidgetInfo);
     }
     private boolean isWorkspaceFolder(DragObject d) {
         return (d.dragSource instanceof Workspace) && (d.dragInfo instanceof FolderInfo);
@@ -141,14 +144,14 @@
         if (isAllAppsApplication(d.dragSource, item)) {
             // Uninstall the application if it is being dragged from AppsCustomize
             mLauncher.startApplicationUninstallActivity((ApplicationInfo) item);
-        } else if (isWorkspaceApplication(d)) {
+        } else if (isWorkspaceOrFolderApplication(d)) {
             LauncherModel.deleteItemFromDatabase(mLauncher, item);
         } else if (isWorkspaceFolder(d)) {
             // Remove the folder from the workspace and delete the contents from launcher model
             FolderInfo folderInfo = (FolderInfo) item;
             mLauncher.removeFolder(folderInfo);
             LauncherModel.deleteFolderContentsFromDatabase(mLauncher, folderInfo);
-        } else if (isWorkspaceWidget(d)) {
+        } else if (isWorkspaceOrFolderWidget(d)) {
             // Remove the widget from the workspace
             mLauncher.removeAppWidget((LauncherAppWidgetInfo) item);
             LauncherModel.deleteItemFromDatabase(mLauncher, item);
diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java
index dfd8160..0bdfec1 100644
--- a/src/com/android/launcher2/DragLayer.java
+++ b/src/com/android/launcher2/DragLayer.java
@@ -175,16 +175,25 @@
                 mTmpXY[0] + descendant.getWidth(), mTmpXY[1] + descendant.getHeight());
     }
 
-    private void getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
-        coord[0] += descendant.getLeft();
-        coord[1] += descendant.getTop();
+    private float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
+        float scale = 1.0f;
+        float[] pt = {coord[0], coord[1]};
+        descendant.getMatrix().mapPoints(pt);
+        scale *= descendant.getScaleX();
+        pt[0] += descendant.getLeft();
+        pt[1] += descendant.getTop();
         ViewParent viewParent = descendant.getParent();
         while (viewParent instanceof View && viewParent != this) {
             final View view = (View)viewParent;
-            coord[0] += view.getLeft() + (int) (view.getTranslationX() + 0.5f) - view.getScrollX();
-            coord[1] += view.getTop() + (int) (view.getTranslationY() + 0.5f) - view.getScrollY();
+            view.getMatrix().mapPoints(pt);
+            scale *= view.getScaleX();
+            pt[0] += view.getLeft() - view.getScrollX();
+            pt[1] += view.getTop() - view.getScrollY();
             viewParent = view.getParent();
         }
+        coord[0] = (int) pt[0];
+        coord[1] = (int) pt[1];
+        return scale;
     }
 
     public void getLocationInDragLayer(View child, int[] loc) {
@@ -304,6 +313,10 @@
     }
 
     public void animateViewIntoPosition(DragView dragView, final View child) {
+        animateViewIntoPosition(dragView, child, null);
+    }
+    public void animateViewIntoPosition(DragView dragView, final View child,
+            final Runnable onFinishAnimationRunnable) {
         ((CellLayoutChildren) child.getParent()).measureChild(child);
         CellLayout.LayoutParams lp =  (CellLayout.LayoutParams) child.getLayoutParams();
 
@@ -311,13 +324,15 @@
         getViewRectRelativeToSelf(dragView, r);
 
         int coord[] = new int[2];
-        coord[0] = lp.x;
-        coord[1] = lp.y;
+        coord[0] = lp.x + (lp.width / 2);
+        coord[1] = lp.y + (lp.height / 2);
         // Since the child hasn't necessarily been laid out, we force the lp to be updated with
         // the correct coordinates and use these to determine the final location
-        getDescendantCoordRelativeToSelf((View) child.getParent(), coord);
-        int toX = coord[0] - (dragView.getWidth() - child.getMeasuredWidth()) / 2;
-        int toY = coord[1] - (dragView.getHeight() - child.getMeasuredHeight()) / 2;
+        float scale = getDescendantCoordRelativeToSelf((View) child.getParent(), coord);
+        int toX = coord[0] - lp.width / 2;
+        int toY = coord[1] - lp.height / 2;
+        toX -= (dragView.getWidth() - child.getMeasuredWidth()) / 2;
+        toY -= (dragView.getHeight() - child.getMeasuredHeight()) / 2;
 
         final int fromX = r.left + (dragView.getWidth() - child.getMeasuredWidth())  / 2;
         final int fromY = r.top + (dragView.getHeight() - child.getMeasuredHeight())  / 2;
@@ -328,19 +343,39 @@
                 child.setVisibility(VISIBLE);
                 ObjectAnimator oa = ObjectAnimator.ofFloat(child, "alpha", 0f, 1f);
                 oa.setDuration(60);
+                oa.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(android.animation.Animator animation) {
+                        if (onFinishAnimationRunnable != null) {
+                            onFinishAnimationRunnable.run();
+                        }
+                    }
+                });
                 oa.start();
             }
         };
-        animateViewIntoPosition(dragView, fromX, fromY, toX, toY, onCompleteRunnable, true);
+        animateViewIntoPosition(dragView, fromX, fromY, toX, toY, scale, onCompleteRunnable, true);
+    }
+
+    /* Just fade out in place */
+    public void animateViewOut(DragView dragView, Runnable onFinishAnimationRunnable) {
+        Rect r = new Rect();
+        getViewRectRelativeToSelf(dragView, r);
+        final int fromX = r.left;
+        final int fromY = r.top;
+        final int toX = fromX;
+        final int toY = fromY;
+        animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1.0f, onFinishAnimationRunnable,
+                true);
     }
 
     private void animateViewIntoPosition(final View view, final int fromX, final int fromY,
-            final int toX, final int toY, Runnable onCompleteRunnable, boolean fadeOut) {
+            final int toX, final int toY, float finalScale, Runnable onCompleteRunnable,
+            boolean fadeOut) {
         Rect from = new Rect(fromX, fromY, fromX +
                 view.getMeasuredWidth(), fromY + view.getMeasuredHeight());
         Rect to = new Rect(toX, toY, toX + view.getMeasuredWidth(), toY + view.getMeasuredHeight());
-        animateView(view, from, to, 1f, 1.0f, -1, null, null, onCompleteRunnable, true);
-
+        animateView(view, from, to, 1f, finalScale, -1, null, null, onCompleteRunnable, true);
     }
 
     public void animateView(final View view, final Rect from, final Rect to, final float finalAlpha,
diff --git a/src/com/android/launcher2/DropTarget.java b/src/com/android/launcher2/DropTarget.java
index 0712420..34fa893 100644
--- a/src/com/android/launcher2/DropTarget.java
+++ b/src/com/android/launcher2/DropTarget.java
@@ -49,6 +49,9 @@
         /** Where the drag originated */
         public DragSource dragSource = null;
 
+        /** Post drag animation runnable */
+        public Runnable postAnimationRunnable = null;
+
         public DragObject() {
         }
     }
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
index 4978e98..283c295 100644
--- a/src/com/android/launcher2/FolderIcon.java
+++ b/src/com/android/launcher2/FolderIcon.java
@@ -286,12 +286,13 @@
     }
 
     public void performCreateAnimation(final ShortcutInfo destInfo, final View destView,
-            final ShortcutInfo srcInfo, final View srcView, Rect dstRect) {
+            final ShortcutInfo srcInfo, final View srcView, Rect dstRect,
+            Runnable postAnimationRunnable) {
 
         Drawable animateDrawable = ((TextView) destView).getCompoundDrawables()[1];
         computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(), destView.getMeasuredWidth());
         // This will animate the dragView (srcView) into the new folder
-        onDrop(srcInfo, srcView, dstRect, 1);
+        onDrop(srcInfo, srcView, dstRect, 1, postAnimationRunnable);
 
         // This will animate the first item from it's position as an icon into its
         // position as the first item in the preview
@@ -309,7 +310,8 @@
         mFolderRingAnimator.animateToNaturalState();
     }
 
-    private void onDrop(final ShortcutInfo item, View animateView, Rect finalRect, int index) {
+    private void onDrop(final ShortcutInfo item, View animateView, Rect finalRect, int index,
+            Runnable postAnimationRunnable) {
         item.cellX = -1;
         item.cellY = -1;
         DragLayer dragLayer = mLauncher.getDragLayer();
@@ -332,7 +334,8 @@
         float finalAlpha = index < NUM_ITEMS_IN_PREVIEW ? 0.5f : 0f;
 
         dragLayer.animateView(animateView, from, to, finalAlpha, scale, DROP_IN_ANIMATION_DURATION,
-                new DecelerateInterpolator(2), new AccelerateInterpolator(2), null, false);
+                new DecelerateInterpolator(2), new AccelerateInterpolator(2), postAnimationRunnable,
+                false);
         postDelayed(new Runnable() {
             public void run() {
                 addItem(item);
@@ -348,7 +351,7 @@
         } else {
             item = (ShortcutInfo) d.dragInfo;
         }
-        onDrop(item, d.dragView, null, mInfo.contents.size());
+        onDrop(item, d.dragView, null, mInfo.contents.size(), d.postAnimationRunnable);
     }
 
     public DropTarget getDropTargetDelegate(DragObject d) {
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index 6f64f9d..530f49c 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -167,6 +167,8 @@
     private AnimatorSet mStateAnimation;
 
     static final int APPWIDGET_HOST_ID = 1024;
+    private static final int EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT = 300;
+    private static final int EXIT_SPRINGLOADED_MODE_LONG_TIMEOUT = 600;
 
     private static final Object sLock = new Object();
     private static int sScreen = DEFAULT_SCREEN;
@@ -592,7 +594,11 @@
         }
     }
 
-    private void completeAdd(PendingAddArguments args) {
+    /**
+     * Returns whether we should delay spring loaded mode -- for shortcuts and widgets that have
+     * a configuration step, this allows the proper animations to run after other transitions.
+     */
+    private boolean completeAdd(PendingAddArguments args) {
         switch (args.requestCode) {
             case REQUEST_PICK_APPLICATION:
                 completeAddApplication(args.intent, args.screen, args.cellX, args.cellY);
@@ -602,22 +608,24 @@
                 break;
             case REQUEST_CREATE_SHORTCUT:
                 completeAddShortcut(args.intent, args.screen, args.cellX, args.cellY);
-                break;
+                return true;
             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;
+                return true;
             case REQUEST_PICK_WALLPAPER:
                 // We just wanted the activity result here so we can clear mWaitingForResult
                 break;
         }
+        return false;
     }
 
     @Override
     protected void onActivityResult(final int requestCode, int resultCode, final Intent data) {
+        boolean delayExitSpringLoadedMode = false;
         mWaitingForResult = false;
 
         // The pattern used here is that a user PICKs a specific application,
@@ -638,17 +646,21 @@
             if (isWorkspaceLocked()) {
                 sPendingAddList.add(args);
             } else {
-                completeAdd(args);
+                delayExitSpringLoadedMode = completeAdd(args);
             }
         } else if ((requestCode == REQUEST_PICK_APPWIDGET ||
-                requestCode == REQUEST_CREATE_APPWIDGET) && resultCode == RESULT_CANCELED &&
-                data != null) {
-            // Clean up the appWidgetId if we canceled
-            int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
-            if (appWidgetId != -1) {
-                mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+                requestCode == REQUEST_CREATE_APPWIDGET) && resultCode == RESULT_CANCELED) {
+            if (data != null) {
+                // Clean up the appWidgetId if we canceled
+                int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
+                if (appWidgetId != -1) {
+                    mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+                }
             }
         }
+
+        // Exit spring loaded mode if necessary after cancelling the configuration of a widget
+        exitSpringLoadedDragModeDelayed(delayExitSpringLoadedMode);
     }
 
     @Override
@@ -1066,7 +1078,6 @@
             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);
@@ -1550,6 +1561,9 @@
         } else {
             // Otherwise just add it
             completeAddAppWidget(appWidgetId, mAddScreen);
+
+            // Exit spring loaded mode if necessary after adding the widget
+            exitSpringLoadedDragModeDelayed(false);
         }
     }
 
@@ -2542,7 +2556,16 @@
         }
         // Otherwise, we are not in spring loaded mode, so don't do anything.
     }
-
+    void exitSpringLoadedDragModeDelayed(boolean extendedDelay) {
+        mWorkspace.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                exitSpringLoadedDragMode();
+            }
+        }, (extendedDelay ?
+                EXIT_SPRINGLOADED_MODE_LONG_TIMEOUT :
+                EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT));
+    }
     void exitSpringLoadedDragMode() {
         if (mState == State.APPS_CUSTOMIZE_SPRING_LOADED) {
             mWorkspace.exitSpringLoadedDragMode(Workspace.ShrinkState.BOTTOM_VISIBLE);
@@ -2674,10 +2697,6 @@
         }
     }
 
-    void onWorkspaceClick(CellLayout layout) {
-        showWorkspace(true, layout);
-    }
-
     private Drawable getExternalPackageToolbarIcon(ComponentName activityName) {
         try {
             PackageManager packageManager = getPackageManager();
@@ -2861,7 +2880,6 @@
          * Handle the action clicked in the "Add to home" dialog.
          */
         public void onClick(DialogInterface dialog, int which) {
-            Resources res = getResources();
             cleanup();
 
             AddAdapter.ListItem item = (AddAdapter.ListItem) mAdapter.getItem(which);
diff --git a/src/com/android/launcher2/LauncherApplication.java b/src/com/android/launcher2/LauncherApplication.java
index 68b1644..db3a4cb 100644
--- a/src/com/android/launcher2/LauncherApplication.java
+++ b/src/com/android/launcher2/LauncherApplication.java
@@ -24,11 +24,14 @@
 import android.database.ContentObserver;
 import android.os.Handler;
 
+import java.lang.ref.WeakReference;
+
 public class LauncherApplication extends Application {
     public LauncherModel mModel;
     public IconCache mIconCache;
     private static boolean sIsScreenLarge;
     private static float sScreenDensity;
+    WeakReference<LauncherProvider> mLauncherProvider;
 
     @Override
     public void onCreate() {
@@ -97,6 +100,14 @@
         return mModel;
     }
 
+    void setLauncherProvider(LauncherProvider provider) {
+        mLauncherProvider = new WeakReference<LauncherProvider>(provider);
+    }
+
+    LauncherProvider getLauncherProvider() {
+        return mLauncherProvider.get();
+    }
+
     public static boolean isScreenLarge() {
         return sIsScreenLarge;
     }
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index e8ae9d9..64b38c0 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -88,9 +88,27 @@
 
     private WeakReference<Callbacks> mCallbacks;
 
-    private AllAppsList mAllAppsList; // only access in worker thread
-    private IconCache mIconCache;
+    // < only access in worker thread >
+    private AllAppsList mAllAppsList;
 
+    // sItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by
+    // LauncherModel to their ids
+    static final HashMap<Long, ItemInfo> sItemsIdMap = new HashMap<Long, ItemInfo>();
+
+    // sItems is passed to bindItems, which expects a list of all folders and shortcuts created by
+    //       LauncherModel that are directly on the home screen (however, no widgets or shortcuts
+    //       within folders).
+    static final ArrayList<ItemInfo> sItems = new ArrayList<ItemInfo>();
+
+    // sAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()
+    static final ArrayList<LauncherAppWidgetInfo> sAppWidgets =
+        new ArrayList<LauncherAppWidgetInfo>();
+
+    // sFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()
+    static final HashMap<Long, FolderInfo> sFolders = new HashMap<Long, FolderInfo>();
+    // </ only access in worker thread >
+
+    private IconCache mIconCache;
     private Bitmap mDefaultIcon;
 
     private static int mCellCountX;
@@ -148,9 +166,8 @@
     /**
      * Move an item in the DB to a new <container, screen, cellX, cellY>
      */
-    static void moveItemInDatabase(Context context, ItemInfo item, long container, int screen,
-            int cellX, int cellY) {
-
+    static void moveItemInDatabase(Context context, final ItemInfo item, final long container,
+            final int screen, final int cellX, final int cellY) {
         item.container = container;
         item.screen = screen;
         item.cellX = cellX;
@@ -168,6 +185,24 @@
         sWorker.post(new Runnable() {
                 public void run() {
                     cr.update(uri, values, null, null);
+                    ItemInfo modelItem = sItemsIdMap.get(item.id);
+                    if (item != modelItem) {
+                        // the modelItem needs to match up perfectly with item if our model is to be
+                        // consistent with the database-- for now, just require modelItem == item
+                        throw new RuntimeException("Error: ItemInfo passed to moveItemInDatabase " +
+                                "doesn't match original");
+                    }
+
+                    // Items are added/removed from the corresponding FolderInfo elsewhere, such
+                    // as in Workspace.onDrop. Here, we just add/remove them from the list of items
+                    // that are on the desktop, as appropriate
+                    if (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+                        if (!sItems.contains(modelItem)) {
+                            sItems.add(modelItem);
+                        }
+                    } else {
+                        sItems.remove(modelItem);
+                    }
                 }
             });
     }
@@ -175,8 +210,8 @@
     /**
      * 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) {
+    static void resizeItemInDatabase(Context context, final ItemInfo item, final int cellX,
+            final int cellY, final int spanX, final int spanY) {
         item.spanX = spanX;
         item.spanY = spanY;
         item.cellX = cellX;
@@ -195,6 +230,13 @@
         sWorker.post(new Runnable() {
                 public void run() {
                     cr.update(uri, values, null, null);
+                    ItemInfo modelItem = sItemsIdMap.get(item.id);
+                    if (item != modelItem) {
+                        // the modelItem needs to match up perfectly with item if our model is to be
+                        // consistent with the database-- for now, just require modelItem == item
+                        throw new RuntimeException("Error: ItemInfo passed to moveItemInDatabase " +
+                            "doesn't match original");
+                    }
                 }
             });
     }
@@ -316,14 +358,37 @@
         final ContentResolver cr = context.getContentResolver();
         item.onAddToDatabase(values);
 
+        Launcher l = (Launcher) context;
+        LauncherApplication app = (LauncherApplication) l.getApplication();
+        item.id = app.getLauncherProvider().generateNewId();
+        values.put(LauncherSettings.Favorites._ID, item.id);
         item.updateValuesWithCoordinates(values, cellX, cellY);
 
-        Uri result = cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :
-            LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);
+        sWorker.post(new Runnable() {
+            public void run() {
+                cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :
+                        LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);
 
-        if (result != null) {
-            item.id = Integer.parseInt(result.getPathSegments().get(1));
-        }
+                sItemsIdMap.put(item.id, item);
+                switch (item.itemType) {
+                    case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
+                        sFolders.put(item.id, (FolderInfo) item);
+                        if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+                            sItems.add(item);
+                        }
+                        break;
+                    case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+                    case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+                        if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+                            sItems.add(item);
+                        }
+                        break;
+                    case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+                        sAppWidgets.add((LauncherAppWidgetInfo) item);
+                        break;
+                }
+            }
+        });
     }
 
     /**
@@ -355,14 +420,26 @@
     /**
      * Update an item to the database in a specified container.
      */
-    static void updateItemInDatabase(Context context, ItemInfo item) {
+    static void updateItemInDatabase(Context context, final ItemInfo item) {
         final ContentValues values = new ContentValues();
         final ContentResolver cr = context.getContentResolver();
 
         item.onAddToDatabase(values);
         item.updateValuesWithCoordinates(values, item.cellX, item.cellY);
 
-        cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null);
+        sWorker.post(new Runnable() {
+            public void run() {
+                cr.update(LauncherSettings.Favorites.getContentUri(item.id, false),
+                        values, null, null);
+                final ItemInfo modelItem = sItemsIdMap.get(item.id);
+                if (item != modelItem) {
+                    // the modelItem needs to match up perfectly with item if our model is to be
+                    // consistent with the database-- for now, just require modelItem == item
+                    throw new RuntimeException("Error: ItemInfo passed to moveItemInDatabase " +
+                        "doesn't match original");
+                }
+            }
+        });
     }
 
     /**
@@ -370,43 +447,50 @@
      * @param context
      * @param item
      */
-    static void deleteItemFromDatabase(Context context, ItemInfo item) {
+    static void deleteItemFromDatabase(Context context, final ItemInfo item) {
         final ContentResolver cr = context.getContentResolver();
         final Uri uriToDelete = LauncherSettings.Favorites.getContentUri(item.id, false);
         sWorker.post(new Runnable() {
                 public void run() {
                     cr.delete(uriToDelete, null, null);
+                    switch (item.itemType) {
+                        case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
+                            sFolders.remove(item.id);
+                            sItems.remove(item);
+                            break;
+                        case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+                        case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+                            sItems.remove(item);
+                            break;
+                        case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+                            sAppWidgets.remove((LauncherAppWidgetInfo) item);
+                            break;
+                    }
+                    sItemsIdMap.remove(item.id);
                 }
             });
     }
 
-    static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {
-        deleteFolderContentsFromDatabase(context, info, false);
-    }
-
     /**
      * Remove the contents of the specified folder from the database
      */
-    static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info,
-            boolean post) {
-        // TODO: this post flag is temporary to fix an ordering of commands issue. In future, 
-        // all db operations will be moved to the worker thread, so this can be discarded at
-        // that time.
+    static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {
         final ContentResolver cr = context.getContentResolver();
 
-        if (!post) {
-            cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);
-            cr.delete(LauncherSettings.Favorites.CONTENT_URI,
-                    LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);
-        } else {
-            sWorker.post(new Runnable() {
+        sWorker.post(new Runnable() {
                 public void run() {
                     cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);
+                    sItemsIdMap.remove(info.id);
+                    sFolders.remove(info.id);
+                    sItems.remove(info);
+
                     cr.delete(LauncherSettings.Favorites.CONTENT_URI,
                             LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);
+                    for (ItemInfo childInfo : info.contents) {
+                        sItemsIdMap.remove(childInfo.id);
+                    }
                 }
             });
-        }
     }
 
     /**
@@ -547,10 +631,6 @@
         private boolean mStopped;
         private boolean mLoadAndBindStepFinished;
 
-        final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>();
-        final ArrayList<LauncherAppWidgetInfo> mAppWidgets = new ArrayList<LauncherAppWidgetInfo>();
-        final HashMap<Long, FolderInfo> mFolders = new HashMap<Long, FolderInfo>();
-
         LoaderTask(Context context, boolean isLaunching) {
             mContext = context;
             mIsLaunching = isLaunching;
@@ -562,14 +642,10 @@
 
         private void loadAndBindWorkspace() {
             // Load the workspace
-
-            // For now, just always reload the workspace.  It's ~100 ms vs. the
-            // binding which takes many hundreds of ms.
-            // We can reconsider.
             if (DEBUG_LOADERS) {
                 Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);
             }
-            if (true || !mWorkspaceLoaded) {
+            if (!mWorkspaceLoaded) {
                 loadWorkspace();
                 if (mStopped) {
                     return;
@@ -743,9 +819,10 @@
             final AppWidgetManager widgets = AppWidgetManager.getInstance(context);
             final boolean isSafeMode = manager.isSafeMode();
 
-            mItems.clear();
-            mAppWidgets.clear();
-            mFolders.clear();
+            sItems.clear();
+            sAppWidgets.clear();
+            sFolders.clear();
+            sItemsIdMap.clear();
 
             final ArrayList<Long> itemsToRemove = new ArrayList<Long>();
 
@@ -834,15 +911,16 @@
 
                                 switch (container) {
                                 case LauncherSettings.Favorites.CONTAINER_DESKTOP:
-                                    mItems.add(info);
+                                    sItems.add(info);
                                     break;
                                 default:
                                     // Item is in a user folder
                                     FolderInfo folderInfo =
-                                            findOrMakeFolder(mFolders, container);
+                                            findOrMakeFolder(sFolders, container);
                                     folderInfo.add(info);
                                     break;
                                 }
+                                sItemsIdMap.put(info.id, info);
 
                                 // now that we've loaded everthing re-save it with the
                                 // icon in case it disappears somehow.
@@ -861,7 +939,7 @@
 
                         case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
                             id = c.getLong(idIndex);
-                            FolderInfo folderInfo = findOrMakeFolder(mFolders, id);
+                            FolderInfo folderInfo = findOrMakeFolder(sFolders, id);
 
                             folderInfo.title = c.getString(titleIndex);
                             folderInfo.id = id;
@@ -877,11 +955,12 @@
                             }
                             switch (container) {
                                 case LauncherSettings.Favorites.CONTAINER_DESKTOP:
-                                    mItems.add(folderInfo);
+                                    sItems.add(folderInfo);
                                     break;
                             }
 
-                            mFolders.put(folderInfo.id, folderInfo);
+                            sItemsIdMap.put(folderInfo.id, folderInfo);
+                            sFolders.put(folderInfo.id, folderInfo);
                             break;
 
                         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
@@ -918,8 +997,8 @@
                                 if (!checkItemPlacement(occupied, appWidgetInfo)) {
                                     break;
                                 }
-
-                                mAppWidgets.add(appWidgetInfo);
+                                sItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);
+                                sAppWidgets.add(appWidgetInfo);
                             }
                             break;
                         }
@@ -993,7 +1072,7 @@
                 }
             });
             // Add the items to the workspace.
-            N = mItems.size();
+            N = sItems.size();
             for (int i=0; i<N; i+=ITEMS_CHUNK) {
                 final int start = i;
                 final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);
@@ -1001,7 +1080,7 @@
                     public void run() {
                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                         if (callbacks != null) {
-                            callbacks.bindItems(mItems, start, start+chunkSize);
+                            callbacks.bindItems(sItems, start, start+chunkSize);
                         }
                     }
                 });
@@ -1010,7 +1089,7 @@
                 public void run() {
                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                     if (callbacks != null) {
-                        callbacks.bindFolders(mFolders);
+                        callbacks.bindFolders(sFolders);
                     }
                 }
             });
@@ -1028,10 +1107,10 @@
             // is just a hint for the order, and if it's wrong, we'll be okay.
             // TODO: instead, we should have that push the current screen into here.
             final int currentScreen = oldCallbacks.getCurrentWorkspaceScreen();
-            N = mAppWidgets.size();
+            N = sAppWidgets.size();
             // once for the current screen
             for (int i=0; i<N; i++) {
-                final LauncherAppWidgetInfo widget = mAppWidgets.get(i);
+                final LauncherAppWidgetInfo widget = sAppWidgets.get(i);
                 if (widget.screen == currentScreen) {
                     mHandler.post(new Runnable() {
                         public void run() {
@@ -1045,7 +1124,7 @@
             }
             // once for the other screens
             for (int i=0; i<N; i++) {
-                final LauncherAppWidgetInfo widget = mAppWidgets.get(i);
+                final LauncherAppWidgetInfo widget = sAppWidgets.get(i);
                 if (widget.screen != currentScreen) {
                     mHandler.post(new Runnable() {
                         public void run() {
@@ -1238,7 +1317,7 @@
             Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);
             Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);
             Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);
-            Log.d(TAG, "mItems size=" + mItems.size());
+            Log.d(TAG, "mItems size=" + sItems.size());
         }
     }
 
diff --git a/src/com/android/launcher2/LauncherProvider.java b/src/com/android/launcher2/LauncherProvider.java
index a02e449..5ffd984 100644
--- a/src/com/android/launcher2/LauncherProvider.java
+++ b/src/com/android/launcher2/LauncherProvider.java
@@ -32,6 +32,7 @@
 import android.content.res.TypedArray;
 import android.content.pm.PackageManager;
 import android.content.pm.ActivityInfo;
+import android.content.SharedPreferences;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteStatement;
@@ -80,11 +81,12 @@
     static final Uri CONTENT_APPWIDGET_RESET_URI =
             Uri.parse("content://" + AUTHORITY + "/appWidgetReset");
     
-    private SQLiteOpenHelper mOpenHelper;
+    private DatabaseHelper mOpenHelper;
 
     @Override
     public boolean onCreate() {
         mOpenHelper = new DatabaseHelper(getContext());
+        ((LauncherApplication) getContext()).setLauncherProvider(this);
         return true;
     }
 
@@ -113,12 +115,20 @@
         return result;
     }
 
+    private static long dbInsertAndCheck(DatabaseHelper helper,
+            SQLiteDatabase db, String table, String nullColumnHack, ContentValues values) {
+        if (!values.containsKey(LauncherSettings.Favorites._ID)) {
+            throw new RuntimeException("Error: attempting to add item without specifying an id");
+        }
+        return db.insert(table, nullColumnHack, values);
+    }
+
     @Override
     public Uri insert(Uri uri, ContentValues initialValues) {
         SqlArguments args = new SqlArguments(uri);
 
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
-        final long rowId = db.insert(args.table, null, initialValues);
+        final long rowId = dbInsertAndCheck(mOpenHelper, db, args.table, null, initialValues);
         if (rowId <= 0) return null;
 
         uri = ContentUris.withAppendedId(uri, rowId);
@@ -136,7 +146,9 @@
         try {
             int numValues = values.length;
             for (int i = 0; i < numValues; i++) {
-                if (db.insert(args.table, null, values[i]) < 0) return 0;
+                if (dbInsertAndCheck(mOpenHelper, db, args.table, null, values[i]) < 0) {
+                    return 0;
+                }
             }
             db.setTransactionSuccessful();
         } finally {
@@ -176,6 +188,10 @@
         }
     }
 
+    public long generateNewId() {
+        return mOpenHelper.generateNewId();
+    }
+
     private static class DatabaseHelper extends SQLiteOpenHelper {
         private static final String TAG_FAVORITES = "favorites";
         private static final String TAG_FAVORITE = "favorite";
@@ -186,11 +202,13 @@
         
         private final Context mContext;
         private final AppWidgetHost mAppWidgetHost;
+        private long mMaxId = -1;
 
         DatabaseHelper(Context context) {
             super(context, DATABASE_NAME, null, DATABASE_VERSION);
             mContext = context;
             mAppWidgetHost = new AppWidgetHost(context, Launcher.APPWIDGET_HOST_ID);
+            mMaxId = initializeMaxId(getWritableDatabase());
         }
 
         /**
@@ -207,7 +225,9 @@
         @Override
         public void onCreate(SQLiteDatabase db) {
             if (LOGD) Log.d(TAG, "creating new launcher database");
-            
+
+            mMaxId = 1;
+
             db.execSQL("CREATE TABLE favorites (" +
                     "_id INTEGER PRIMARY KEY," +
                     "title TEXT," +
@@ -253,7 +273,7 @@
             try {
                 cursor = resolver.query(uri, null, null, null, null);
             } catch (Exception e) {
-	            // Ignore
+                // Ignore
             }
 
             // We already have a favorites database in the old provider
@@ -321,7 +341,7 @@
             try {
                 int numValues = rows.length;
                 for (i = 0; i < numValues; i++) {
-                    if (db.insert(TABLE_FAVORITES, null, rows[i]) < 0) {
+                    if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, rows[i]) < 0) {
                         return 0;
                     } else {
                         total++;
@@ -535,7 +555,36 @@
                     c.close();
                 }
             }
-            
+        }
+
+        // Generates a new ID to use for an object in your database. This method should be only
+        // called from the main UI thread. As an exception, we do call it when we call the
+        // constructor from the worker thread; however, this doesn't extend until after the
+        // constructor is called, and we only pass a reference to LauncherProvider to LauncherApp
+        // after that point
+        public long generateNewId() {
+            if (mMaxId < 0) {
+                throw new RuntimeException("Error: max id was not initialized");
+            }
+            mMaxId += 1;
+            return mMaxId;
+        }
+
+        private long initializeMaxId(SQLiteDatabase db) {
+            Cursor c = db.rawQuery("SELECT MAX(_id) FROM favorites", null);
+
+            // get the result
+            final int maxIdIndex = 0;
+            long id = -1;
+            if (c != null && c.moveToNext()) {
+                id = c.getLong(maxIdIndex);
+            }
+
+            if (id == -1) {
+                throw new RuntimeException("Error: could not query max id");
+            }
+
+            return id;
         }
 
         /**
@@ -712,7 +761,8 @@
                 values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPLICATION);
                 values.put(Favorites.SPANX, 1);
                 values.put(Favorites.SPANY, 1);
-                db.insert(TABLE_FAVORITES, null, values);
+                values.put(Favorites._ID, generateNewId());
+                dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values);
             } catch (PackageManager.NameNotFoundException e) {
                 Log.w(TAG, "Unable to add favorite: " + packageName +
                         "/" + className, e);
@@ -804,7 +854,8 @@
                 values.put(Favorites.SPANX, spanX);
                 values.put(Favorites.SPANY, spanY);
                 values.put(Favorites.APPWIDGET_ID, appWidgetId);
-                db.insert(TABLE_FAVORITES, null, values);
+                values.put(Favorites._ID, generateNewId());
+                dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values);
 
                 allocatedAppWidgets = true;
                 
@@ -847,8 +898,8 @@
             values.put(Favorites.ICON_TYPE, Favorites.ICON_TYPE_RESOURCE);
             values.put(Favorites.ICON_PACKAGE, mContext.getPackageName());
             values.put(Favorites.ICON_RESOURCE, r.getResourceName(iconResId));
-
-            db.insert(TABLE_FAVORITES, null, values);
+            values.put(Favorites._ID, generateNewId());
+            dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values);
 
             return true;
         }
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index 81e876f..8c74c42 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -368,8 +368,11 @@
     // we moved this functionality to a helper function so SmoothPagedView can reuse it
     protected boolean computeScrollHelper() {
         if (mScroller.computeScrollOffset()) {
-            mDirtyPageAlpha = true;
-            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
+            // Don't bother scrolling if the page does not need to be moved
+            if (mScrollX != mScroller.getCurrX() || mScrollY != mScroller.getCurrY()) {
+                mDirtyPageAlpha = true;
+                scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
+            }
             invalidate();
             return true;
         } else if (mNextPage != INVALID_PAGE) {
@@ -652,7 +655,7 @@
         if (pageCount > 0) {
             final int pageWidth = getScaledMeasuredWidth(getChildAt(0));
             final int screenWidth = getMeasuredWidth();
-            int x = getRelativeChildOffset(0) + pageWidth;
+            int x = getScaledRelativeChildOffset(0) + pageWidth;
             int leftScreen = 0;
             int rightScreen = 0;
             while (x <= mScrollX) {
@@ -1255,6 +1258,10 @@
         return (getMeasuredWidth() - getChildWidth(index)) / 2;
     }
 
+    protected int getScaledRelativeChildOffset(int index) {
+        return (getMeasuredWidth() - getScaledMeasuredWidth(getChildAt(index))) / 2;
+    }
+
     protected int getChildOffset(int index) {
         if (getChildCount() == 0)
             return 0;
diff --git a/src/com/android/launcher2/SearchDropTargetBar.java b/src/com/android/launcher2/SearchDropTargetBar.java
index 943bd00..4bfb40a 100644
--- a/src/com/android/launcher2/SearchDropTargetBar.java
+++ b/src/com/android/launcher2/SearchDropTargetBar.java
@@ -62,7 +62,6 @@
         dragController.addDropTarget(mDeleteDropTarget);
         mInfoDropTarget.setLauncher(launcher);
         mDeleteDropTarget.setLauncher(launcher);
-        mDropTargetBar.setBackgroundColor(0x33000000);
     }
 
     @Override
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index fd18338..87279d0 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -74,8 +74,7 @@
  * 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,
-        View.OnClickListener {
+        implements DropTarget, DragSource, DragScroller, View.OnTouchListener {
     @SuppressWarnings({"UnusedDeclaration"})
     private static final String TAG = "Launcher.Workspace";
 
@@ -109,16 +108,11 @@
     private float mOverScrollMaxBackgroundAlpha = 0.0f;
     private int mOverScrollPageIndex = -1;
 
-
-
     private final WallpaperManager mWallpaperManager;
     private IBinder mWindowToken;
 
     private int mDefaultPage;
 
-    private boolean mIsDragInProcess = false;
-    private boolean mIsDraggingOverIcon = false;
-
     /**
      * CellInfo for the cell that is currently being dragged
      */
@@ -147,9 +141,7 @@
     private float[] mTempTouchCoordinates = new float[2];
     private float[] mTempCellLayoutCenterCoordinates = new float[2];
     private float[] mTempDragBottomRightCoordinates = new float[2];
-    private float[] mTempFloatTuple = new float[2];
     private Matrix mTempInverseMatrix = new Matrix();
-    private int[] mTempLocation = new int[2];
 
     private SpringLoadedDragController mSpringLoadedDragController;
     private float mSpringLoadedShrinkFactor;
@@ -172,9 +164,6 @@
     /** Is the user is dragging an item near the edge of a page? */
     private boolean mInScrollArea = false;
 
-    /** If mInScrollArea is true, the direction of the scroll. */
-    private int mPendingScrollDirection = DragController.SCROLL_NONE;
-
     private final HolographicOutlineHelper mOutlineHelper = new HolographicOutlineHelper();
     private Bitmap mDragOutline = null;
     private final Rect mTempRect = new Rect();
@@ -196,9 +185,6 @@
     boolean mSyncWallpaperOffsetWithScroll = true;
     private Runnable mDelayedResizeRunnable;
 
-    // info about the last drag
-    private DragView mLastDragView;
-
     // Variables relating to the creation of user folders by hovering shortcuts over shortcuts
     private static final int FOLDER_CREATION_TIMEOUT = 250;
     private final Alarm mFolderCreationAlarm = new Alarm();
@@ -255,10 +241,6 @@
             // TODO: This code currently fails on tablets with an aspect ratio < 1.3.
             // Around that ratio we should make cells the same size in portrait and
             // landscape
-            final DisplayMetrics dm = res.getDisplayMetrics();
-            float widthDp = dm.widthPixels / dm.density;
-            float heightDp = dm.heightPixels / dm.density;
-
             TypedArray actionBarSizeTypedArray =
                 context.obtainStyledAttributes(new int[] { android.R.attr.actionBarSize });
             final float actionBarHeight = actionBarSizeTypedArray.getDimension(0, 0f);
@@ -355,7 +337,6 @@
         }
         CellLayout cl = ((CellLayout) child);
         cl.setOnInterceptTouchListener(this);
-        cl.setOnClickListener(this);
         cl.setClickable(true);
         cl.enableHardwareLayers();
     }
@@ -523,17 +504,6 @@
         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);
-        }
-    }
-
     protected void onWindowVisibilityChanged (int visibility) {
         mLauncher.onWindowVisibilityChanged(visibility);
     }
@@ -962,11 +932,11 @@
         mBackgroundFadeInAnimation.start();
     }
 
-    private void hideBackgroundGradient() {
+    private void hideBackgroundGradient(float finalAlpha) {
         if (mBackground == null) return;
         if (mBackgroundFadeInAnimation != null) mBackgroundFadeInAnimation.cancel();
         if (mBackgroundFadeOutAnimation != null) mBackgroundFadeOutAnimation.cancel();
-        mBackgroundFadeOutAnimation = ValueAnimator.ofFloat(getBackgroundAlpha(), 0f);
+        mBackgroundFadeOutAnimation = ValueAnimator.ofFloat(getBackgroundAlpha(), finalAlpha);
         mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() {
             public void onAnimationUpdate(ValueAnimator animation) {
                 setBackgroundAlpha(((Float) animation.getAnimatedValue()).floatValue());
@@ -1130,40 +1100,27 @@
 
     @Override
     protected void dispatchDraw(Canvas canvas) {
-        if (mIsSmall || mIsInUnshrinkAnimation) {
-            // Draw all the workspaces if we're small
-            final int pageCount = getChildCount();
-            final long drawingTime = getDrawingTime();
-            for (int i = 0; i < pageCount; i++) {
-                final CellLayout page = (CellLayout) getChildAt(i);
-                if (page.getVisibility() == VISIBLE
-                        && (page.getAlpha() != 0f || page.getBackgroundAlpha() != 0f)) {
-                    drawChild(canvas, page, drawingTime);
-                }
-            }
-        } else {
-            super.dispatchDraw(canvas);
+        super.dispatchDraw(canvas);
 
-            if (mInScrollArea && !LauncherApplication.isScreenLarge()) {
-                final int width = getWidth();
-                final int height = getHeight();
-                final int pageHeight = getChildAt(0).getHeight();
+        if (mInScrollArea && !LauncherApplication.isScreenLarge()) {
+            final int width = getWidth();
+            final int height = getHeight();
+            final int pageHeight = getChildAt(0).getHeight();
 
-                // This determines the height of the glowing edge: 90% of the page height
-                final int padding = (int) ((height - pageHeight) * 0.5f + pageHeight * 0.1f);
+            // This determines the height of the glowing edge: 90% of the page height
+            final int padding = (int) ((height - pageHeight) * 0.5f + pageHeight * 0.1f);
 
-                final CellLayout leftPage = (CellLayout) getChildAt(mCurrentPage - 1);
-                final CellLayout rightPage = (CellLayout) getChildAt(mCurrentPage + 1);
+            final CellLayout leftPage = (CellLayout) getChildAt(mCurrentPage - 1);
+            final CellLayout rightPage = (CellLayout) getChildAt(mCurrentPage + 1);
 
-                if (leftPage != null && leftPage.getIsDragOverlapping()) {
-                    final Drawable d = getResources().getDrawable(R.drawable.page_hover_left_holo);
-                    d.setBounds(mScrollX, padding, mScrollX + d.getIntrinsicWidth(), height - padding);
-                    d.draw(canvas);
-                } else if (rightPage != null && rightPage.getIsDragOverlapping()) {
-                    final Drawable d = getResources().getDrawable(R.drawable.page_hover_right_holo);
-                    d.setBounds(mScrollX + width - d.getIntrinsicWidth(), padding, mScrollX + width, height - padding);
-                    d.draw(canvas);
-                }
+            if (leftPage != null && leftPage.getIsDragOverlapping()) {
+                final Drawable d = getResources().getDrawable(R.drawable.page_hover_left_holo);
+                d.setBounds(mScrollX, padding, mScrollX + d.getIntrinsicWidth(), height - padding);
+                d.draw(canvas);
+            } else if (rightPage != null && rightPage.getIsDragOverlapping()) {
+                final Drawable d = getResources().getDrawable(R.drawable.page_hover_right_holo);
+                d.setBounds(mScrollX + width - d.getIntrinsicWidth(), padding, mScrollX + width, height - padding);
+                d.draw(canvas);
             }
         }
     }
@@ -1439,7 +1396,10 @@
         float offsetFromCenter = (wallpaperTravelHeight / (float) mWallpaperHeight) / 2f;
         boolean isLandscape = display.getWidth() > display.getHeight();
 
-        final boolean enableWallpaperEffects = isHardwareAccelerated();
+        // on phones, don't scroll the wallpaper horizontally or vertically when switching
+        // to/from all apps
+        final boolean enableWallpaperEffects =
+            isHardwareAccelerated() && LauncherApplication.isScreenLarge();
         if (enableWallpaperEffects) {
             switch (shrinkState) {
                 // animating in
@@ -1480,7 +1440,7 @@
                         // an optimization, and required for correct behavior.
                         return;
                     }
-                    fastInvalidate();
+                    invalidate();
                     if (enableWallpaperEffects) {
                         setHorizontalWallpaperOffset(
                             a * oldHorizontalWallpaperOffset + b * newHorizontalWallpaperOffset);
@@ -1583,8 +1543,6 @@
     *
     */
     public void onDragStartedWithItem(View v) {
-        mIsDragInProcess = true;
-
         final Canvas canvas = new Canvas();
 
         // We need to add extra padding to the bitmap to make room for the glow effect
@@ -1595,8 +1553,6 @@
     }
 
     public void onDragStartedWithItemSpans(int spanX, int spanY, Bitmap b) {
-        mIsDragInProcess = true;
-
         final Canvas canvas = new Canvas();
 
         // We need to add extra padding to the bitmap to make room for the glow effect
@@ -1617,7 +1573,6 @@
         if (!success) {
             doDragExit(null);
         }
-        mIsDragInProcess = false;
     }
 
     // We call this when we trigger an unshrink by clicking on the CellLayout cl
@@ -1752,7 +1707,10 @@
             }
             Display display = mLauncher.getWindowManager().getDefaultDisplay();
             boolean isLandscape = display.getWidth() > display.getHeight();
-            final boolean enableWallpaperEffects = isHardwareAccelerated();
+            // on phones, don't scroll the wallpaper horizontally or vertically when switching
+            // to/from all apps
+            final boolean enableWallpaperEffects =
+                isHardwareAccelerated() && LauncherApplication.isScreenLarge();
             if (enableWallpaperEffects) {
                 switch (mShrinkState) {
                     // animating out
@@ -1793,7 +1751,7 @@
                             // an optimization, but not required
                             return;
                         }
-                        fastInvalidate();
+                        invalidate();
                         if (enableWallpaperEffects) {
                             setHorizontalWallpaperOffset(a * oldHorizontalWallpaperOffset
                                     + b * newHorizontalWallpaperOffset);
@@ -1849,9 +1807,8 @@
             }
         }
 
-        if (!springLoaded) {
-            hideBackgroundGradient();
-        }
+        hideBackgroundGradient(springLoaded ? getResources().getInteger(
+                R.integer.config_appsCustomizeSpringLoadedBgAlpha) / 100f : 0f);
     }
 
     /**
@@ -2050,9 +2007,19 @@
             mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,
                     d.dragView, mDragViewVisualCenter);
 
-            final CellLayout.CellInfo dragCellInfo = mDragInfo;
-            final int spanX = dragCellInfo == null ? 1 : dragCellInfo.spanX;
-            final int spanY = dragCellInfo == null ? 1 : dragCellInfo.spanY;
+            int spanX = 1;
+            int spanY = 1;
+            View ignoreView = null;
+            if (mDragInfo != null) {
+                final CellLayout.CellInfo dragCellInfo = mDragInfo;
+                spanX = dragCellInfo.spanX;
+                spanY = dragCellInfo.spanY;
+                ignoreView = dragCellInfo.cell;
+            } else {
+                final ItemInfo dragInfo = (ItemInfo) d.dragInfo;
+                spanX = dragInfo.spanX;
+                spanY = dragInfo.spanY;
+            }
 
             mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
                     (int) mDragViewVisualCenter[1], spanX, spanY, mDragTargetLayout, mTargetCell);
@@ -2065,7 +2032,6 @@
                 return true;
             }
 
-            final View ignoreView = dragCellInfo == null ? null : dragCellInfo.cell;
 
             // Don't accept the drop if there's no room for the item
             if (!mDragTargetLayout.findCellForSpanIgnoring(null, spanX, spanY, ignoreView)) {
@@ -2107,7 +2073,7 @@
     }
 
     boolean createUserFolderIfNecessary(View newView, CellLayout target,
-            int[] targetCell, boolean external, DragView dragView) {
+            int[] targetCell, boolean external, DragView dragView, Runnable postAnimationRunnable) {
         View v = target.getChildAt(targetCell[0], targetCell[1]);
         boolean hasntMoved = mDragInfo != null
                 && (mDragInfo.cellX == targetCell[0] && mDragInfo.cellY == targetCell[1]);
@@ -2139,7 +2105,8 @@
             sourceInfo.cellX = -1;
             sourceInfo.cellY = -1;
 
-            fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation);
+            fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation,
+                    postAnimationRunnable);
             return true;
         }
         return false;
@@ -2207,7 +2174,7 @@
                 boolean dropInscrollArea = mCurrentPage != screen;
 
                 if (!dropInscrollArea && createUserFolderIfNecessary(cell, dropTargetLayout,
-                        mTargetCell, false, d.dragView)) {
+                        mTargetCell, false, d.dragView, null)) {
                     return;
                 }
 
@@ -2305,7 +2272,6 @@
         mDragTargetLayout = getCurrentDropLayout();
         mDragTargetLayout.setIsDragOverlapping(true);
         mDragTargetLayout.onDragEnter();
-        mLastDragView = d.dragView;
 
         // Because we don't have space in the Phone UI (the CellLayouts run to the edge) we
         // don't need to show the outlines
@@ -2325,7 +2291,6 @@
             mDragTargetLayout.setIsDragOverlapping(false);
             mDragTargetLayout.onDragExit();
         }
-        mLastDragView = null;
         mLastDragOverView = null;
 
         if (!mIsPageMoving) {
@@ -2387,8 +2352,7 @@
                 if (isShortcut) {
                     // Check if we have enough space on this screen to add a new shortcut
                     if (!layout.findCellForSpan(pos, 1, 1)) {
-                        Toast.makeText(mContext, mContext.getString(R.string.out_of_space),
-                                Toast.LENGTH_SHORT).show();
+                        mLauncher.showOutOfSpaceMessage();
                         return false;
                     }
                 }
@@ -2572,10 +2536,6 @@
      *
      */
     private CellLayout findMatchingPageForDragOver(
-            DragView dragView, int originX, int originY, int offsetX, int offsetY) {
-        return findMatchingPageForDragOver(dragView, originX, originY, offsetX, offsetY, false);
-    }
-    private CellLayout findMatchingPageForDragOver(
             DragView dragView, int originX, int originY, int offsetX, int offsetY, boolean exact) {
         // We loop through all the screens (ie CellLayouts) and see which ones overlap
         // with the item being dragged and then choose the one that's closest to the touch point
@@ -2831,27 +2791,38 @@
      * 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[] touchXY, Object dragInfo,
-            CellLayout cellLayout, boolean insertAtFirst, DragObject d) {
-        int screen = indexOfChild(cellLayout);
+    private void onDropExternal(final int[] touchXY, final Object dragInfo,
+            final CellLayout cellLayout, boolean insertAtFirst, DragObject d) {
+        final Runnable exitSpringLoadedRunnable = new Runnable() {
+            @Override
+            public void run() {
+                mLauncher.exitSpringLoadedDragModeDelayed(false);
+            }
+        };
+        final int screen = indexOfChild(cellLayout);
         if (screen != mCurrentPage && mShrinkState != ShrinkState.SPRING_LOADED) {
             snapToPage(screen);
         }
         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
-            switch (info.itemType) {
-                case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
-                    mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) info, screen, touchXY);
-                    break;
-                case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
-                    mLauncher.processShortcutFromDrop(info.componentName, screen, touchXY);
-                    break;
-                default:
-                    throw new IllegalStateException("Unknown item type: " + info.itemType);
-            }
-            cellLayout.onDragExit();
+            final PendingAddItemInfo info = (PendingAddItemInfo) dragInfo;
+            mLauncher.getDragLayer().animateViewOut(d.dragView, new Runnable() {
+                @Override
+                public void run() {
+                    // When dragging and dropping from customization tray, we deal with creating
+                    // widgets/shortcuts/folders in a slightly different way
+                    switch (info.itemType) {
+                    case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+                        mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) info, screen, touchXY);
+                        break;
+                    case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+                        mLauncher.processShortcutFromDrop(info.componentName, screen, touchXY);
+                        break;
+                    default:
+                        throw new IllegalStateException("Unknown item type: " + info.itemType);
+                    }
+                    cellLayout.onDragExit();
+                }
+            });
         } else {
             // This is for other drag/drop cases, like dragging from All Apps
             ItemInfo info = (ItemInfo) dragInfo;
@@ -2875,14 +2846,24 @@
                 throw new IllegalStateException("Unknown item type: " + info.itemType);
             }
 
-            int spanX = mDragInfo != null ? mDragInfo.spanX : 1;
-            int spanY = mDragInfo != null ? mDragInfo.spanY : 1;
+            int spanX = 1;
+            int spanY = 1;
+            if (mDragInfo != null) {
+                spanX = mDragInfo.spanX;
+                spanY = mDragInfo.spanY;
+            } else {
+                spanX = info.spanX;
+                spanY = info.spanY;
+            }
+
             // First we find the cell nearest to point at which the item is
             // dropped, without any consideration to whether there is an item there.
             if (touchXY != null) {
                 mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY,
                         cellLayout, mTargetCell);
-                if (createUserFolderIfNecessary(view, cellLayout, mTargetCell, true, d.dragView)) {
+                d.postAnimationRunnable = exitSpringLoadedRunnable;
+                if (createUserFolderIfNecessary(view, cellLayout, mTargetCell, true, d.dragView,
+                        d.postAnimationRunnable)) {
                     return;
                 }
                 if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, d, true)) {
@@ -2909,7 +2890,8 @@
                     lp.cellX, lp.cellY);
 
             if (d.dragView != null) {
-                mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, view);
+                mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, view,
+                    exitSpringLoadedRunnable);
             }
         }
     }
@@ -3026,7 +3008,6 @@
     public void onEnterScrollArea(int direction) {
         if (!mIsSmall && !mIsInUnshrinkAnimation) {
             mInScrollArea = true;
-            mPendingScrollDirection = direction;
 
             final int page = mCurrentPage + (direction == DragController.SCROLL_LEFT ? -1 : 1);
             final CellLayout layout = (CellLayout) getChildAt(page);
@@ -3061,7 +3042,6 @@
                 // so we need to redraw the workspace when this may have changed.
                 invalidate();
             }
-            mPendingScrollDirection = DragController.SCROLL_NONE;
             mInScrollArea = false;
         }
     }
@@ -3075,7 +3055,6 @@
             // so we need to redraw the workspace when this may have changed.
             invalidate();
         }
-        mPendingScrollDirection = DragController.SCROLL_NONE;
         mInScrollArea = false;
     }
 
@@ -3131,7 +3110,6 @@
 
     void removeItems(final ArrayList<ApplicationInfo> apps) {
         final int screenCount = getChildCount();
-        final PackageManager manager = getContext().getPackageManager();
         final AppWidgetManager widgets = AppWidgetManager.getInstance(getContext());
 
         final HashSet<String> packageNames = new HashSet<String>();