merge in ics-release history after reset to master
diff --git a/res/drawable-hdpi/all_apps_bg_gradient.png b/res/drawable-hdpi/all_apps_bg_gradient.png
new file mode 100644
index 0000000..c420ca5
--- /dev/null
+++ b/res/drawable-hdpi/all_apps_bg_gradient.png
Binary files differ
diff --git a/res/drawable-hdpi/homescreen_large_blue.9.png b/res/drawable-hdpi/homescreen_large_blue.9.png
new file mode 100644
index 0000000..416514d
--- /dev/null
+++ b/res/drawable-hdpi/homescreen_large_blue.9.png
Binary files differ
diff --git a/res/drawable-hdpi/homescreen_large_blue_strong.9.png b/res/drawable-hdpi/homescreen_large_blue_strong.9.png
new file mode 100644
index 0000000..d7e32e7
--- /dev/null
+++ b/res/drawable-hdpi/homescreen_large_blue_strong.9.png
Binary files differ
diff --git a/res/drawable-hdpi/homescreen_large_green.9.png b/res/drawable-hdpi/homescreen_large_green.9.png
new file mode 100644
index 0000000..60042c2
--- /dev/null
+++ b/res/drawable-hdpi/homescreen_large_green.9.png
Binary files differ
diff --git a/res/drawable-hdpi/homescreen_large_green_strong.9.png b/res/drawable-hdpi/homescreen_large_green_strong.9.png
new file mode 100644
index 0000000..c40b98e
--- /dev/null
+++ b/res/drawable-hdpi/homescreen_large_green_strong.9.png
Binary files differ
diff --git a/res/drawable-hdpi/homescreen_small_blue.9.png b/res/drawable-hdpi/homescreen_small_blue.9.png
new file mode 100644
index 0000000..ddc458b
--- /dev/null
+++ b/res/drawable-hdpi/homescreen_small_blue.9.png
Binary files differ
diff --git a/res/drawable-hdpi/homescreen_small_blue_strong.9.png b/res/drawable-hdpi/homescreen_small_blue_strong.9.png
new file mode 100644
index 0000000..8f5a74e
--- /dev/null
+++ b/res/drawable-hdpi/homescreen_small_blue_strong.9.png
Binary files differ
diff --git a/res/drawable-hdpi/homescreen_small_green_strong.9.png b/res/drawable-hdpi/homescreen_small_green_strong.9.png
new file mode 100644
index 0000000..77baa52
--- /dev/null
+++ b/res/drawable-hdpi/homescreen_small_green_strong.9.png
Binary files differ
diff --git a/res/drawable-large-hdpi/homescreen_large_blue.9.png b/res/drawable-large-hdpi/homescreen_large_blue.9.png
deleted file mode 100644
index 6ce3d29..0000000
--- a/res/drawable-large-hdpi/homescreen_large_blue.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-large-hdpi/homescreen_large_blue_strong.9.png b/res/drawable-large-hdpi/homescreen_large_blue_strong.9.png
deleted file mode 100644
index 8110148..0000000
--- a/res/drawable-large-hdpi/homescreen_large_blue_strong.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-large-hdpi/homescreen_large_green.9.png b/res/drawable-large-hdpi/homescreen_large_green.9.png
deleted file mode 100644
index 4a6546e..0000000
--- a/res/drawable-large-hdpi/homescreen_large_green.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-large-hdpi/homescreen_large_green_strong.9.png b/res/drawable-large-hdpi/homescreen_large_green_strong.9.png
deleted file mode 100644
index 5ba9ebe..0000000
--- a/res/drawable-large-hdpi/homescreen_large_green_strong.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-large-hdpi/homescreen_small_blue.9.png b/res/drawable-large-hdpi/homescreen_small_blue.9.png
deleted file mode 100644
index db93b3c..0000000
--- a/res/drawable-large-hdpi/homescreen_small_blue.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-large-hdpi/homescreen_small_blue_strong.9.png b/res/drawable-large-hdpi/homescreen_small_blue_strong.9.png
deleted file mode 100644
index 32bd857..0000000
--- a/res/drawable-large-hdpi/homescreen_small_blue_strong.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-large-hdpi/homescreen_small_green.9.png b/res/drawable-large-hdpi/homescreen_small_green.9.png
deleted file mode 100644
index 00baae9..0000000
--- a/res/drawable-large-hdpi/homescreen_small_green.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-large-hdpi/homescreen_small_green_strong.9.png b/res/drawable-large-hdpi/homescreen_small_green_strong.9.png
deleted file mode 100644
index e1e64c5..0000000
--- a/res/drawable-large-hdpi/homescreen_small_green_strong.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-large-mdpi/homescreen_small_green.9.png b/res/drawable-large-mdpi/homescreen_small_green.9.png
deleted file mode 100644
index 58698ea..0000000
--- a/res/drawable-large-mdpi/homescreen_small_green.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/all_apps_bg_gradient.png b/res/drawable-mdpi/all_apps_bg_gradient.png
new file mode 100644
index 0000000..c420ca5
--- /dev/null
+++ b/res/drawable-mdpi/all_apps_bg_gradient.png
Binary files differ
diff --git a/res/drawable-large-mdpi/homescreen_large_blue.9.png b/res/drawable-mdpi/homescreen_large_blue.9.png
similarity index 100%
rename from res/drawable-large-mdpi/homescreen_large_blue.9.png
rename to res/drawable-mdpi/homescreen_large_blue.9.png
Binary files differ
diff --git a/res/drawable-large-mdpi/homescreen_large_green.9.png b/res/drawable-mdpi/homescreen_large_green.9.png
similarity index 100%
rename from res/drawable-large-mdpi/homescreen_large_green.9.png
rename to res/drawable-mdpi/homescreen_large_green.9.png
Binary files differ
diff --git a/res/drawable-large-mdpi/homescreen_large_green_strong.9.png b/res/drawable-mdpi/homescreen_large_green_strong.9.png
similarity index 100%
rename from res/drawable-large-mdpi/homescreen_large_green_strong.9.png
rename to res/drawable-mdpi/homescreen_large_green_strong.9.png
Binary files differ
diff --git a/res/drawable-large-mdpi/homescreen_small_blue.9.png b/res/drawable-mdpi/homescreen_small_blue.9.png
similarity index 100%
rename from res/drawable-large-mdpi/homescreen_small_blue.9.png
rename to res/drawable-mdpi/homescreen_small_blue.9.png
Binary files differ
diff --git a/res/drawable-large-mdpi/homescreen_small_blue_strong.9.png b/res/drawable-mdpi/homescreen_small_blue_strong.9.png
similarity index 100%
rename from res/drawable-large-mdpi/homescreen_small_blue_strong.9.png
rename to res/drawable-mdpi/homescreen_small_blue_strong.9.png
Binary files differ
diff --git a/res/drawable-large-mdpi/homescreen_small_green_strong.9.png b/res/drawable-mdpi/homescreen_small_green_strong.9.png
similarity index 100%
rename from res/drawable-large-mdpi/homescreen_small_green_strong.9.png
rename to res/drawable-mdpi/homescreen_small_green_strong.9.png
Binary files differ
diff --git a/res/layout/apps_customize_pane.xml b/res/layout/apps_customize_pane.xml
index 604dff4..f3ecb48 100644
--- a/res/layout/apps_customize_pane.xml
+++ b/res/layout/apps_customize_pane.xml
@@ -16,11 +16,14 @@
 <com.android.launcher2.AppsCustomizeTabHost
     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"
-        android:layout_height="match_parent"
-        android:background="#FF000000">
+        android:layout_height="match_parent">
         <!-- The layout_width of the tab bar gets overriden to align the content
              with the text in the tabs in AppsCustomizeTabHost. -->
         <FrameLayout
diff --git a/res/values-large/config.xml b/res/values-large/config.xml
index 8b77696..dca8282 100644
--- a/res/values-large/config.xml
+++ b/res/values-large/config.xml
@@ -6,6 +6,8 @@
     <integer name="config_customizeZoomOutTime">600</integer>
     <integer name="config_customizeZoomScaleFactor">7</integer>
     <integer name="config_customizeFadeInTime">800</integer>
+    <!-- Out of 100, the percent to shrink the workspace during spring loaded mode. -->
+    <integer name="config_workspaceSpringLoadShrinkPercentage">70</integer>
 
     <!-- The slope, in percent, of the drag movement needed to drag an item out of
          Customize (y / x * 100%)  -->
@@ -24,12 +26,4 @@
     <!-- When shrinking the workspace, this is the percentage of its original size. -->
     <integer name="config_workspaceShrinkPercent">17</integer>
 
-    <!-- When items are dropped on the mini screens in customize mode, we have a bounce animation
-         of the bright green hover outline, and then fade out the outline at the end. These are
-         the values used in that animation -->
-    <integer name="config_screenOnDropScalePercent">120</integer>
-    <integer name="config_screenOnDropScaleUpDuration">200</integer>
-    <integer name="config_screenOnDropScaleDownDuration">200</integer>
-    <integer name="config_screenOnDropAlphaFadeDelay">350</integer>
-    <integer name="config_screenOnDropAlphaFadeDuration">50</integer>
 </resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 44ba589..394ff8a 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -5,6 +5,16 @@
     <integer name="config_dragAppsCustomizeIconFadeOutDuration">200</integer>
     <integer name="config_dragAppsCustomizeIconFadeAlpha">100</integer>
     <integer name="config_workspaceUnshrinkTime">650</integer>
+    <!-- Out of 100, the percent to shrink the workspace during spring loaded mode. -->
+    <integer name="config_workspaceSpringLoadShrinkPercentage">80</integer>
+    <!-- When items are dropped on the mini screens in customize mode, we have a bounce animation
+         of the bright green hover outline, and then fade out the outline at the end. These are
+         the values used in that animation -->
+    <integer name="config_screenOnDropScalePercent">120</integer>
+    <integer name="config_screenOnDropScaleUpDuration">200</integer>
+    <integer name="config_screenOnDropScaleDownDuration">200</integer>
+    <integer name="config_screenOnDropAlphaFadeDelay">350</integer>
+    <integer name="config_screenOnDropAlphaFadeDuration">50</integer>
 
     <!-- Fade/zoom in/out duration & scale in the AllApps transition.
          Note: This should be less than the workspaceShrinkTime as they happen together. -->
