Merge "Fixing small folder bugs"
diff --git a/res/layout/apps_customize_pane.xml b/res/layout/apps_customize_pane.xml
index 8b1bd39..b455153 100644
--- a/res/layout/apps_customize_pane.xml
+++ b/res/layout/apps_customize_pane.xml
@@ -73,7 +73,8 @@
                 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"
-                launcher:widgetCountY="@integer/apps_customize_widget_cell_count_y" />
+                launcher:widgetCountY="@integer/apps_customize_widget_cell_count_y"
+                launcher:maxGap="@dimen/workspace_max_gap" />
             <ImageView
                 android:id="@+id/paged_view_indicator"
                 android:layout_width="wrap_content"
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 4540c15..278da54 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -31,12 +31,12 @@
 
     <integer name="all_apps_view_cellCountX">6</integer>
     <integer name="all_apps_view_cellCountY">3</integer>
-    <dimen name="all_apps_view_pageLayoutWidthGap">10dp</dimen>
-    <dimen name="all_apps_view_pageLayoutHeightGap">5dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingTop">4dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingBottom">4dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingLeft">2dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingRight">2dp</dimen>
+    <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_widget_cell_width_gap">30dp</dimen>
diff --git a/res/values-port/dimens.xml b/res/values-port/dimens.xml
index 8b423dd..945699b 100644
--- a/res/values-port/dimens.xml
+++ b/res/values-port/dimens.xml
@@ -29,12 +29,12 @@
 
     <integer name="all_apps_view_cellCountX">4</integer>
     <integer name="all_apps_view_cellCountY">5</integer>
-    <dimen name="all_apps_view_pageLayoutWidthGap">0dp</dimen>
-    <dimen name="all_apps_view_pageLayoutHeightGap">8dp</dimen>
+    <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">0dp</dimen>
-    <dimen name="all_apps_view_pageLayoutPaddingRight">0dp</dimen>
+    <dimen name="all_apps_view_pageLayoutPaddingLeft">5dp</dimen>
+    <dimen name="all_apps_view_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/dimens.xml b/res/values/dimens.xml
index 52110bd..2a54981 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -32,8 +32,8 @@
     <dimen name="app_icon_size">56dp</dimen>
     <dimen name="apps_customize_cell_width">72dp</dimen>
     <dimen name="apps_customize_cell_height">72dp</dimen>
-    <!-- In portrat/normal, we peek only 1/8th the app cell width -->
-    <dimen name="apps_customize_peek_width">9dp</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>
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java
index 54a2e42..35ca3e9 100644
--- a/src/com/android/launcher2/AppsCustomizePagedView.java
+++ b/src/com/android/launcher2/AppsCustomizePagedView.java
@@ -283,6 +283,10 @@
         mShortcutCountX = Math.max(1, (int) Math.round(mCellCountX / 2f));
         mShortcutCountY = Math.max(1, (int) Math.round(mCellCountY / 2f));
 
+        // Force a measure to update recalculate the gaps
+        int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST);
+        int heightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST);
+        mWidgetSpacingLayout.measure(widthSpec, heightSpec);
         mContentWidth = mWidgetSpacingLayout.getContentWidth();
 
         invalidatePageData();
@@ -537,7 +541,7 @@
         // expected page width, so we can actually optimize by hiding all the TextView-based
         // children that are expensive to measure, and let that happen naturally later.
         setVisibilityOnChildren(layout, View.GONE);
-        int widthSpec = MeasureSpec.makeMeasureSpec(getPageContentWidth(), MeasureSpec.AT_MOST);
+        int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST);
         int heightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST);
         layout.setMinimumWidth(getPageContentWidth());
         layout.measure(widthSpec, heightSpec);
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 68e9edb..99d62ae 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -153,7 +153,6 @@
         mWidthGap = a.getDimensionPixelSize(R.styleable.CellLayout_widthGap, 0);
         mHeightGap = a.getDimensionPixelSize(R.styleable.CellLayout_heightGap, 0);
         mMaxGap = a.getDimensionPixelSize(R.styleable.CellLayout_maxGap, 0);