diff --git a/src/com/android/launcher2/AllApps2D.java b/src/com/android/launcher2/AllApps2D.java
index 44af7b7..4547f54 100644
--- a/src/com/android/launcher2/AllApps2D.java
+++ b/src/com/android/launcher2/AllApps2D.java
@@ -16,8 +16,6 @@
 
 package com.android.launcher2;
 
-import com.android.launcher.R;
-
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
@@ -37,6 +35,9 @@
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
+import com.android.launcher.R;
+import com.android.launcher2.DropTarget.DragObject;
+
 import java.util.ArrayList;
 import java.util.Collections;
 
@@ -208,7 +209,7 @@
     }
 
     @Override
-    public void onDropCompleted(View target, Object dragInfo, boolean success) {
+    public void onDropCompleted(View target, DragObject d, boolean success) {
     }
 
     /**
diff --git a/src/com/android/launcher2/AllApps3D.java b/src/com/android/launcher2/AllApps3D.java
index 0e512c6..837ddbb 100644
--- a/src/com/android/launcher2/AllApps3D.java
+++ b/src/com/android/launcher2/AllApps3D.java
@@ -16,12 +16,6 @@
 
 package com.android.launcher2;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-
-import com.android.launcher.R;
-
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
@@ -29,9 +23,20 @@
 import android.graphics.Canvas;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
-import android.renderscript.*;
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Matrix4f;
+import android.renderscript.Mesh;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramFragmentFixedFunction;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.ProgramVertexFixedFunction;
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+import android.renderscript.Sampler;
 import android.util.AttributeSet;
-import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -42,6 +47,13 @@
 import android.view.ViewConfiguration;
 import android.view.accessibility.AccessibilityEvent;
 
+import com.android.launcher.R;
+import com.android.launcher2.DropTarget.DragObject;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
 public class AllApps3D extends RSSurfaceView
         implements AllAppsView, View.OnClickListener, View.OnLongClickListener, DragSource {
     private static final String TAG = "Launcher.AllApps3D";
@@ -744,7 +756,7 @@
     }
 
     @Override
-    public void onDropCompleted(View target, Object dragInfo, boolean success) {
+    public void onDropCompleted(View target, DragObject d, boolean success) {
         mLauncher.getWorkspace().onDragStopped(success);
         mLauncher.unlockScreenOrientation();
     }
diff --git a/src/com/android/launcher2/AllAppsPagedView.java b/src/com/android/launcher2/AllAppsPagedView.java
index 0f364f8..ae8b970 100644
--- a/src/com/android/launcher2/AllAppsPagedView.java
+++ b/src/com/android/launcher2/AllAppsPagedView.java
@@ -16,9 +16,6 @@
 
 package com.android.launcher2;
 
-import com.android.launcher.R;
-import com.android.launcher2.DropTarget.DragObject;
-
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
@@ -34,6 +31,8 @@
 import android.widget.Checkable;
 import android.widget.TextView;
 
+import com.android.launcher.R;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
@@ -412,7 +411,7 @@
     }
 
     @Override
-    public void onDropCompleted(View target, Object dragInfo, boolean success) {
+    public void onDropCompleted(View target, DragObject d, boolean success) {
         // close the choice action mode if we have a proper drop
         if (target != this) {
             endChoiceMode();
diff --git a/src/com/android/launcher2/ApplicationInfoDropTarget.java b/src/com/android/launcher2/ApplicationInfoDropTarget.java
index 311ac7e..fa4663a 100644
--- a/src/com/android/launcher2/ApplicationInfoDropTarget.java
+++ b/src/com/android/launcher2/ApplicationInfoDropTarget.java
@@ -16,9 +16,6 @@
 
 package com.android.launcher2;
 
-import com.android.launcher.R;
-import com.android.launcher2.DropTarget.DragObject;
-
 import android.animation.Animator;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
@@ -30,6 +27,8 @@
 import android.util.AttributeSet;
 import android.view.View;
 
+import com.android.launcher.R;
+
 /**
  * Implements a DropTarget which allows applications to be dropped on it,
  * in order to launch the application info for that app.
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java
index 7c6742f..464bb44 100644
--- a/src/com/android/launcher2/AppsCustomizePagedView.java
+++ b/src/com/android/launcher2/AppsCustomizePagedView.java
@@ -16,11 +16,6 @@
 
 package com.android.launcher2;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
@@ -38,9 +33,9 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Rect;
+import android.graphics.Bitmap.Config;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -56,6 +51,12 @@
 import android.widget.Toast;
 
 import com.android.launcher.R;
+import com.android.launcher2.DropTarget.DragObject;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
 
 public class AppsCustomizePagedView extends PagedViewWithDraggableItems implements
         AllAppsView, View.OnClickListener, DragSource {
@@ -409,9 +410,6 @@
     protected boolean beginDragging(View v) {
         if (!super.beginDragging(v)) return false;
 
-        // Hide the pane so that the user can drop onto the workspace, we must do this first,
-        // due to how the drop target layout is computed when we start dragging to the workspace.
-        mLauncher.showWorkspace(true);
 
         if (v instanceof PagedViewIcon) {
             beginDraggingApplication(v);
@@ -419,6 +417,10 @@
             beginDraggingWidget(v);
         }
 
+        // Go into spring loaded mode
+        int currentPageIndex = mLauncher.getWorkspace().getCurrentPage();
+        CellLayout currentPage = (CellLayout) mLauncher.getWorkspace().getChildAt(currentPageIndex);
+        mLauncher.enterSpringLoadedDragMode(currentPage);
         return true;
     }
     private void endDragging(boolean success) {
@@ -438,8 +440,10 @@
                 if (allAppsInfoButton != null) allAppsInfoButton.setDragAndDropEnabled(false);
             }
         });
+        mLauncher.exitSpringLoadedDragMode();
         mLauncher.getWorkspace().onDragStopped(success);
         mLauncher.unlockScreenOrientation();
+
     }
 
     /*
@@ -448,7 +452,7 @@
     @Override
     public void onDragViewVisible() {}
     @Override
-    public void onDropCompleted(View target, Object dragInfo, boolean success) {
+    public void onDropCompleted(View target, DragObject d, boolean success) {
         endDragging(success);
 
         // Display an error message if the drag failed due to there not being enough space on the
@@ -459,7 +463,7 @@
                 int currentScreen = mLauncher.getCurrentWorkspaceScreen();
                 Workspace workspace = (Workspace) target;
                 CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen);
-                ItemInfo itemInfo = (ItemInfo) dragInfo;
+                ItemInfo itemInfo = (ItemInfo) d.dragInfo;
                 if (layout != null) {
                     layout.calculateSpans(itemInfo);
                     showOutOfSpaceMessage =
@@ -780,6 +784,34 @@
         return mContentWidth;
     }
 
+    @Override
+    protected void onPageBeginMoving() {
+        /* TO BE ENABLED LATER
+        setChildrenDrawnWithCacheEnabled(true);
+        for (int i = 0; i < getChildCount(); ++i) {
+            View v = getChildAt(i);
+            if (v instanceof PagedViewCellLayout) {
+                ((PagedViewCellLayout) v).setChildrenDrawingCacheEnabled(true);
+            }
+        }
+        */
+        super.onPageBeginMoving();
+    }
+
+    @Override
+    protected void onPageEndMoving() {
+        /* TO BE ENABLED LATER
+        for (int i = 0; i < getChildCount(); ++i) {
+            View v = getChildAt(i);
+            if (v instanceof PagedViewCellLayout) {
+                ((PagedViewCellLayout) v).setChildrenDrawingCacheEnabled(false);
+            }
+        }
+        setChildrenDrawnWithCacheEnabled(false);
+        */
+        super.onPageEndMoving();
+    }
+
     /*
      * AllAppsView implementation
      */
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index eb92d20..e5aa7a9 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -16,8 +16,6 @@
 
 package com.android.launcher2;
 
-import java.util.Arrays;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
@@ -49,6 +47,8 @@
 
 import com.android.launcher.R;
 
+import java.util.Arrays;
+
 public class CellLayout extends ViewGroup {
     static final String TAG = "CellLayout";
 
@@ -167,24 +167,22 @@
 
         final Resources res = getResources();
 
-        if (LauncherApplication.isScreenLarge()) {
-            mNormalBackground = res.getDrawable(R.drawable.homescreen_large_blue);
-            mActiveBackground = res.getDrawable(R.drawable.homescreen_large_green);
-            mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_large_green_strong);
+        mNormalBackground = res.getDrawable(R.drawable.homescreen_large_blue);
+        mActiveBackground = res.getDrawable(R.drawable.homescreen_large_green);
+        mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_large_green_strong);
 
-            mNormalBackgroundMini = res.getDrawable(R.drawable.homescreen_small_blue);
-            mNormalGlowBackgroundMini = res.getDrawable(R.drawable.homescreen_small_blue_strong);
-            mActiveBackgroundMini = res.getDrawable(R.drawable.homescreen_small_green);
-            mActiveGlowBackgroundMini = res.getDrawable(R.drawable.homescreen_small_green_strong);
+        mNormalBackgroundMini = res.getDrawable(R.drawable.homescreen_small_blue);
+        mNormalGlowBackgroundMini = res.getDrawable(R.drawable.homescreen_small_blue_strong);
+        mActiveBackgroundMini = res.getDrawable(R.drawable.homescreen_small_green);
+        mActiveGlowBackgroundMini = res.getDrawable(R.drawable.homescreen_small_green_strong);
 