-
         mCountX = LauncherModel.getCellCountX();
         mCountY = LauncherModel.getCellCountY();
         mOccupied = new boolean[mCountX][mCountY];
@@ -1384,13 +1383,11 @@
      *
      * @param child The child that is being dropped
      */
-    void onDropChild(View child, boolean animate) {
+    void onDropChild(View child) {
         if (child != null) {
             LayoutParams lp = (LayoutParams) child.getLayoutParams();
             lp.isDragging = false;
             lp.dropped = true;
-            lp.animateDrop = animate;
-            child.setVisibility(animate ? View.INVISIBLE : View.VISIBLE);
             child.requestLayout();
         }
     }
@@ -1717,22 +1714,8 @@
         @ViewDebug.ExportedProperty
         int y;
 
-        /**
-         * The old X coordinate of this item, relative to its current parent.
-         * Used to animate the item into its new position.
-         */
-        int oldX;
-
-        /**
-         * The old Y coordinate of this item, relative to its current parent.
-         * Used to animate the item into its new position.
-         */
-        int oldY;
-
         boolean dropped;
 
-        boolean animateDrop;
-
         public LayoutParams(Context c, AttributeSet attrs) {
             super(c, attrs);
             cellHSpan = 1;
diff --git a/src/com/android/launcher2/CellLayoutChildren.java b/src/com/android/launcher2/CellLayoutChildren.java
index 1caecc0..615740e 100644
--- a/src/com/android/launcher2/CellLayoutChildren.java
+++ b/src/com/android/launcher2/CellLayoutChildren.java
@@ -117,15 +117,6 @@
                             WallpaperManager.COMMAND_DROP,
                             cellXY[0] + childLeft + lp.width / 2,
                             cellXY[1] + childTop + lp.height / 2, 0, null);
-
-                    if (lp.animateDrop) {
-                        lp.animateDrop = false;
-
-                        // This call does not result in a requestLayout(), but at one point did.
-                        // We need to be cautious about any method calls within the layout pass
-                        // to insure we don't leave the view tree in a bad state.
-                        ((Workspace) mParent.getParent()).animateViewIntoPosition(child);
-                    }
                 }
             }
         }
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index 5b1b20a..ca72ce9 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -81,9 +81,6 @@
     /** Info about the screen for clamping. */
     private DisplayMetrics mDisplayMetrics = new DisplayMetrics();
 
-    /** Original view that is being dragged.  */
-    private View mOriginator;
-
     /** the area at the edge of the screen that makes the workspace go left
      *   or right while you're dragging.
      */
@@ -178,8 +175,6 @@
      */
     public void startDrag(View v, DragSource source, Object dragInfo, int dragAction,
             Rect dragRegion) {
-        mOriginator = v;
-
         Bitmap b = getViewBitmap(v);
 
         if (b == null) {
@@ -214,8 +209,6 @@
      */
     public void startDrag(View v, Bitmap bmp, DragSource source, Object dragInfo, int dragAction,
             Rect dragRegion) {
-        mOriginator = v;
-
         int[] loc = mCoordinatesTemp;
         v.getLocationOnScreen(loc);
         int screenX = loc[0];
@@ -383,9 +376,6 @@
     private void endDrag() {
         if (mDragging) {
             mDragging = false;
-            if (mOriginator != null) {
-                mOriginator.setVisibility(View.VISIBLE);
-            }
             for (DragListener listener : mListeners) {
                 listener.onDragEnd();
             }
diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java
index 0cdfd28..0ce153e 100644
--- a/src/com/android/launcher2/DragLayer.java
+++ b/src/com/android/launcher2/DragLayer.java
@@ -16,17 +16,27 @@
 
 package com.android.launcher2;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewParent;
+import android.view.animation.DecelerateInterpolator;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
+import com.android.launcher.R;
+
 import java.util.ArrayList;
 
 /**
@@ -36,12 +46,19 @@
     private DragController mDragController;
     private int[] mTmpXY = new int[2];
 
+    private int mXDown, mYDown;
+    private Launcher mLauncher;
+
     // Variables relating to resizing widgets
     private final ArrayList<AppWidgetResizeFrame> mResizeFrames =
             new ArrayList<AppWidgetResizeFrame>();
     private AppWidgetResizeFrame mCurrentResizeFrame;
-    private int mXDown, mYDown;
-    private Launcher mLauncher;
+
+    // Variables relating to animation of views after drop
+    private ValueAnimator mDropAnim = null;
+    private TimeInterpolator mQuintEaseOutInterpolator = new DecelerateInterpolator(2.5f);
+    private int[] mDropViewPos = new int[] { -1, -1 };
+    private View mDropView = null;
 
     /**
      * Used to create a new DragLayer from XML.
@@ -148,16 +165,35 @@
 
     public void getDescendantRectRelativeToSelf(View descendant, Rect r) {
         descendant.getHitRect(r);
+        mTmpXY[0] = 0;
+        mTmpXY[1] = 0;
+        getDescendantCoordRelativeToSelf(descendant, mTmpXY);
+        r.offset(mTmpXY[0], mTmpXY[1]);
+    }
 
+    public void getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
         ViewParent viewParent = descendant.getParent();
         while (viewParent instanceof View && viewParent != this) {
             final View view = (View)viewParent;
-            r.offset(view.getLeft() + (int) (view.getTranslationX() + 0.5f) - view.getScrollX(),
-                    view.getTop() + (int) (view.getTranslationY() + 0.5f) - view.getScrollY());
+            coord[0] += view.getLeft() + (int) (view.getTranslationX() + 0.5f) - view.getScrollX();
+            coord[1] += view.getTop() + (int) (view.getTranslationY() + 0.5f) - view.getScrollY();
             viewParent = view.getParent();
         }
     }
 
+    public void getViewLocationRelativeToSelf(View v, int[] location) {
+        getLocationOnScreen(location);
+        int x = location[0];
+        int y = location[1];
+
+        v.getLocationOnScreen(location);
+        int vX = location[0];
+        int vY = location[1];
+
+        location[0] = vX - x;
+        location[1] = vY - y;
+    }
+
     @Override
     public boolean dispatchUnhandledMove(View focused, int direction) {
         return mDragController.dispatchUnhandledMove(focused, direction);
@@ -267,4 +303,94 @@
 
         resizeFrame.snapToWidget(false);
     }
+
+    public void animateViewIntoPosition(DragView dragView, final View child) {
+        ((CellLayoutChildren) child.getParent()).measureChild(child);
+        CellLayout.LayoutParams lp =  (CellLayout.LayoutParams) child.getLayoutParams();
+
+        int[] loc = new int[2];
+        getViewLocationRelativeToSelf(dragView, loc);
+
+        int coord[] = new int[2];
+        coord[0] = lp.x;
+        coord[1] = lp.y;
+        getDescendantCoordRelativeToSelf(child, coord);
+
+        final int fromX = loc[0] + (dragView.getWidth() - child.getMeasuredWidth())  / 2;
+        final int fromY = loc[1] + (dragView.getHeight() - child.getMeasuredHeight())  / 2;
+        final int dx = coord[0] - fromX;
+        final int dy = coord[1] - fromY;
+
+        child.setVisibility(INVISIBLE);
+        animateViewIntoPosition(child, fromX, fromY, dx, dy);
+    }
+
+    private void animateViewIntoPosition(final View view, final int fromX, final int fromY,
+            final int dX, final int dY) {
+
+        // Calculate the duration of the animation based on the object's distance
+        final float dist = (float) Math.sqrt(dX*dX + dY*dY);
+        final Resources res = getResources();
+        final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
+        int duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
+        if (dist < maxDist) {
+            duration *= mQuintEaseOutInterpolator.getInterpolation(dist / maxDist);
+        }
+
+        if (mDropAnim != null) {
+            mDropAnim.end();
+        }
+        mDropAnim = new ValueAnimator();
+        mDropAnim.setInterpolator(mQuintEaseOutInterpolator);
+
+        // The view is invisible during the animation; we render it manually.
+        mDropAnim.addListener(new AnimatorListenerAdapter() {
+            public void onAnimationStart(Animator animation) {
+                // Set this here so that we don't render it until the animation begins
+                mDropView = view;
+            }
+
+            public void onAnimationEnd(Animator animation) {
+                if (mDropView != null) {
+                    mDropView.setVisibility(View.VISIBLE);
+                    mDropView = null;
+                }
+            }
+        });
+
+        mDropAnim.setDuration(duration);
+        mDropAnim.setFloatValues(0.0f, 1.0f);
+        mDropAnim.removeAllUpdateListeners();
+        mDropAnim.addUpdateListener(new AnimatorUpdateListener() {
+            public void onAnimationUpdate(ValueAnimator animation) {
+                final float percent = (Float) animation.getAnimatedValue();
+                // Invalidate the old position
+                int width = view.getMeasuredWidth();
+                int height = view.getMeasuredHeight();
+                invalidate(mDropViewPos[0], mDropViewPos[1],
+                        mDropViewPos[0] + width, mDropViewPos[1] + height);
+
+                mDropViewPos[0] = fromX + (int) (percent * dX + 0.5f);
+                mDropViewPos[1] = fromY + (int) (percent * dY + 0.5f);
+                invalidate(mDropViewPos[0], mDropViewPos[1],
+                        mDropViewPos[0] + width, mDropViewPos[1] + height);
+            }
+        });
+        mDropAnim.start();
+    }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        super.dispatchDraw(canvas);
+        if (mDropView != null) {
+            // We are animating an item that was just dropped on the home screen.
+            // Render its View in the current animation position.
+            canvas.save(Canvas.MATRIX_SAVE_FLAG);
+            final int xPos = mDropViewPos[0] - mDropView.getScrollX();
+            final int yPos = mDropViewPos[1] - mDropView.getScrollY();
+            canvas.translate(xPos, yPos);
+            mDropView.draw(canvas);
+            canvas.restore();
+        }
+    }
 }
diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java
index b02e22b..4cc2c55 100644
--- a/src/com/android/launcher2/DragView.java
+++ b/src/com/android/launcher2/DragView.java
@@ -227,7 +227,7 @@
 
         mAnim.start();
     }
-    
+
     /**
      * Move the window containing this view.
      *
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index 89e4603..37368b9 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -224,12 +224,16 @@
             mEmptyCell[0] = item.cellX;
             mEmptyCell[1] = item.cellY;
             mCurrentDragView = v;
-            mContent.removeView(mCurrentDragView);
-            mInfo.remove(item);
+
         }
         return true;
     }
 
+    public void onDragViewVisible() {
+        mContent.removeView(mCurrentDragView);
+        mInfo.remove(mCurrentDragInfo);
+    }
+
     public boolean isEditingName() {
         return mIsEditingName;
     }
@@ -294,9 +298,6 @@
         mDragController = dragController;
     }
 
-    public void onDragViewVisible() {
-    }
-
     void setLauncher(Launcher launcher) {
         mLauncher = launcher;
     }
@@ -542,7 +543,6 @@
     public void onDragEnter(DragObject d) {
         mPreviousTargetCell[0] = -1;
         mPreviousTargetCell[1] = -1;
-        mContent.onDragEnter();
         mOnExitAlarm.cancelAlarm();
     }
 
@@ -661,7 +661,6 @@
             mOnExitAlarm.setAlarm(ON_EXIT_CLOSE_DELAY);
         }
         mReorderAlarm.cancelAlarm();
-        mContent.onDragExit();
     }
 
     public void onDropCompleted(View target, DragObject d, boolean success) {
@@ -847,7 +846,7 @@
                     LauncherSettings.Favorites.CONTAINER_DESKTOP, mInfo.screen,
                     mInfo.cellX, mInfo.cellY);
         }
-        LauncherModel.deleteFolderContentsFromDatabase(mLauncher, mInfo, true);
+        LauncherModel.deleteItemFromDatabase(mLauncher, mInfo);
 
         // Add the last remaining child to the workspace in place of the folder
         if (finalItem != null) {
@@ -876,9 +875,9 @@
             si.cellX = lp.cellX = mEmptyCell[0];
             si.cellX = lp.cellY = mEmptyCell[1];
             mContent.addViewToCellLayout(mCurrentDragView, -1, (int)item.id, lp, true);
-            mSuppressOnAdd = true;
-            mItemsInvalidated = true;
+            mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, mCurrentDragView);
             setupContentDimension(getItemCount());
+            mSuppressOnAdd = true;
         }
         mInfo.add(item);
     }
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index b52a4f7..54b7b9c 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -39,12 +39,12 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
-import android.content.Intent.ShortcutIconResource;
 import android.content.IntentFilter;
+import android.content.Intent.ShortcutIconResource;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -78,9 +78,9 @@
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.View.OnClickListener;
 import android.view.View.OnLongClickListener;
-import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.DecelerateInterpolator;
 import android.view.inputmethod.InputMethodManager;
@@ -433,6 +433,10 @@
         }
     }
 
+    public DragLayer getDragLayer() {
+        return mDragLayer;
+    }
+
     static int getScreen() {
         synchronized (sLock) {
             return sScreen;
diff --git a/src/com/android/launcher2/PagedViewCellLayout.java b/src/com/android/launcher2/PagedViewCellLayout.java
index 9c37c01..fc1b012 100644
--- a/src/com/android/launcher2/PagedViewCellLayout.java
+++ b/src/com/android/launcher2/PagedViewCellLayout.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewDebug;
@@ -36,10 +37,13 @@
 
     private int mCellCountX;
     private int mCellCountY;
+    private int mOriginalCellWidth;
+    private int mOriginalCellHeight;
     private int mCellWidth;
     private int mCellHeight;
     private int mWidthGap;
     private int mHeightGap;
+    private int mMaxGap;
     private float mPeekWidth;
     protected PagedViewCellLayoutChildren mChildren;
     private PagedViewCellLayoutChildren mHolographicChildren;
@@ -61,12 +65,15 @@
 
         // setup default cell parameters
         Resources resources = context.getResources();
-        mCellWidth = resources.getDimensionPixelSize(R.dimen.apps_customize_cell_width);
-        mCellHeight = resources.getDimensionPixelSize(R.dimen.apps_customize_cell_height);
+        mOriginalCellWidth = mCellWidth =
+            resources.getDimensionPixelSize(R.dimen.apps_customize_cell_width);
+        mOriginalCellHeight = mCellHeight =
+            resources.getDimensionPixelSize(R.dimen.apps_customize_cell_height);
         mPeekWidth = resources.getDimensionPixelSize(R.dimen.apps_customize_peek_width);
         mCellCountX = LauncherModel.getCellCountX();
         mCellCountY = LauncherModel.getCellCountY();
         mWidthGap = mHeightGap = -1;
+        mMaxGap = resources.getDimensionPixelSize(R.dimen.apps_customize_max_gap);
 
         mChildren = new PagedViewCellLayoutChildren(context);
         mChildren.setCellDimensions(mCellWidth, mCellHeight);
@@ -214,53 +221,47 @@
             throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
         }
 
-        final int cellWidth = mCellWidth;
-        final int cellHeight = mCellHeight;
+
 
         int numWidthGaps = mCellCountX - 1;
         int numHeightGaps = mCellCountY - 1;
 
-        int vSpaceLeft = heightSpecSize - mPaddingTop
-                - mPaddingBottom - (cellHeight * mCellCountY);
-        int heightGap = (numHeightGaps <= 0) ? 0 : (vSpaceLeft / numHeightGaps);
+        if (mWidthGap < 0 || mHeightGap < 0) {
+            int hSpace = widthSpecSize - mPaddingLeft - mPaddingRight;
+            int vSpace = heightSpecSize - mPaddingTop - mPaddingBottom;
+            int hFreeSpace = hSpace - (mCellCountX * mOriginalCellWidth);
+            int vFreeSpace = vSpace - (mCellCountY * mOriginalCellHeight);
+            mWidthGap = Math.min(mMaxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0);
+            mHeightGap = Math.min(mMaxGap,numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0);
 
-        int hSpaceLeft = widthSpecSize - mPaddingLeft
-                - mPaddingRight - (cellWidth * mCellCountX);
-        int widthGap = (numWidthGaps <= 0) ? 0 : (hSpaceLeft / numWidthGaps);
-
-        // center it around the min gaps
-        int minGap = Math.min(widthGap, heightGap);
-        /*
-        if (minGap < heightGap) {
-            // vertical space has shrunken, so change padding accordingly
-            paddingTop += ((heightGap - minGap) * (mCellCountY - 1)) / 2;
-        } else if (minGap < widthGap) {
-            // horizontal space has shrunken, so change padding accordingly
-            paddingLeft += ((widthGap - minGap) * (mCellCountX - 1)) / 2;
-        }
-        */
-        if (mWidthGap > -1 && mHeightGap > -1) {
-            widthGap = mWidthGap;
-            heightGap = mHeightGap;
-        } else {
-            widthGap = heightGap = minGap;
+            mChildren.setGap(mWidthGap, mHeightGap);
+            mHolographicChildren.setGap(mWidthGap, mHeightGap);
         }
 
-        int newWidth = (mCellCountX * cellWidth) + ((mCellCountX - 1) * widthGap);
-        int newHeight = (mCellCountY * cellHeight) + ((mCellCountY - 1) * heightGap);
+        // Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY
+        int newWidth = widthSpecSize;
+        int newHeight = heightSpecSize;
+        if (widthSpecMode == MeasureSpec.AT_MOST) {
+            newWidth = mPaddingLeft + mPaddingRight + (mCellCountX * mCellWidth) +
+                ((mCellCountX - 1) * mWidthGap);
+            newHeight = mPaddingTop + mPaddingBottom + (mCellCountY * mCellHeight) +
+                ((mCellCountY - 1) * mHeightGap);
+            setMeasuredDimension(newWidth, newHeight);
+        }
 
         final int count = getChildCount();
         for (int i = 0; i < count; i++) {
             View child = getChildAt(i);
             int childWidthMeasureSpec =
-                MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY);
+                MeasureSpec.makeMeasureSpec(newWidth - mPaddingLeft -
+                        mPaddingRight, MeasureSpec.EXACTLY);
             int childheightMeasureSpec =
-                MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY);
+                MeasureSpec.makeMeasureSpec(newHeight - mPaddingTop -
+                        mPaddingBottom, MeasureSpec.EXACTLY);
             child.measure(childWidthMeasureSpec, childheightMeasureSpec);
         }
 
-        setMeasuredDimension(newWidth + mPaddingLeft + mPaddingRight,
-            newHeight + mPaddingTop + mPaddingBottom);
+        setMeasuredDimension(newWidth, newHeight);
     }
 
     int getContentWidth() {
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index dd1e8ec..5ba9fd7 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -16,17 +16,13 @@
 
 package com.android.launcher2;
 
-import java.util.ArrayList;
-import java.util.HashSet;
-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;
@@ -45,7 +41,6 @@
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Paint;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region.Op;
@@ -69,6 +64,10 @@
 import com.android.launcher2.FolderIcon.FolderRingAnimator;
 import com.android.launcher2.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
 
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
 /**
  * The workspace is a wide area with a wallpaper and a finite number of pages.
  * Each page contains a number of icons, folders or widgets the user can
@@ -181,11 +180,6 @@
     private final Rect mTempRect = new Rect();
     private final int[] mTempXY = new int[2];
 
-    private ValueAnimator mDropAnim = null;
-    private TimeInterpolator mQuintEaseOutInterpolator = new DecelerateInterpolator(2.5f);
-    private View mDropView = null;
-    private int[] mDropViewPos = new int[] { -1, -1 };
-
     // Paint used to draw external drop outline
     private final Paint mExternalDragOutlinePaint = new Paint();
 
@@ -415,7 +409,7 @@
      * @return The open folder on the current screen, or null if there is none
      */
     Folder getOpenFolder() {
-        DragLayer dragLayer = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
+        DragLayer dragLayer = mLauncher.getDragLayer();
         int count = dragLayer.getChildCount();
         for (int i = 0; i < count; i++) {
             View child = dragLayer.getChildAt(i);
@@ -1255,17 +1249,6 @@
                     d.draw(canvas);
                 }
             }
-
-            if (mDropView != null) {
-                // We are animating an item that was just dropped on the home screen.
-                // Render its View in the current animation position.
-                canvas.save(Canvas.MATRIX_SAVE_FLAG);
-                final int xPos = mDropViewPos[0] - mDropView.getScrollX();
-                final int yPos = mDropViewPos[1] - mDropView.getScrollY();
-                canvas.translate(xPos, yPos);
-                mDropView.draw(canvas);
-                canvas.restore();
-            }
         }
     }
 
@@ -1761,7 +1744,7 @@
     }
 
     public void exitWidgetResizeMode() {
-        DragLayer dragLayer = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
+        DragLayer dragLayer = mLauncher.getDragLayer();
         dragLayer.clearAllResizeFrames();
     }
 