-            mNormalBackground.setFilterBitmap(true);
-            mActiveBackground.setFilterBitmap(true);
-            mActiveGlowBackground.setFilterBitmap(true);
-            mNormalBackgroundMini.setFilterBitmap(true);
-            mNormalGlowBackgroundMini.setFilterBitmap(true);
-            mActiveBackgroundMini.setFilterBitmap(true);
-            mActiveGlowBackgroundMini.setFilterBitmap(true);
-        }
+        mNormalBackground.setFilterBitmap(true);
+        mActiveBackground.setFilterBitmap(true);
+        mActiveGlowBackground.setFilterBitmap(true);
+        mNormalBackgroundMini.setFilterBitmap(true);
+        mNormalGlowBackgroundMini.setFilterBitmap(true);
+        mActiveBackgroundMini.setFilterBitmap(true);
+        mActiveGlowBackgroundMini.setFilterBitmap(true);
 
         // Initialize the data structures used for the drag visualization.
 
@@ -383,35 +381,33 @@
     }
 
     void animateDrop() {
-        if (LauncherApplication.isScreenLarge()) {
-            Resources res = getResources();
-            float onDropScale = res.getInteger(R.integer.config_screenOnDropScalePercent) / 100.0f;
-            ObjectAnimator scaleUp = ObjectAnimator.ofFloat(this, "hoverScale", onDropScale);
-            scaleUp.setDuration(res.getInteger(R.integer.config_screenOnDropScaleUpDuration));
-            ObjectAnimator scaleDown = ObjectAnimator.ofFloat(this, "hoverScale", 1.0f);
-            scaleDown.setDuration(res.getInteger(R.integer.config_screenOnDropScaleDownDuration));
-            ObjectAnimator alphaFadeOut = ObjectAnimator.ofFloat(this, "hoverAlpha", 0.0f);
+        Resources res = getResources();
+        float onDropScale = res.getInteger(R.integer.config_screenOnDropScalePercent) / 100.0f;
+        ObjectAnimator scaleUp = ObjectAnimator.ofFloat(this, "hoverScale", onDropScale);
+        scaleUp.setDuration(res.getInteger(R.integer.config_screenOnDropScaleUpDuration));
+        ObjectAnimator scaleDown = ObjectAnimator.ofFloat(this, "hoverScale", 1.0f);
+        scaleDown.setDuration(res.getInteger(R.integer.config_screenOnDropScaleDownDuration));
+        ObjectAnimator alphaFadeOut = ObjectAnimator.ofFloat(this, "hoverAlpha", 0.0f);
 
-            alphaFadeOut.setStartDelay(res.getInteger(R.integer.config_screenOnDropAlphaFadeDelay));
-            alphaFadeOut.setDuration(res.getInteger(R.integer.config_screenOnDropAlphaFadeDelay));
+        alphaFadeOut.setStartDelay(res.getInteger(R.integer.config_screenOnDropAlphaFadeDelay));
+        alphaFadeOut.setDuration(res.getInteger(R.integer.config_screenOnDropAlphaFadeDuration));
 
-            AnimatorSet bouncer = new AnimatorSet();
-            bouncer.play(scaleUp).before(scaleDown);
-            bouncer.play(scaleUp).with(alphaFadeOut);
-            bouncer.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    setIsDragOverlapping(true);
-                }
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    setIsDragOverlapping(false);
-                    setHoverScale(1.0f);
-                    setHoverAlpha(1.0f);
-                }
-            });
-            bouncer.start();
-        }
+        AnimatorSet bouncer = new AnimatorSet();
+        bouncer.play(scaleUp).before(scaleDown);
+        bouncer.play(scaleUp).with(alphaFadeOut);
+        bouncer.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                setIsDragOverlapping(true);
+            }
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                setIsDragOverlapping(false);
+                setHoverScale(1.0f);
+                setHoverAlpha(1.0f);
+            }
+        });
+        bouncer.start();
     }
 
     @Override
@@ -421,7 +417,7 @@
         // When we're small, we are either drawn normally or in the "accepts drops" state (during
         // a drag). However, we also drag the mini hover background *over* one of those two
         // backgrounds
-        if (LauncherApplication.isScreenLarge() && mBackgroundAlpha > 0.0f) {
+        if (mBackgroundAlpha > 0.0f) {
             Drawable bg;
             boolean mini = getScaleX() < 0.5f;
 
@@ -1150,12 +1146,12 @@
         // re-mark space taken by ignoreView as occupied
         markCellsAsOccupiedForView(ignoreView);
 
-        // Return null if no suitable location found
-        if (bestDistance < Double.MAX_VALUE) {
-            return bestXY;
-        } else {
-            return null;
+        // Return -1, -1 if no suitable location found
+        if (bestDistance == Double.MAX_VALUE) {
+            bestXY[0] = -1;
+            bestXY[1] = -1;
         }
+        return bestXY;
     }
 
     /**
diff --git a/src/com/android/launcher2/CustomizePagedView.java b/src/com/android/launcher2/CustomizePagedView.java
index 932af89..b2a7603 100644
--- a/src/com/android/launcher2/CustomizePagedView.java
+++ b/src/com/android/launcher2/CustomizePagedView.java
@@ -16,10 +16,6 @@
 
 package com.android.launcher2;
 
-import com.android.launcher.R;
-
-import org.xmlpull.v1.XmlPullParser;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
@@ -54,7 +50,6 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
-import android.view.View.MeasureSpec;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.LinearInterpolator;
 import android.widget.Checkable;
@@ -62,6 +57,11 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import com.android.launcher.R;
+import com.android.launcher2.DropTarget.DragObject;
+
+import org.xmlpull.v1.XmlPullParser;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -402,7 +402,7 @@
         }
     }
 
-    public void onDropCompleted(View target, Object dragInfo, boolean success) {
+    public void onDropCompleted(View target, DragObject d, 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
@@ -413,7 +413,7 @@
 
         if (success) {
             resetCheckedItem(true);
-            animateDropOntoScreen(animView, (ItemInfo) dragInfo, DROP_ANIM_DURATION, 0);
+            animateDropOntoScreen(animView, (ItemInfo) d.dragInfo, DROP_ANIM_DURATION, 0);
         } else {
             // Animate the icon/widget back to its original position
             animateIntoPosition(animView, mDragViewOrigin[0], mDragViewOrigin[1], new Runnable() {
diff --git a/src/com/android/launcher2/DeleteDropTarget.java b/src/com/android/launcher2/DeleteDropTarget.java
index 5c67793..4986a31 100644
--- a/src/com/android/launcher2/DeleteDropTarget.java
+++ b/src/com/android/launcher2/DeleteDropTarget.java
@@ -126,7 +126,7 @@
     public void onDragExit(DragObject d) {
         super.onDragExit(d);
 
-        mIcon.reverseTransition(sTransitionDuration);
+        mIcon.resetTransition();
         setTextColor(mDefaultTextColor);
     }
 
diff --git a/src/com/android/launcher2/DeleteZone.java b/src/com/android/launcher2/DeleteZone.java
index c349e5d..025b292 100644
--- a/src/com/android/launcher2/DeleteZone.java
+++ b/src/com/android/launcher2/DeleteZone.java
@@ -33,7 +33,6 @@
 import android.view.animation.AccelerateInterpolator;
 
 import com.android.launcher.R;
-import com.android.launcher2.DropTarget.DragObject;
 
 public class DeleteZone extends IconDropTarget {
     private static final int ORIENTATION_HORIZONTAL = 1;
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index 1690cac..8ad5c7c 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -16,8 +16,6 @@
 
 package com.android.launcher2;
 
-import java.util.ArrayList;
-
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
@@ -35,7 +33,8 @@
 import android.view.inputmethod.InputMethodManager;
 
 import com.android.launcher.R;
-import com.android.launcher2.DropTarget.DragObject;
+
+import java.util.ArrayList;
 
 /**
  * Class for initiating a drag within a view or across multiple views.
@@ -374,7 +373,7 @@
     public void cancelDrag() {
         if (mDragging) {
             // Should we also be calling onDragExit() here?
-            mDragObject.dragSource.onDropCompleted(null, mDragObject.dragInfo, false);
+            mDragObject.dragSource.onDropCompleted(null, mDragObject, false);
         }
         endDrag();
     }
@@ -572,8 +571,7 @@
                 accepted = true;
             }
         }
-        mDragObject.dragSource.onDropCompleted((View) dropTarget, mDragObject.dragInfo, accepted);
-
+        mDragObject.dragSource.onDropCompleted((View) dropTarget, mDragObject, accepted);
     }
 
     private DropTarget findDropTarget(int x, int y, int[] dropCoordinates) {
diff --git a/src/com/android/launcher2/DragSource.java b/src/com/android/launcher2/DragSource.java
index 649120d..2a8f263 100644
--- a/src/com/android/launcher2/DragSource.java
+++ b/src/com/android/launcher2/DragSource.java
@@ -18,6 +18,8 @@
 
 import android.view.View;
 
+import com.android.launcher2.DropTarget.DragObject;
+
 /**
  * Interface defining an object that can originate a drag.
  *
@@ -29,5 +31,5 @@
      */
     void onDragViewVisible();
 
-    void onDropCompleted(View target, Object dragInfo, boolean success);
+    void onDropCompleted(View target, DragObject d, boolean success);
 }
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index 0b35acb..08907c9 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -16,8 +16,6 @@
 
 package com.android.launcher2;
 
-import java.util.ArrayList;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
@@ -43,6 +41,8 @@
 import com.android.launcher.R;
 import com.android.launcher2.FolderInfo.FolderListener;
 
+import java.util.ArrayList;
+
 /**
  * Represents a set of icons chosen by the user or generated by the system.
  */
@@ -448,7 +448,7 @@
         return r;
     }
 