@@ -2150,98 +2133,6 @@
                 cellXY[0], cellXY[1]);
     }
 
-    private void setPositionForDropAnimation(
-            View dragView, int dragViewX, int dragViewY, View parent, View child) {
-        final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
-
-        // Based on the position of the drag view, find the top left of the original view
-        int viewX = dragViewX + (dragView.getWidth() - child.getMeasuredWidth()) / 2;
-        int viewY = dragViewY + (dragView.getHeight() - child.getMeasuredHeight()) / 2;
-
-        CellLayout layout = (CellLayout) parent;
-
-        // Set its old pos (in the new parent's coordinates); it will be animated
-        // in animateViewIntoPosition after the next layout pass
-        lp.oldX = viewX - (layout.getLeft() + layout.getPaddingLeft() - mScrollX);
-        lp.oldY = viewY - (layout.getTop() + layout.getPaddingTop() - mScrollY);
-    }
-
-    public void animateViewIntoPosition(final View view, final int fromX, final int fromY, 
-            final int dX, final int dY, final Runnable animationEndRunnable) {
-
-        // Calculate the duration of the animation based on the object's distance
-        final float dist = (float) Math.sqrt(dX*dX + dY*dY);
-        final Resources res = getResources();
-        final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
-        int duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
-        if (dist < maxDist) {
-            duration *= mQuintEaseOutInterpolator.getInterpolation(dist / maxDist);
-        }
-
-        if (mDropAnim != null) {
-            mDropAnim.end();
-        }
-        mDropAnim = new ValueAnimator();
-        mDropAnim.setInterpolator(mQuintEaseOutInterpolator);
-
-        // The view is invisible during the animation; we render it manually.
-        mDropAnim.addListener(new AnimatorListenerAdapter() {
-            public void onAnimationStart(Animator animation) {
-                // Set this here so that we don't render it until the animation begins
-                mDropView = view;
-            }
-
-            public void onAnimationEnd(Animator animation) {
-                animationEndRunnable.run();
-            }
-        });
-
-        mDropAnim.setDuration(duration);
-        mDropAnim.setFloatValues(0.0f, 1.0f);
-        mDropAnim.removeAllUpdateListeners();
-        mDropAnim.addUpdateListener(new AnimatorUpdateListener() {
-            public void onAnimationUpdate(ValueAnimator animation) {
-                final float percent = (Float) animation.getAnimatedValue();
-                // Invalidate the old position
-                invalidate(mDropViewPos[0], mDropViewPos[1],
-                        mDropViewPos[0] + view.getWidth(), mDropViewPos[1] + view.getHeight());
-
-                mDropViewPos[0] = fromX + (int) (percent * dX + 0.5f);
-                mDropViewPos[1] = fromY + (int) (percent * dY + 0.5f);
-                invalidate(mDropViewPos[0], mDropViewPos[1],
-                        mDropViewPos[0] + view.getWidth(), mDropViewPos[1] + view.getHeight());
-            }
-        });
-
-        mDropAnim.start();
-    }
-
-    /*
-     * We should be careful that this method cannot result in any synchronous requestLayout()
-     * calls, as it is called from onLayout().
-     */
-    public void animateViewIntoPosition(final View view) {
-        final CellLayout parent = (CellLayout) view.getParent().getParent();
-        final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
-
-        // Convert the animation params to be relative to the Workspace, not the CellLayout
-        final int fromX = lp.oldX + parent.getLeft() + parent.getPaddingLeft();
-        final int fromY = lp.oldY + parent.getTop() + parent.getPaddingTop();
-
-        final int dx = lp.x - lp.oldX;
-        final int dy = lp.y - lp.oldY;
-
-        Runnable animationEndRunnable = new Runnable() {
-            public void run() {
-                if (mDropView != null) {
-                    mDropView.setVisibility(View.VISIBLE);
-                    mDropView = null;
-                }
-            }
-        };
-        animateViewIntoPosition(view, fromX, fromY, dx, dy, animationEndRunnable);
-    }
-
     /**
      * {@inheritDoc}
      */