-    public void onDropCompleted(View target, Object dragInfo, boolean success) {
+    public void onDropCompleted(View target, DragObject d, boolean success) {
     }
 
     public boolean isDropEnabled() {
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
index 952d704..449068c 100644
--- a/src/com/android/launcher2/FolderIcon.java
+++ b/src/com/android/launcher2/FolderIcon.java
@@ -16,8 +16,6 @@
 
 package com.android.launcher2;
 
-import java.util.ArrayList;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
@@ -36,12 +34,15 @@
 import android.widget.TextView;
 
 import com.android.launcher.R;
+import com.android.launcher2.DropTarget.DragObject;
 import com.android.launcher2.FolderInfo.FolderListener;
 
+import java.util.ArrayList;
+
 /**
  * An icon that can appear on in the workspace representing an {@link UserFolder}.
  */
-public class FolderIcon extends FrameLayout implements DropTarget, FolderListener {
+public class FolderIcon extends FrameLayout implements FolderListener {
     private Launcher mLauncher;
     Folder mFolder;
     FolderInfo mInfo;
@@ -63,7 +64,7 @@
     private static final float OUTER_RING_GROWTH_FACTOR = 0.3f;
 
     // The amount of vertical spread between items in the stack [0...1]
-    private static final float PERSPECTIVE_SHIFT_FACTOR = 0.18f;
+    private static final float PERSPECTIVE_SHIFT_FACTOR = 0.3f;
 
     // The degree to which the item in the back of the stack is scaled [0...1]
     // (0 means it's not scaled at all, 1 means it's scaled to nothing)
@@ -72,9 +73,6 @@
     // The percentage of the FolderIcons view that will be dedicated to the items preview
     private static final float SPACE_PERCENTAGE_FOR_ICONS = 0.8f;
 
-    public static Drawable sFolderOuterRingDrawable = null;
-    public static Drawable sFolderInnerRingDrawable = null;
-
     private int mOriginalWidth = -1;
     private int mOriginalHeight = -1;
 
@@ -127,29 +125,43 @@
         public float mInnerRingScale;
         public FolderIcon mFolderIcon = null;
         private Launcher mLauncher;
+        public Drawable mOuterRingDrawable = null;
+        public Drawable mInnerRingDrawable = null;
+        public static Drawable sSharedOuterRingDrawable = null;
+        public static Drawable sSharedInnerRingDrawable = null;
+        private ValueAnimator mAcceptAnimator;
+        private ValueAnimator mNeutralAnimator;
 
         public FolderRingAnimator(Launcher launcher, FolderIcon folderIcon) {
             mLauncher = launcher;
             mFolderIcon = folderIcon;
-            if (sFolderOuterRingDrawable == null) {
-                sFolderOuterRingDrawable =
+            mOuterRingDrawable =
+                    launcher.getResources().getDrawable(R.drawable.portal_ring_outer_holo);
+            mInnerRingDrawable =
+                    launcher.getResources().getDrawable(R.drawable.portal_ring_inner_holo);
+            if (sSharedOuterRingDrawable == null) {
+                sSharedOuterRingDrawable =
                         launcher.getResources().getDrawable(R.drawable.portal_ring_outer_holo);
             }
-            if (sFolderInnerRingDrawable == null) {
-                sFolderInnerRingDrawable =
+            if (sSharedInnerRingDrawable == null) {
+                sSharedInnerRingDrawable =
                         launcher.getResources().getDrawable(R.drawable.portal_ring_inner_holo);
             }
         }
 
+        // Location is expressed in window coordinates
         public void setLocation(int x, int y) {
             mFolderLocX = x;
             mFolderLocY = y;
         }
 
         public void animateToAcceptState() {
-            ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
-            va.setDuration(CONSUMPTION_ANIMATION_DURATION);
-            va.addUpdateListener(new AnimatorUpdateListener() {
+            if (mNeutralAnimator != null) {
+                mNeutralAnimator.cancel();
+            }
+            mAcceptAnimator = ValueAnimator.ofFloat(0f, 1f);
+            mAcceptAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
+            mAcceptAnimator.addUpdateListener(new AnimatorUpdateListener() {
                 public void onAnimationUpdate(ValueAnimator animation) {
                     final float percent = (Float) animation.getAnimatedValue();
                     mOuterRingScale = OUTER_RING_BASELINE_SCALE + percent * OUTER_RING_GROWTH_FACTOR;
@@ -160,25 +172,24 @@
                     }
                 }
             });
-            va.addListener(new AnimatorListenerAdapter() {
+            mAcceptAnimator.addListener(new AnimatorListenerAdapter() {
                 @Override
-                public void onAnimationEnd(Animator animation) {
-                    // Instead of setting the background drawable to null, we set the color to
-                    // transparent. Setting the background drawable to null results in onDraw
-                    // not getting called.
+                public void onAnimationStart(Animator animation) {
                     if (mFolderIcon != null) {
-                        mFolderIcon.setBackgroundColor(Color.TRANSPARENT);
-                        mFolderIcon.requestLayout();
+                        mFolderIcon.setBackgroundDrawable(null);
                     }
                 }
             });
-            va.start();
+            mAcceptAnimator.start();
         }
 
         public void animateToNaturalState() {
-            ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
-            va.setDuration(CONSUMPTION_ANIMATION_DURATION);
-            va.addUpdateListener(new AnimatorUpdateListener() {
+            if (mAcceptAnimator != null) {
+                mAcceptAnimator.cancel();
+            }
+            mNeutralAnimator = ValueAnimator.ofFloat(0f, 1f);
+            mNeutralAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
+            mNeutralAnimator.addUpdateListener(new AnimatorUpdateListener() {
                 public void onAnimationUpdate(ValueAnimator animation) {
                     final float percent = (Float) animation.getAnimatedValue();
                     mOuterRingScale = OUTER_RING_BASELINE_SCALE + OUTER_RING_GROWTH_FACTOR
@@ -191,18 +202,19 @@
                     }
                 }
             });
-            va.addListener(new AnimatorListenerAdapter() {
+            mNeutralAnimator.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
                     if (mFolderIcon != null) {
-                        mFolderIcon.setBackgroundDrawable(sFolderInnerRingDrawable);
+                        mFolderIcon.setBackgroundDrawable(mInnerRingDrawable);
                     }
                     mLauncher.getWorkspace().hideFolderAccept(FolderRingAnimator.this);
                 }
             });
-            va.start();
+            mNeutralAnimator.start();
         }
 
+        // Location is expressed in window coordinates
         public void getLocation(int[] loc) {
             loc[0] = mFolderLocX;
             loc[1] = mFolderLocY;
@@ -224,8 +236,8 @@
                 !mFolder.isFull() && item != mInfo);
     }
 
-    public boolean acceptDrop(DragObject d) {
-        final ItemInfo item = (ItemInfo) d.dragInfo;
+    public boolean acceptDrop(Object dragInfo) {
+        final ItemInfo item = (ItemInfo) dragInfo;
         return willAcceptItem(item);
     }
 
@@ -234,19 +246,6 @@
         LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
     }
 
-    public void onDrop(DragObject d) {
-        ShortcutInfo item;
-        if (d.dragInfo instanceof ApplicationInfo) {
-            // Came from all apps -- make a copy
-            item = ((ApplicationInfo) d.dragInfo).makeShortcut();
-        } else {
-            item = (ShortcutInfo) d.dragInfo;
-        }
-        item.cellX = -1;
-        item.cellY = -1;
-        addItem(item);
-    }
-
     void saveState(CellLayout.LayoutParams lp) {
         mOriginalWidth = lp.width;
         mOriginalHeight = lp.height;
@@ -255,35 +254,48 @@
     private void determineFolderLocationInWorkspace() {
         int tvLocation[] = new int[2];
         int wsLocation[] = new int[2];
-        getLocationOnScreen(tvLocation);
-        mLauncher.getWorkspace().getLocationOnScreen(wsLocation);
+        getLocationInWindow(tvLocation);
+        mLauncher.getWorkspace().getLocationInWindow(wsLocation);
 
         int x = tvLocation[0] - wsLocation[0] + getMeasuredWidth() / 2;
         int y = tvLocation[1] - wsLocation[1] + getMeasuredHeight() / 2;
         mFolderRingAnimator.setLocation(x, y);
     }
 
-    public void onDragEnter(DragObject d) {
-        if (!willAcceptItem((ItemInfo) d.dragInfo)) return;
+    public void onDragEnter(Object dragInfo) {
+        if (!willAcceptItem((ItemInfo) dragInfo)) return;
         determineFolderLocationInWorkspace();
         mLauncher.getWorkspace().showFolderAccept(mFolderRingAnimator);
         mFolderRingAnimator.animateToAcceptState();
     }
 
-    public void onDragOver(DragObject d) {
+    public void onDragOver(Object dragInfo) {
     }
 
-    public void onDragExit(DragObject d) {
-        if (!willAcceptItem((ItemInfo) d.dragInfo)) return;
+    public void onDragExit(Object dragInfo) {
+        if (!willAcceptItem((ItemInfo) dragInfo)) return;
         mFolderRingAnimator.animateToNaturalState();
     }
 
+    public void onDrop(Object dragInfo) {
+        ShortcutInfo item;
+        if (dragInfo instanceof ApplicationInfo) {
+            // Came from all apps -- make a copy
+            item = ((ApplicationInfo) dragInfo).makeShortcut();
+        } else {
+            item = (ShortcutInfo) dragInfo;
+        }
+        item.cellX = -1;
+        item.cellY = -1;
+        addItem(item);
+    }
+
     public DropTarget getDropTargetDelegate(DragObject d) {
         return null;
     }
 
     @Override
-    protected void onDraw(Canvas canvas) {
+    protected void dispatchDraw(Canvas canvas) {
         if (mFolder == null) return;
         if (mFolder.getItemCount() == 0) return;
 
@@ -337,7 +349,6 @@
             }
             canvas.restore();
         }
-
         canvas.restore();
     }
 
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index eb533fe..6279b78 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -17,14 +17,6 @@
 
 package com.android.launcher2;
 
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
@@ -107,6 +99,14 @@
 import com.android.launcher.R;
 import com.android.launcher2.Workspace.ShrinkState;
 
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
 /**
  * Default launcher application.
  */
@@ -168,7 +168,7 @@
 
     /** The different states that Launcher can be in. */
     private enum State { WORKSPACE, APPS_CUSTOMIZE, ALL_APPS, CUSTOMIZE,
-        CUSTOMIZE_SPRING_LOADED, ALL_APPS_SPRING_LOADED };
+        APPS_CUSTOMIZE_SPRING_LOADED };
     private State mState = State.WORKSPACE;
     private AnimatorSet mStateAnimation;
 
@@ -1495,6 +1495,11 @@
     public void onDestroy() {
         super.onDestroy();
 
+        // Stop callbacks from LauncherModel
+        LauncherApplication app = ((LauncherApplication) getApplication());
+        mModel.stopLoader();
+        app.setLauncher(null);
+
         try {
             mAppWidgetHost.stopListening();
         } catch (NullPointerException ex) {
@@ -1506,7 +1511,6 @@
 
         TextKeyListener.getInstance().release();
 
-        mModel.stopLoader();
 
         unbindDesktopItems();
 
@@ -2667,7 +2671,16 @@
         setPivotsForZoom(toView, toState, scale);
 
         if (toAllApps) {
-            if (!springLoaded) {
+            if (springLoaded) {
+                if (toState == State.APPS_CUSTOMIZE) {
+                    // Shrink workspaces away if going back to AppsCustomize from spring loaded mode
+                    mWorkspace.shrink(ShrinkState.BOTTOM_HIDDEN, animated);
+                } else {
+                    // Shrink workspaces to bottom if going back to AllApps from spring loaded mode
+                    mWorkspace.shrink(ShrinkState.BOTTOM_VISIBLE, animated);
+                }
+            } else {
+                // Shrink workspaces away if going to AllApps/AppsCustomize from workspace
                 mWorkspace.shrink(ShrinkState.BOTTOM_HIDDEN, animated);
 
                 if (LauncherApplication.isScreenLarge()) {
@@ -2675,10 +2688,9 @@
                     // controls when it should hide/show the mini workspaces
                     mAllAppsPagedView.resetSuccessfulDropFlag();
                 }
-            } else {
-                mWorkspace.shrink(ShrinkState.BOTTOM_VISIBLE, animated);
             }
         } else {
+            // In Customize mode, shrink the workspaces to the top
             mWorkspace.shrink(ShrinkState.TOP, animated);
         }
 
@@ -2897,39 +2909,25 @@
     }
 
     void enterSpringLoadedDragMode(CellLayout layout) {
+        // Enter spring loaded mode on a new layout
         mWorkspace.enterSpringLoadedDragMode(layout);
-        if (mState == State.ALL_APPS || mState == State.APPS_CUSTOMIZE) {
-            mState = State.ALL_APPS_SPRING_LOADED;
-            if (LauncherApplication.isScreenLarge()) {
-                cameraZoomIn(State.ALL_APPS, true, true);
-            } else {
-                cameraZoomIn(State.APPS_CUSTOMIZE, true, true);
-            }
-        } else if (mState == State.CUSTOMIZE) {
-            mState = State.CUSTOMIZE_SPRING_LOADED;
-            cameraZoomIn(State.CUSTOMIZE, true, true);
-        }/* else {
-            // we're already in spring loaded mode; don't do anything
-        }*/
+
+        if (mState == State.APPS_CUSTOMIZE) {
+            mState = State.APPS_CUSTOMIZE_SPRING_LOADED;
+            cameraZoomIn(State.APPS_CUSTOMIZE, true, true);
+        } else {
+            // Do nothing
+        }
     }
 
     void exitSpringLoadedDragMode() {
-        if (mState == State.ALL_APPS_SPRING_LOADED) {
-            mWorkspace.exitSpringLoadedDragMode(Workspace.ShrinkState.BOTTOM_VISIBLE);
-            if (LauncherApplication.isScreenLarge()) {
-                cameraZoomOut(State.ALL_APPS, true, true);
-                mState = State.ALL_APPS;
-            } else {
-                cameraZoomOut(State.APPS_CUSTOMIZE, true, true);
-                mState = State.APPS_CUSTOMIZE;
-            }
-        } else if (mState == State.CUSTOMIZE_SPRING_LOADED) {
-            mWorkspace.exitSpringLoadedDragMode(Workspace.ShrinkState.TOP);
-            cameraZoomOut(State.CUSTOMIZE, true, true);
-            mState = State.CUSTOMIZE;
-        }/* else {
-            // we're not in spring loaded mode; don't do anything
-        }*/
+        if (mState == State.APPS_CUSTOMIZE_SPRING_LOADED) {
+            mWorkspace.exitSpringLoadedDragMode(Workspace.ShrinkState.BOTTOM_HIDDEN);
+            cameraZoomOut(State.APPS_CUSTOMIZE, true, true);
+            mState = State.APPS_CUSTOMIZE;
+        } else {
+            // Do nothing
+        }
     }
 
     void showAllApps(boolean animated) {
@@ -3001,7 +2999,7 @@
      */
     void closeAllApps(boolean animated) {
         if (LauncherApplication.isScreenLarge()) {
-            if (mState == State.ALL_APPS || mState == State.ALL_APPS_SPRING_LOADED) {
+            if (mState == State.ALL_APPS) {
                 mWorkspace.setVisibility(View.VISIBLE);
                 cameraZoomIn(State.ALL_APPS, animated, false);
 
@@ -3009,7 +3007,7 @@
                 findViewById(R.id.all_apps_button).requestFocus();
             }
         } else {
-            if (mState == State.APPS_CUSTOMIZE || mState == State.ALL_APPS_SPRING_LOADED) {
+            if (mState == State.APPS_CUSTOMIZE || mState == State.APPS_CUSTOMIZE_SPRING_LOADED) {
                 mWorkspace.setVisibility(View.VISIBLE);
                 cameraZoomIn(State.APPS_CUSTOMIZE, animated, false);
 
@@ -3045,7 +3043,7 @@
 
     // Hide the customization drawer (only exists in x-large configuration)
     void hideCustomizationDrawer(boolean animated) {
-        if (mState == State.CUSTOMIZE || mState == State.CUSTOMIZE_SPRING_LOADED) {
+        if (mState == State.CUSTOMIZE) {
             cameraZoomIn(State.CUSTOMIZE, animated, false);
 
             // Set focus to the customize button
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index d5505c5..7cfab2a 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -1301,7 +1301,8 @@
                 final ArrayList<ApplicationInfo> addedFinal = added;
                 mHandler.post(new Runnable() {
                     public void run() {
-                        if (callbacks == mCallbacks.get()) {
+                        Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
+                        if (callbacks == cb && cb != null) {
                             callbacks.bindAppsAdded(addedFinal);
                         }
                     }
@@ -1311,7 +1312,8 @@
                 final ArrayList<ApplicationInfo> modifiedFinal = modified;
                 mHandler.post(new Runnable() {
                     public void run() {
-                        if (callbacks == mCallbacks.get()) {
+                        Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
+                        if (callbacks == cb && cb != null) {
                             callbacks.bindAppsUpdated(modifiedFinal);
                         }
                     }
@@ -1322,7 +1324,8 @@
                 final ArrayList<ApplicationInfo> removedFinal = removed;
                 mHandler.post(new Runnable() {
                     public void run() {
-                        if (callbacks == mCallbacks.get()) {
+                        Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
+                        if (callbacks == cb && cb != null) {
                             callbacks.bindAppsRemoved(removedFinal, permanent);
                         }
                     }
@@ -1332,7 +1335,8 @@
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    if (callbacks == mCallbacks.get()) {
+                    Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
+                    if (callbacks == cb && cb != null) {
                         callbacks.bindPackagesUpdated();
                     }
                 }
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index 8ee3810..79f0d56 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -62,7 +62,7 @@
     private static final int PAGE_SNAP_ANIMATION_DURATION = 550;
     protected static final float NANOTIME_DIV = 1000000000.0f;
 
-    private static final float OVERSCROLL_DAMP_FACTOR = 0.08f;
+    private static final float OVERSCROLL_DAMP_FACTOR = 0.14f;
     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;
@@ -470,12 +470,18 @@
             childrenX[i] = child.getX();
             childrenY[i] = child.getY();
         }
-        onLayout(false, mLeft, mTop, mRight, mBottom);
+        // Trigger a full re-layout (never just call onLayout directly!)
+        int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY);
+        int heightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY);
+        requestLayout();
+        measure(widthSpec, heightSpec);
+        layout(mLeft, mTop, mRight, mBottom);
         for (int i = 0; i < childCount; i++) {
             final View child = getChildAt(i);
             child.setX(childrenX[i]);
             child.setY(childrenY[i]);
         }
+
         // Also, the page offset has changed  (since the pages are now smaller);
         // update the page offset, but again preserving absolute X and Y coordinates
         scrollToNewPageWithoutMovingPages(mCurrentPage);
diff --git a/src/com/android/launcher2/SmoothPagedView.java b/src/com/android/launcher2/SmoothPagedView.java
index 8b0a835..fe763f5 100644
--- a/src/com/android/launcher2/SmoothPagedView.java
+++ b/src/com/android/launcher2/SmoothPagedView.java
@@ -87,7 +87,7 @@
     }
 
     protected int getScrollMode() {
-        return DEFAULT_MODE;
+        return X_LARGE_MODE;
     }
 
     /**
diff --git a/src/com/android/launcher2/SpringLoadedDragController.java b/src/com/android/launcher2/SpringLoadedDragController.java
index 9007581..37a94d4 100644
--- a/src/com/android/launcher2/SpringLoadedDragController.java
+++ b/src/com/android/launcher2/SpringLoadedDragController.java
@@ -26,8 +26,6 @@
     // the screen the user is currently hovering over, if any
     private CellLayout mScreen;
     private Launcher mLauncher;
-    boolean mFinishedAnimation = false;
-    boolean mWaitingToReenter = false;
 
     public SpringLoadedDragController(Launcher launcher) {
         mLauncher = launcher;
@@ -35,35 +33,25 @@
         mAlarm.setOnAlarmListener(this);
     }
 
-    public void onDragEnter(CellLayout cl, boolean isSpringLoaded) {
+    public void cancel() {
+        mAlarm.cancelAlarm();
+    }
+
+    // Set a new alarm to expire for the screen that we are hovering over now
+    public void setAlarm(CellLayout cl) {
+        if (mScreen != cl) {
+            mAlarm.setAlarm(ENTER_SPRING_LOAD_HOVER_TIME);
+        }
         mScreen = cl;
-        mAlarm.setAlarm(ENTER_SPRING_LOAD_HOVER_TIME);
-        mFinishedAnimation = isSpringLoaded;
-        mWaitingToReenter = false;
-    }
-
-    public void onEnterSpringLoadedMode(boolean waitToReenter) {
-        mFinishedAnimation = true;
-        mWaitingToReenter = waitToReenter;
-    }
-
-    public void onDragExit() {
-        if (mScreen != null) {
-            mScreen.onDragExit();
-        }
-        mScreen = null;
-        if (mFinishedAnimation && !mWaitingToReenter) {
-            mAlarm.setAlarm(EXIT_SPRING_LOAD_HOVER_TIME);
-        }
     }
 
     // this is called when our timer runs out
     public void onAlarm(Alarm alarm) {
         if (mScreen != null) {
-            // we're currently hovering over a screen
-            mLauncher.enterSpringLoadedDragMode(mScreen);
-        } else {
-            mLauncher.exitSpringLoadedDragMode();
+            // Snap to the screen that we are hovering over now
+            Workspace w = mLauncher.getWorkspace();
+            int page = w.indexOfChild(mScreen);
+            w.snapToPage(page);
         }
     }
 }
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index e0472fc..fee6b5b 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -21,12 +21,12 @@
 import java.util.List;
 
 import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
-import android.animation.Animator.AnimatorListener;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.app.AlertDialog;
 import android.app.WallpaperManager;
@@ -52,6 +52,7 @@
 import android.os.IBinder;
 import android.os.Parcelable;
 import android.util.AttributeSet;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Pair;
 import android.view.Display;
@@ -80,9 +81,6 @@
     @SuppressWarnings({"UnusedDeclaration"})
     private static final String TAG = "Launcher.Workspace";
 
-    // How much the screens shrink when we enter spring loaded drag mode
-    private static final float SPRING_LOADED_DRAG_SHRINK_FACTOR = 0.7f;
-
     // Y rotation to apply to the workspace screens
     private static final float WORKSPACE_ROTATION = 12.5f;
 
@@ -136,7 +134,7 @@
     /**
      * Target drop area calculated during last acceptDrop call.
      */
-    private int[] mTargetCell = null;
+    private int[] mTargetCell = new int[2];
 
     /**
      * The CellLayout that is currently being dragged over
@@ -156,10 +154,12 @@
     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;
 
     private static final int DEFAULT_CELL_COUNT_X = 4;
     private static final int DEFAULT_CELL_COUNT_Y = 4;
@@ -175,7 +175,6 @@
     private AnimatorListener mUnshrinkAnimationListener;
     enum ShrinkState { TOP, SPRING_LOADED, MIDDLE, BOTTOM_HIDDEN, BOTTOM_VISIBLE };
     private ShrinkState mShrinkState;
-    private boolean mWasSpringLoadedOnDragExit = false;
     private boolean mWaitingToShrink = false;
     private ShrinkState mWaitingToShrinkState;
     private AnimatorSet mAnimator;
@@ -222,7 +221,7 @@
     private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>();
 
     // Variables relating to the creation of user folders by hovering shortcuts over shortcuts
-    private static final int FOLDER_CREATION_TIMEOUT = 400;
+    private static final int FOLDER_CREATION_TIMEOUT = 250;
     private final Alarm mFolderCreationAlarm = new Alarm();
     private FolderRingAnimator mDragFolderRingAnimator = null;
     private View mLastDragOverView = null;
@@ -270,12 +269,15 @@
         TypedArray a = context.obtainStyledAttributes(attrs,
                 R.styleable.Workspace, defStyle, 0);
 
+        final Resources res = context.getResources();
         if (LauncherApplication.isScreenLarge()) {
             // Determine number of rows/columns dynamically
             // 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 Resources res = context.getResources();
+            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 });
@@ -295,6 +297,9 @@
             }
         }
 
+        mSpringLoadedShrinkFactor =
+            res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f;
+
         // if the value is manually specified, use that instead
         cellCountX = a.getInt(R.styleable.Workspace_cellCountX, cellCountX);
         cellCountY = a.getInt(R.styleable.Workspace_cellCountY, cellCountY);
@@ -340,14 +345,7 @@
             public void onAnimationEnd(Animator animation) {
                 mIsInUnshrinkAnimation = false;
                 mSyncWallpaperOffsetWithScroll = true;
-                if (mShrinkState == ShrinkState.SPRING_LOADED) {
-                    View layout = null;
-                    if (mLastDragView != null) {
-                        layout = findMatchingPageForDragOver(mLastDragView, mLastDragOriginX,
-                                mLastDragOriginY, mLastDragXOffset, mLastDragYOffset);
-                    }
-                    mSpringLoadedDragController.onEnterSpringLoadedMode(layout == null);
-                } else {
+                if (mShrinkState != ShrinkState.SPRING_LOADED) {
                     mDrawCustomizeTrayBackground = false;
                 }
                 mWallpaperOffset.setOverrideHorizontalCatchupConstant(false);
@@ -372,11 +370,7 @@
 
     @Override
     protected int getScrollMode() {
-        if (LauncherApplication.isScreenLarge()) {
-            return SmoothPagedView.X_LARGE_MODE;
-        } else {
-            return SmoothPagedView.DEFAULT_MODE;
-        }
+        return SmoothPagedView.X_LARGE_MODE;
     }
 
     private void onAddView(View child) {
@@ -1232,29 +1226,63 @@
 
         // The folder outer / inner ring image(s)
         for (int i = 0; i < mFolderOuterRings.size(); i++) {
+            View currentPage = getChildAt(getCurrentPage());
+            Matrix m = currentPage.getMatrix();
 
             // Draw outer ring
             FolderRingAnimator fra = mFolderOuterRings.get(i);
-            Drawable d = FolderIcon.sFolderOuterRingDrawable;
+            Drawable d = FolderRingAnimator.sSharedOuterRingDrawable;
             int width = (int) (d.getIntrinsicWidth() * fra.getOuterRingScale());
             int height = (int) (d.getIntrinsicHeight() * fra.getOuterRingScale());
             fra.getLocation(mTempLocation);
-            int x = mTempLocation[0] + mScrollX - width / 2;
-            int y = mTempLocation[1] + mScrollY - height / 2;
-            d.setBounds(x, y, x + width, y + height);
+
+            // First we map the folder's location from window coordinates to its containing
+            // CellLayout's coordinates. Then we transform the coordinates according to the
+            // CellLayout's transform. Finally, we map this back into the coordinates of the
+            // the window (ie. Workspace).
+            int x = mTempLocation[0] + mScrollX - width / 2 - currentPage.getLeft();
+            int y = mTempLocation[1] + mScrollY - height / 2 - currentPage.getTop();
+            mTempFloatTuple[0] = x;
+            mTempFloatTuple[1] = y;
+            m.mapPoints(mTempFloatTuple);
+            x = (int) (mTempFloatTuple[0]) + currentPage.getLeft();
+            y = (int) (mTempFloatTuple[1]) + currentPage.getTop();
+
+            canvas.save();
+            canvas.translate(x, y);
+            d.setBounds(0, 0, (int) (width * currentPage.getScaleX()),
+                    (int) (height * currentPage.getScaleY()));
             d.draw(canvas);
+            canvas.restore();
 
             // Draw inner ring
             if (fra.mFolderIcon != null) {
-                int folderWidth = fra.mFolderIcon != null ? fra.mFolderIcon.getMeasuredWidth() : mCellWidth;
-                int folderHeight = fra.mFolderIcon != null ? fra.mFolderIcon.getMeasuredWidth() : mCellHeight;
-                d = FolderIcon.sFolderInnerRingDrawable;
+                int folderWidth = fra.mFolderIcon != null ?
+                        fra.mFolderIcon.getMeasuredWidth() : mCellWidth;
+                int folderHeight = fra.mFolderIcon != null ?
+                        fra.mFolderIcon.getMeasuredWidth() : mCellHeight;
+                d = FolderRingAnimator.sSharedInnerRingDrawable;
                 width = (int) (folderWidth * fra.getInnerRingScale());
                 height = (int) (folderHeight * fra.getInnerRingScale());
-                x = mTempLocation[0] + mScrollX - width / 2;
-                y = mTempLocation[1] + mScrollY - height / 2;
-                d.setBounds(x, y, x + width, y + height);
+
+                // First we map the folder's location from window coordinates to its containing
+                // CellLayout's coordinates. Then we transform the coordinates according to the
+                // CellLayout's transform. Finally, we map this back into the coordinates of the
+                // the window (ie. Workspace).
+                x = mTempLocation[0] + mScrollX - width / 2 - currentPage.getLeft();
+                y = mTempLocation[1] + mScrollY - height / 2 - currentPage.getTop();
+                mTempFloatTuple[0] = x;
+                mTempFloatTuple[1] = y;
+                m.mapPoints(mTempFloatTuple);
+                x = (int) (mTempFloatTuple[0]) + currentPage.getLeft();
+                y = (int) (mTempFloatTuple[1]) + currentPage.getTop();
+
+                canvas.save();
+                canvas.translate(x, y);
+                d.setBounds(0, 0, (int) (width * currentPage.getScaleX()),
+                        (int) (height * currentPage.getScaleY()));
                 d.draw(canvas);
+                canvas.restore();
             }
         }
         super.onDraw(canvas);
@@ -1867,7 +1895,7 @@
         mLastDragView = null;
         // In the success case, DragController has already called onDragExit()
         if (!success) {
-            doDragExit();
+            doDragExit(null);
         }
         mIsDragInProcess = false;
         updateWhichPagesAcceptDrops(mShrinkState);
@@ -1882,7 +1910,7 @@
         int newCurrentPage = indexOfChild(clThatWasClicked);
         if (mIsSmall) {
             if (springLoaded) {
-                setLayoutScale(SPRING_LOADED_DRAG_SHRINK_FACTOR);
+                setLayoutScale(mSpringLoadedShrinkFactor);
             }
             scrollToNewPageWithoutMovingPages(newCurrentPage);
             unshrink(true, springLoaded);
@@ -1893,13 +1921,17 @@
     public void enterSpringLoadedDragMode(CellLayout clThatWasClicked) {
         mShrinkState = ShrinkState.SPRING_LOADED;
         unshrink(clThatWasClicked, true);
+        mDragTargetLayout = getCurrentDropLayout();
         mDragTargetLayout.onDragEnter();
+        mDragTargetLayout.setIsDragOverlapping(true);
+        showOutlines();
     }
 
     public void exitSpringLoadedDragMode(ShrinkState shrinkState) {
         shrink(shrinkState);
         if (mDragTargetLayout != null) {
             mDragTargetLayout.onDragExit();
+            mDragTargetLayout = null;
         }
     }
 
@@ -1918,7 +1950,7 @@
             float finalScaleFactor = 1.0f;
             float finalBackgroundAlpha = 0.0f;
             if (springLoaded) {
-                finalScaleFactor = SPRING_LOADED_DRAG_SHRINK_FACTOR;
+                finalScaleFactor = mSpringLoadedShrinkFactor;
                 finalBackgroundAlpha = 1.0f;
             } else {
                 mIsSmall = false;
@@ -1966,9 +1998,7 @@
                     // alpha.  See screenScrolled().
                     finalAlphaValue = 1f;
                 }
-                float finalAlphaMultiplierValue =
-                        ((i == mCurrentPage) && (mShrinkState != ShrinkState.SPRING_LOADED)) ?
-                        0.0f : 1.0f;
+                float finalAlphaMultiplierValue = 1f;
 
                 float translation = 0f;
 
@@ -2407,42 +2437,29 @@
         return true;
     }
 
-    boolean willCreateUserFolder(ItemInfo info, CellLayout target, int originX, int originY) {
-        mTargetCell = findNearestArea(originX, originY, 1, 1, target, mTargetCell);
-
-        View v = target.getChildAt(mTargetCell[0], mTargetCell[1]);
-        boolean hasntMoved = mDragInfo != null && (mDragInfo.cellX == mTargetCell[0] &&
-                mDragInfo.cellY == mTargetCell[1]);
+    boolean willCreateUserFolder(ItemInfo info, View v, int[] targetCell) {
+        boolean hasntMoved = mDragInfo != null
+                && (mDragInfo.cellX == targetCell[0] && mDragInfo.cellY == targetCell[1]);
 
         if (v == null || hasntMoved) return false;
 
         boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo);
         boolean willBecomeShortcut =
-            (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
-            info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT);
+                (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
+                info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT);
 
         return (aboveShortcut && willBecomeShortcut);
     }
 
-    boolean createUserFolderIfNecessary(View newView, CellLayout target, int originX,
-            int originY, boolean external) {
-        int spanX = mDragInfo != null ? mDragInfo.spanX : 1;
-        int spanY = mDragInfo != null ? mDragInfo.spanY : 1;
-
-        // First we find the cell nearest to point at which the item is dropped, without
-        // any consideration to whether there is an item there.
-        mTargetCell = findNearestArea(originX, originY,
-                spanX, spanY, target,
-                mTargetCell);
-
-        View v = target.getChildAt(mTargetCell[0], mTargetCell[1]);
-        boolean hasntMoved = mDragInfo != null && (mDragInfo.cellX == mTargetCell[0] &&
-                mDragInfo.cellY == mTargetCell[1]);
+    boolean createUserFolderIfNecessary(View newView, CellLayout target,
+            int[] targetCell, boolean external) {
+        View v = target.getChildAt(targetCell[0], targetCell[1]);
+        boolean hasntMoved = mDragInfo != null
+                && (mDragInfo.cellX == targetCell[0] && mDragInfo.cellY == targetCell[1]);
 
         if (v == null || hasntMoved || !mCreateUserFolderOnDrop) return false;
         mCreateUserFolderOnDrop = false;
-        final int screen = (mTargetCell == null) ?
-                mDragInfo.screen : indexOfChild(target);
+        final int screen = (targetCell == null) ? mDragInfo.screen : indexOfChild(target);
 
         boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo);
         boolean willBecomeShortcut = (newView.getTag() instanceof ShortcutInfo);
@@ -2458,7 +2475,7 @@
             }
 
             target.removeView(v);
-            FolderIcon fi = mLauncher.addFolder(screen, mTargetCell[0], mTargetCell[1]);
+            FolderIcon fi = mLauncher.addFolder(screen, targetCell[0], targetCell[1]);
             destInfo.cellX = -1;
             destInfo.cellY = -1;
             sourceInfo.cellX = -1;
@@ -2470,6 +2487,26 @@
         return false;
     }
 
+    boolean addToExistingFolderIfNecessary(View newView, CellLayout target, int[] tagetCell,
+            Object dragInfo, boolean external) {
+        View dropOverView = target.getChildAt(tagetCell[0], tagetCell[1]);
+        if (dropOverView instanceof FolderIcon) {
+            FolderIcon fi = (FolderIcon) dropOverView;
+            if (fi.acceptDrop(dragInfo)) {
+                fi.onDrop(dragInfo);
+
+                // if the drag started here, we need to remove it from the workspace
+                if (!external) {
+                    int fromScreen = mDragInfo.screen;
+                    CellLayout sourceLayout = (CellLayout) getChildAt(fromScreen);
+                    sourceLayout.removeView(newView);
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
     public void onDrop(DragObject d) {
 
         mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView,
@@ -2518,13 +2555,25 @@
 
             if (dropTargetLayout != null) {
                 // Move internally
-                final int screen = (mTargetCell == null) ?
+                final int screen = (mTargetCell[0] < 0) ?
                         mDragInfo.screen : indexOfChild(dropTargetLayout);
 
-                // If the item being dropped is a shortcut and the nearest drop cell also contains
+                int spanX = mDragInfo != null ? mDragInfo.spanX : 1;
+                int spanY = mDragInfo != null ? mDragInfo.spanY : 1;
+                // First we find the cell nearest to point at which the item is
+                // dropped, without any consideration to whether there is an item there.
+                mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], (int)
+                        mDragViewVisualCenter[1], spanX, spanY, dropTargetLayout, mTargetCell);
+                // If the item being dropped is a shortcut and the nearest drop
+                // cell also contains
                 // a shortcut, then create a folder with the two shortcuts.
                 if (!dropInscrollArea && createUserFolderIfNecessary(cell, dropTargetLayout,
-                        (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], false)) {
+                        mTargetCell, false)) {
+                    return;
+                }
+
+                if (addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell,
+                        d.dragInfo, false)) {
                     return;
                 }
 
@@ -2538,12 +2587,12 @@
                     snapToPage(screen);
                 }
 
-                if (mTargetCell != null) {
+                if (mTargetCell[0] >= 0 && mTargetCell[1] >= 0) {
                     if (screen != mDragInfo.screen) {
                         // Reparent the view
                         ((CellLayout) getChildAt(mDragInfo.screen)).removeView(cell);
-                        addInScreen(cell, screen, mTargetCell[0], mTargetCell[1],
-                                mDragInfo.spanX, mDragInfo.spanY);
+                        addInScreen(cell, screen, mTargetCell[0], mTargetCell[1], mDragInfo.spanX,
+                                mDragInfo.spanY);
                     }
 
                     // update the item's position after drop
@@ -2565,10 +2614,9 @@
                         if (pinfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) {
                             final Runnable resizeRunnable = new Runnable() {
                                 public void run() {
-                                    DragLayer dragLayer = (DragLayer)
-                                            mLauncher.findViewById(R.id.drag_layer);
-                                    dragLayer.addResizeFrame(info, hostView,
-                                            cellLayout);
+                                    DragLayer dragLayer =
+                                            (DragLayer) mLauncher.findViewById(R.id.drag_layer);
+                                    dragLayer.addResizeFrame(info, hostView, cellLayout);
                                 }
                             };
                             post(new Runnable() {
@@ -2597,8 +2645,7 @@
             // Prepare it to be animated into its new position
             // This must be called after the view has been re-parented
             setPositionForDropAnimation(d.dragView, loc[0], loc[1], parent, cell);
-            boolean animateDrop = !mWasSpringLoadedOnDragExit;
-            parent.onDropChild(cell, animateDrop);
+            parent.onDropChild(cell, true);
         }
     }
 
@@ -2616,7 +2663,11 @@
     }
 
     public void onDragEnter(DragObject d) {
-        mDragTargetLayout = null; // Reset the drag state
+        mLastDragOverView = null;
+        if (mDragTargetLayout != null) {
+            mDragTargetLayout.onDragExit();
+            mDragTargetLayout = null; // Reset the drag state
+        }
 
         if (!mIsSmall) {
             mDragTargetLayout = getCurrentDropLayout();
@@ -2997,24 +3048,21 @@
                 if (layout != null && layout != mDragTargetLayout) {
                     if (mDragTargetLayout != null) {
                         mDragTargetLayout.setIsDragOverlapping(false);
-                        mSpringLoadedDragController.onDragExit();
+                        mDragTargetLayout.clearDragOutlines();
                     }
                     mDragTargetLayout = layout;
 
-                    // Workaround the fact that we don't actually want spring-loaded mode in phone
-                    // UI yet.
-                    if (LauncherApplication.isScreenLarge()) {
-                        // 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);
+                    // 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 isInSpringLoadedMode = (mShrinkState == ShrinkState.SPRING_LOADED);
+                    boolean allowDragOver = (mDragTargetLayout != null) &&
+                            (mDragTargetLayout.getAcceptsDrops() || isInSpringLoadedMode);
+                    if (allowDragOver) {
+                        if (isInSpringLoadedMode) {
+                            mSpringLoadedDragController.setAlarm(mDragTargetLayout);
                         }
+                        mDragTargetLayout.setIsDragOverlapping(true);
                     }
                 }
             } else {
@@ -3036,8 +3084,8 @@
 
                     if (widgetInfo.spanX == -1) {
                         // Calculate the grid spans needed to fit this widget
-                        int[] spans = layout.rectToCell(
-                                widgetInfo.minWidth, widgetInfo.minHeight, null);
+                        int[] spans = layout.rectToCell(widgetInfo.minWidth,
+                                widgetInfo.minHeight, null);
                         item.spanX = spans[0];
                         item.spanY = spans[1];
                     }
@@ -3049,37 +3097,40 @@
                     mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null);
                     ItemInfo info = (ItemInfo) d.dragInfo;
 
-                    boolean willCreateUserFolder = willCreateUserFolder(info, mDragTargetLayout,
-                            (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1]);
+                    mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
+                            (int) mDragViewVisualCenter[1], 1, 1, mDragTargetLayout, mTargetCell);
+                    final View dragOverView = mDragTargetLayout.getChildAt(mTargetCell[0],
+                            mTargetCell[1]);
 
-                    View newDropOver = null;
-                    if (willCreateUserFolder) {
-                        newDropOver = mDragTargetLayout.getChildAt(mTargetCell[0], mTargetCell[1]);
-                    }
+                    boolean userFolderPending = willCreateUserFolder(info, dragOverView,
+                            mTargetCell);
+                    boolean isOverFolder = dragOverView instanceof FolderIcon;
+                    if (dragOverView != mLastDragOverView) {
+                        cancelFolderCreation();
+                        if (mLastDragOverView != null && mLastDragOverView instanceof FolderIcon) {
 
-                    if (newDropOver != mLastDragOverView || !willCreateUserFolder) {
-                        if (mDragFolderRingAnimator != null && mCreateUserFolderOnDrop) {
-                            mDragFolderRingAnimator.animateToNaturalState();
+                            ((FolderIcon) mLastDragOverView).onDragExit(d.dragInfo);
                         }
-                        mCreateUserFolderOnDrop = false;
-                        mFolderCreationAlarm.cancelAlarm();
-                        mIsDraggingOverIcon = false;
                     }
 
-                    if (willCreateUserFolder && !mIsDraggingOverIcon) {
-                        mIsDraggingOverIcon = true;
-
-                        mLastDragOverView = mDragTargetLayout.getChildAt(mTargetCell[0], mTargetCell[1]);
-                        mFolderCreationAlarm.setOnAlarmListener(new FolderCreationAlarmListener(mLastDragOverView));
+                    if (userFolderPending && dragOverView != mLastDragOverView) {
+                        mFolderCreationAlarm.setOnAlarmListener(new
+                                FolderCreationAlarmListener(dragOverView));
                         mFolderCreationAlarm.setAlarm(FOLDER_CREATION_TIMEOUT);
-
-                        mDragTargetLayout.clearDragOutlines();
                     }
 
-                    if (!mCreateUserFolderOnDrop) {
+                    if (dragOverView != mLastDragOverView && isOverFolder) {
+
+                        ((FolderIcon) dragOverView).onDragEnter(d.dragInfo);
+                        if (mDragTargetLayout != null) {
+                            mDragTargetLayout.clearDragOutlines();
+                        }
+                    }
+                    mLastDragOverView = dragOverView;
+
+                    if (!mCreateUserFolderOnDrop && !isOverFolder) {
                         mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
-                                (int) mDragViewVisualCenter[0],
-                                (int) mDragViewVisualCenter[1],
+                                (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1],
                                 item.spanX, item.spanY);
                     }
                 }
@@ -3087,6 +3138,14 @@
         }
     }
 
+    private void cancelFolderCreation() {
+        if (mDragFolderRingAnimator != null && mCreateUserFolderOnDrop) {
+            mDragFolderRingAnimator.animateToNaturalState();
+        }
+        mCreateUserFolderOnDrop = false;
+        mFolderCreationAlarm.cancelAlarm();
+    }
+
     class FolderCreationAlarmListener implements OnAlarmListener {
         View v;
 
@@ -3097,15 +3156,15 @@
         public void onAlarm(Alarm alarm) {
             int tvLocation[] = new int[2];
             int wsLocation[] = new int[2];
-            v.getLocationOnScreen(tvLocation);
-            getLocationOnScreen(wsLocation);
+            v.getLocationInWindow(tvLocation);
+            getLocationInWindow(wsLocation);
 
-            if (mCellWidth < 0 || mCellHeight < 0) {
+            if (mCellWidth < 0 || mCellHeight < 0 && mDragTargetLayout != null) {
                 mCellWidth = mDragTargetLayout.getCellWidth();
                 mCellHeight = mDragTargetLayout.getCellHeight();
             }
-            int x = tvLocation[0] - wsLocation[0] + mCellWidth / 2;
-            int y = tvLocation[1] - wsLocation[1] + mCellHeight / 2;
+            int x = tvLocation[0] - wsLocation[0] + v.getMeasuredWidth() / 2;
+            int y = tvLocation[1] - wsLocation[1] + v.getMeasuredHeight() / 2;
 
             if (mDragFolderRingAnimator == null) {
                 mDragFolderRingAnimator = new FolderRingAnimator(mLauncher, null);
@@ -3114,16 +3173,21 @@
             mDragFolderRingAnimator.animateToAcceptState();
             showFolderAccept(mDragFolderRingAnimator);
             mCreateUserFolderOnDrop = true;
-            mDragTargetLayout.clearDragOutlines();
+            if (mDragTargetLayout != null) {
+                mDragTargetLayout.clearDragOutlines();
+            }
         }
     }
 
-    private void doDragExit() {
-        mWasSpringLoadedOnDragExit = mShrinkState == ShrinkState.SPRING_LOADED;
-
+    private void doDragExit(DragObject d) {
         if (mDragFolderRingAnimator != null && mCreateUserFolderOnDrop) {
             mDragFolderRingAnimator.animateToNaturalState();
         }
+        if (mLastDragOverView != null && mLastDragOverView instanceof FolderIcon) {
+            if (d != null) {
+                ((FolderIcon) mLastDragOverView).onDragExit(d.dragInfo);
+            }
+        }
         mFolderCreationAlarm.cancelAlarm();
 
         if (mDragTargetLayout != null) {
@@ -3132,14 +3196,11 @@
         if (!mIsPageMoving) {
             hideOutlines();
         }
-        if (mShrinkState == ShrinkState.SPRING_LOADED) {
-            mLauncher.exitSpringLoadedDragMode();
-        }
         clearAllHovers();
     }
 
     public void onDragExit(DragObject d) {
-        doDragExit();
+        doDragExit(d);
     }
 
     @Override
@@ -3210,32 +3271,38 @@
                         (ShortcutInfo) info);
                 break;
             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
-                view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher,
-                        cellLayout, (FolderInfo) info, mIconCache);
+                view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, cellLayout,
+                        (FolderInfo) info, mIconCache);
                 break;
             default:
                 throw new IllegalStateException("Unknown item type: " + info.itemType);
             }
 
-            // If the item being dropped is a shortcut and the nearest drop cell also contains
-            // a shortcut, then create a folder with the two shortcuts.
-            if (touchXY != null && createUserFolderIfNecessary(view, cellLayout, touchXY[0],
-                  touchXY[1], true)) {
-                return;
+            int spanX = mDragInfo != null ? mDragInfo.spanX : 1;
+            int spanY = mDragInfo != null ? mDragInfo.spanY : 1;
+            // 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)) {
+                    return;
+                }
+                if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, dragInfo, true)) {
+                    return;
+                }
             }
 
-            mTargetCell = new int[2];
             if (touchXY != null) {
                 // when dragging and dropping, just find the closest free spot
-                mTargetCell = findNearestVacantArea(touchXY[0], touchXY[1], 1, 1, null, cellLayout,
-                        mTargetCell);
+                mTargetCell = findNearestVacantArea(touchXY[0], touchXY[1], 1, 1, null,
+                        cellLayout, mTargetCell);
             } else {
                 cellLayout.findCellForSpan(mTargetCell, 1, 1);
             }
             addInScreen(view, indexOfChild(cellLayout), mTargetCell[0],
                     mTargetCell[1], info.spanX, info.spanY, insertAtFirst);
-            boolean animateDrop = !mWasSpringLoadedOnDragExit;
-            cellLayout.onDropChild(view, animateDrop);
+            cellLayout.onDropChild(view, false);
             cellLayout.animateDrop();
             CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
             cellLayout.getChildrenLayout().measureChild(view);
@@ -3309,13 +3376,13 @@
     /**
      * Called at the end of a drag which originated on the workspace.
      */
-    public void onDropCompleted(View target, Object dragInfo, boolean success) {
+    public void onDropCompleted(View target, DragObject d, boolean success) {
         if (success) {
             if (target != this && mDragInfo != null) {
                 final CellLayout cellLayout = (CellLayout) getChildAt(mDragInfo.screen);
                 cellLayout.removeView(mDragInfo.cell);
                 if (mDragInfo.cell instanceof DropTarget) {
-                    mDragController.removeDropTarget((DropTarget)mDragInfo.cell);
+                    mDragController.removeDropTarget((DropTarget) mDragInfo.cell);
                 }
                 // final Object tag = mDragInfo.cell.getTag();
             }
@@ -3323,7 +3390,7 @@
             // NOTE: When 'success' is true, onDragExit is called by the DragController before
             // calling onDropCompleted(). We call it ourselves here, but maybe this should be
             // moved into DragController.cancelDrag().
-            doDragExit();
+            doDragExit(null);
             ((CellLayout) getChildAt(mDragInfo.screen)).onDropChild(mDragInfo.cell, false);
         }
         mLauncher.unlockScreenOrientation();
@@ -3368,6 +3435,7 @@
 
             final int page = mCurrentPage + (direction == DragController.SCROLL_LEFT ? -1 : 1);
             final CellLayout layout = (CellLayout) getChildAt(page);
+            cancelFolderCreation();
 
             if (layout != null) {
                 layout.setIsDragOverlapping(true);
@@ -3389,7 +3457,6 @@
         for (int i = 0; i < childCount; i++) {
             ((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.