@@ -2457,8 +2348,7 @@
                         if (pinfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) {
                             final Runnable resizeRunnable = new Runnable() {
                                 public void run() {
-                                    DragLayer dragLayer =
-                                            (DragLayer) mLauncher.findViewById(R.id.drag_layer);
+                                    DragLayer dragLayer = mLauncher.getDragLayer();
                                     dragLayer.addResizeFrame(info, hostView, cellLayout);
                                 }
                             };
@@ -2482,13 +2372,10 @@
 
             final CellLayout parent = (CellLayout) cell.getParent().getParent();
 
-            int loc[] = new int[2];
-            getViewLocationRelativeToSelf(d.dragView, loc);
-
             // 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);
-            parent.onDropChild(cell, true);
+            mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell);
+            parent.onDropChild(cell);
         }
     }
 
@@ -3116,17 +3003,13 @@
             }
             addInScreen(view, indexOfChild(cellLayout), mTargetCell[0],
                     mTargetCell[1], info.spanX, info.spanY, insertAtFirst);
-            cellLayout.onDropChild(view, false);
+            cellLayout.onDropChild(view);
             cellLayout.animateDrop();
             CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
             cellLayout.getChildrenLayout().measureChild(view);
 
             if (dragView != null) {
-                // we have the visual center of the drag view, we need to find the actual
-                // left and top of the dragView.
-                int loc[] = new int[2];
-                getViewLocationRelativeToSelf(dragView, loc);
-                setPositionForDropAnimation(dragView, loc[0], loc[1], cellLayout, view);
+                mLauncher.getDragLayer().animateViewIntoPosition(dragView, view);
             }
 
             LauncherModel.addOrMoveItemInDatabase(mLauncher, info,
@@ -3199,7 +3082,7 @@
             // calling onDropCompleted(). We call it ourselves here, but maybe this should be
             // moved into DragController.cancelDrag().
             doDragExit(null);
-            ((CellLayout) getChildAt(mDragInfo.screen)).onDropChild(mDragInfo.cell, false);
+            ((CellLayout) getChildAt(mDragInfo.screen)).onDropChild(mDragInfo.cell);
         }
         mLauncher.unlockScreenOrientation();
         mDragOutline = null;