merge in ics-release history after reset to master
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 22516cc..ae22507 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -64,6 +64,8 @@
     private int mCountX;
     private int mCountY;
 
+    private int mOriginalWidthGap;
+    private int mOriginalHeightGap;
     private int mWidthGap;
     private int mHeightGap;
     private int mMaxGap;
@@ -155,8 +157,8 @@
             mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10);
         mOriginalCellHeight =
             mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10);
-        mWidthGap = a.getDimensionPixelSize(R.styleable.CellLayout_widthGap, 0);
-        mHeightGap = a.getDimensionPixelSize(R.styleable.CellLayout_heightGap, 0);
+        mWidthGap = mOriginalWidthGap = a.getDimensionPixelSize(R.styleable.CellLayout_widthGap, 0);
+        mHeightGap = mOriginalHeightGap = a.getDimensionPixelSize(R.styleable.CellLayout_heightGap, 0);
         mMaxGap = a.getDimensionPixelSize(R.styleable.CellLayout_maxGap, 0);
         mCountX = LauncherModel.getCellCountX();
         mCountY = LauncherModel.getCellCountY();
@@ -872,7 +874,7 @@
         int numWidthGaps = mCountX - 1;
         int numHeightGaps = mCountY - 1;
 
-        if (mWidthGap < 0 || mHeightGap < 0) {
+        if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) {
             int hSpace = widthSpecSize - mPaddingLeft - mPaddingRight;
             int vSpace = heightSpecSize - mPaddingTop - mPaddingBottom;
             int hFreeSpace = hSpace - (mCountX * mOriginalCellWidth);
@@ -885,6 +887,9 @@
             mCellHeight = mOriginalCellHeight + remainingVSpace / mCountY;
 
             mChildren.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
+        } else {
+            mWidthGap = mOriginalWidthGap;
+            mHeightGap = mOriginalHeightGap;
         }
 
         // Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY
diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java
index 37abe5a..8563be9 100644
--- a/src/com/android/launcher2/DragLayer.java
+++ b/src/com/android/launcher2/DragLayer.java
@@ -169,6 +169,13 @@
         return mDragController.onTouchEvent(ev);
     }
 
+    /**
+     * Determine the rect of the descendant in this DragLayer's coordinates
+     *
+     * @param descendant The descendant whose coordinates we want to find.
+     * @param r The rect into which to place the results.
+     * @return The factor by which this descendant is scaled relative to this DragLayer.
+     */
     public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
         mTmpXY[0] = 0;
         mTmpXY[1] = 0;
@@ -178,7 +185,21 @@
         return scale;
     }
 
-    private float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
+    public void getLocationInDragLayer(View child, int[] loc) {
+        loc[0] = 0;
+        loc[1] = 0;
+        getDescendantCoordRelativeToSelf(child, loc);
+    }
+
+    /**
+     * Given a coordinate relative to the descendant, find the coordinate in this DragLayer's
+     * coordinates.
+     *
+     * @param descendant The descendant to which the passed coordinate is relative.
+     * @param coord The coordinate that we want mapped.
+     * @return The factor by which this descendant is scaled relative to this DragLayer.
+     */
+    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
         float scale = 1.0f;
         float[] pt = {coord[0], coord[1]};
         descendant.getMatrix().mapPoints(pt);
@@ -199,12 +220,6 @@
         return scale;
     }
 
-    public void getLocationInDragLayer(View child, int[] loc) {
-        loc[0] = 0;
-        loc[1] = 0;
-        getDescendantCoordRelativeToSelf(child, loc);
-    }
-
     public void getViewRectRelativeToSelf(View v, Rect r) {
         int[] loc = new int[2];
         getLocationInWindow(loc);
@@ -319,6 +334,17 @@
         animateViewIntoPosition(dragView, child, null);
     }
 
+    public void animateViewIntoPosition(DragView dragView, final int[] pos, float scale,
+            Runnable onFinishRunnable) {
+        Rect r = new Rect();
+        getViewRectRelativeToSelf(dragView, r);
+        final int fromX = r.left;
+        final int fromY = r.top;
+
+        animateViewIntoPosition(dragView, fromX, fromY, pos[0], pos[1], scale,
+                onFinishRunnable, true);
+    }
+
     public void animateViewIntoPosition(DragView dragView, final View child,
             final Runnable onFinishAnimationRunnable) {
         ((CellLayoutChildren) child.getParent()).measureChild(child);
@@ -373,18 +399,6 @@
         animateViewIntoPosition(dragView, fromX, fromY, toX, toY, scale, onCompleteRunnable, true);
     }
 
-    /* Just fade out in place */
-    public void animateViewOut(DragView dragView, Runnable onFinishAnimationRunnable) {
-        Rect r = new Rect();
-        getViewRectRelativeToSelf(dragView, r);
-        final int fromX = r.left;
-        final int fromY = r.top;
-        final int toX = fromX;
-        final int toY = fromY;
-        animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1.0f, onFinishAnimationRunnable,
-                true);
-    }
-
     private void animateViewIntoPosition(final View view, final int fromX, final int fromY,
             final int toX, final int toY, float finalScale, Runnable onCompleteRunnable,
             boolean fadeOut) {
@@ -394,6 +408,24 @@
         animateView(view, from, to, 1f, finalScale, -1, null, null, onCompleteRunnable, true);
     }
 
+    /**
+     * This method animates a view at the end of a drag and drop animation.
+     *
+     * @param view The view to be animated. This view is drawn directly into DragLayer, and so
+     *        doesn't need to be a child of DragLayer.
+     * @param from The initial location of the view. Only the left and top parameters are used.
+     * @param to The final location of the view. Only the left and top parameters are used. This
+     *        location doesn't account for scaling, and so should be centered about the desired
+     *        final location (including scaling).
+     * @param finalAlpha The final alpha of the view, in case we want it to fade as it animates.
+     * @param finalScale The final scale of the view. The view is scaled about its center.
+     * @param duration The duration of the animation.
+     * @param motionInterpolator The interpolator to use for the location of the view.
+     * @param alphaInterpolator The interpolator to use for the alpha of the view.
+     * @param onCompleteRunnable Optional runnable to run on animation completion.
+     * @param fadeOut Whether or not to fade out the view once the animation completes. If true,
+     *        the runnable will execute after the view is faded out.
+     */
     public void animateView(final View view, final Rect from, final Rect to, final float finalAlpha,
             final float finalScale, int duration, final Interpolator motionInterpolator,
             final Interpolator alphaInterpolator, final Runnable onCompleteRunnable,
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index dd0bffd..7641fe7 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -35,6 +35,7 @@
 import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.View.MeasureSpec;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.DecelerateInterpolator;
 import android.view.inputmethod.EditorInfo;
@@ -730,20 +731,24 @@
         int centeredLeft = centerX - width / 2;
         int centeredTop = centerY - height / 2;
 
-        int parentWidth = 0;
-        int parentHeight = 0;
-        if (parent != null) {
-            parentWidth = parent.getMeasuredWidth();
-            parentHeight = parent.getMeasuredHeight();
-        }
+        // We first fetch the currently visible CellLayoutChildren
+        int page = mLauncher.getWorkspace().getCurrentPage();
+        CellLayout currentPage = (CellLayout) mLauncher.getWorkspace().getChildAt(page);
+        CellLayoutChildren boundingLayout = currentPage.getChildrenLayout();
+        Rect bounds = new Rect();
+        parent.getDescendantRectRelativeToSelf(boundingLayout, bounds);
 
-        int left = Math.min(Math.max(0, centeredLeft), parentWidth - width);
-        int top = Math.min(Math.max(0, centeredTop), parentHeight - height);
-        if (width >= parentWidth) {
-            left = (parentWidth - width) / 2;
+        // We need to bound the folder to the currently visible CellLayoutChildren
+        int left = Math.min(Math.max(bounds.left, centeredLeft),
+                bounds.left + bounds.width() - width);
+        int top = Math.min(Math.max(bounds.top, centeredTop),
+                bounds.top + bounds.height() - height);
+        // If the folder doesn't fit within the bounds, center it about the desired bounds
+        if (width >= bounds.width()) {
+            left = bounds.left + (bounds.width() - width) / 2;
         }
-        if (height >= parentHeight) {
-            top = (parentHeight - height) / 2;
+        if (height >= bounds.height()) {
+            top = bounds.top + (bounds.height() - height) / 2;
         }
 
         int folderPivotX = width / 2 + (centeredLeft - left);
@@ -779,6 +784,23 @@
         centerAboutIcon();
     }
 
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
+        // Technically there is no padding at the bottom, but we add space equal to the padding
+        // and have to account for that here.
+        int height = getPaddingTop() + mContent.getDesiredHeight() + mFolderNameHeight;
+
+        int contentWidthSpec = MeasureSpec.makeMeasureSpec(mContent.getDesiredWidth(),
+                MeasureSpec.EXACTLY);
+        int contentHeightSpec = MeasureSpec.makeMeasureSpec(mContent.getDesiredHeight(),
+                MeasureSpec.EXACTLY);
+        mContent.measure(contentWidthSpec, contentHeightSpec);
+
+        mFolderName.measure(contentWidthSpec,
+                MeasureSpec.makeMeasureSpec(mFolderNameHeight, MeasureSpec.EXACTLY));
+        setMeasuredDimension(width, height);
+    }
+
     private void arrangeChildren(ArrayList<View> list) {
         int[] vacant = new int[2];
         if (list == null) {
diff --git a/src/com/android/launcher2/PagedViewCellLayout.java b/src/com/android/launcher2/PagedViewCellLayout.java
index fc1b012..bec00ec 100644
--- a/src/com/android/launcher2/PagedViewCellLayout.java
+++ b/src/com/android/launcher2/PagedViewCellLayout.java
@@ -41,6 +41,8 @@
     private int mOriginalCellHeight;
     private int mCellWidth;
     private int mCellHeight;
+    private int mOriginalWidthGap;
+    private int mOriginalHeightGap;
     private int mWidthGap;
     private int mHeightGap;
     private int mMaxGap;
@@ -72,7 +74,7 @@
         mPeekWidth = resources.getDimensionPixelSize(R.dimen.apps_customize_peek_width);
         mCellCountX = LauncherModel.getCellCountX();
         mCellCountY = LauncherModel.getCellCountY();
-        mWidthGap = mHeightGap = -1;
+        mOriginalHeightGap = mOriginalHeightGap = mWidthGap = mHeightGap = -1;
         mMaxGap = resources.getDimensionPixelSize(R.dimen.apps_customize_max_gap);
 
         mChildren = new PagedViewCellLayoutChildren(context);
@@ -221,12 +223,10 @@
             throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
         }
 
-
-
         int numWidthGaps = mCellCountX - 1;
         int numHeightGaps = mCellCountY - 1;
 
-        if (mWidthGap < 0 || mHeightGap < 0) {
+        if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) {
             int hSpace = widthSpecSize - mPaddingLeft - mPaddingRight;
             int vSpace = heightSpecSize - mPaddingTop - mPaddingBottom;
             int hFreeSpace = hSpace - (mCellCountX * mOriginalCellWidth);
@@ -236,6 +236,9 @@
 
             mChildren.setGap(mWidthGap, mHeightGap);
             mHolographicChildren.setGap(mWidthGap, mHeightGap);
+        } else {
+            mWidthGap = mOriginalWidthGap;
+            mHeightGap = mOriginalHeightGap;
         }
 
         // Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index eeb5534..ba290d3 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -288,11 +288,13 @@
     public void onDragStart(DragSource source, Object info, int dragAction) {
         mIsDragOccuring = true;
         updateChildrenLayersEnabled();
+        mLauncher.lockScreenOrientation();
     }
 
     public void onDragEnd() {
         mIsDragOccuring = false;
         updateChildrenLayersEnabled();
+        mLauncher.unlockScreenOrientation();
     }
 
     /**
@@ -1187,7 +1189,7 @@
     }
 
     public boolean isSmall() {
-        return mState == State.SMALL;
+        return mState == State.SMALL || mState == State.SPRING_LOADED;
     }
 
     void enableChildrenCache(int fromPage, int toPage) {
@@ -1631,8 +1633,9 @@
             if (springLoaded) {
                 finalScaleFactor = mSpringLoadedShrinkFactor;
                 finalBackgroundAlpha = 1.0f;
+                mState = State.SPRING_LOADED;
             } else {
-                mState = springLoaded ? State.SPRING_LOADED : State.NORMAL;
+                mState = State.NORMAL;
             }
             if (mAnimator != null) {
                 mAnimator.cancel();
@@ -2003,7 +2006,6 @@
         mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),
                 DragController.DRAG_ACTION_MOVE, dragRect);
         b.recycle();
-        mLauncher.lockScreenOrientation();
     }
 
     void addApplicationShortcut(ShortcutInfo info, int screen, int cellX, int cellY,
@@ -2834,33 +2836,72 @@
                 mLauncher.exitSpringLoadedDragModeDelayed(false);
             }
         };
+
+        ItemInfo info = (ItemInfo) dragInfo;
+        int spanX = info.spanX;
+        int spanY = info.spanY;
+        if (mDragInfo != null) {
+            spanX = mDragInfo.spanX;
+            spanY = mDragInfo.spanY;
+        }
+
         final int screen = indexOfChild(cellLayout);
         if (screen != mCurrentPage && mState != State.SPRING_LOADED) {
             snapToPage(screen);
         }
-        if (dragInfo instanceof PendingAddItemInfo) {
-            final PendingAddItemInfo info = (PendingAddItemInfo) dragInfo;
-            mLauncher.getDragLayer().animateViewOut(d.dragView, new Runnable() {
+
+        if (info instanceof PendingAddItemInfo) {
+            final PendingAddItemInfo pendingInfo = (PendingAddItemInfo) dragInfo;
+
+            Runnable onAnimationCompleteRunnable = new Runnable() {
                 @Override
                 public void run() {
                     // When dragging and dropping from customization tray, we deal with creating
                     // widgets/shortcuts/folders in a slightly different way
-                    switch (info.itemType) {
+                    switch (pendingInfo.itemType) {
                     case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
-                        mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) info, screen, touchXY);
+                        mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) pendingInfo,
+                                screen, touchXY);
                         break;
                     case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
-                        mLauncher.processShortcutFromDrop(info.componentName, screen, touchXY);
+                        mLauncher.processShortcutFromDrop(pendingInfo.componentName,
+                                screen, touchXY);
                         break;
                     default:
-                        throw new IllegalStateException("Unknown item type: " + info.itemType);
+                        throw new IllegalStateException("Unknown item type: " +
+                                pendingInfo.itemType);
                     }
                     cellLayout.onDragExit();
                 }
-            });
+            };
+
+            // Now we animate the dragView, (ie. the widget or shortcut preview) into its final
+            // location and size on the home screen.
+
+            // The target cell is also calculated later in Launcher when the widget is actually
+            // added, however, we do it here as well to find out where to animate to. The re-use
+            // of this computation required to much restructuring.
+            mTargetCell = findNearestVacantArea(touchXY[0], touchXY[1], spanX, spanY, null,
+                    cellLayout, mTargetCell);
+
+            int loc[] = new int[2];
+            cellLayout.cellToPoint(mTargetCell[0], mTargetCell[1], loc);
+
+            RectF r = new RectF();
+            cellLayout.cellToRect(mTargetCell[0], mTargetCell[1], spanX, spanY, r);
+            float cellLayoutScale =
+                    mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(cellLayout, loc);
+
+            float dragViewScale =  r.width() / d.dragView.getMeasuredWidth();
+            // The animation will scale the dragView about its center, so we need to center about
+            // the final location.
+            loc[0] -= (d.dragView.getMeasuredWidth() - cellLayoutScale * r.width()) / 2;
+            loc[1] -= (d.dragView.getMeasuredHeight() - cellLayoutScale * r.height()) / 2;
+
+            mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, loc,
+                    dragViewScale * cellLayoutScale, onAnimationCompleteRunnable);
         } else {
             // This is for other drag/drop cases, like dragging from All Apps
-            ItemInfo info = (ItemInfo) dragInfo;
             View view = null;
 
             switch (info.itemType) {
@@ -2881,16 +2922,6 @@
                 throw new IllegalStateException("Unknown item type: " + info.itemType);
             }
 
-            int spanX = 1;
-            int spanY = 1;
-            if (mDragInfo != null) {
-                spanX = mDragInfo.spanX;
-                spanY = mDragInfo.spanY;
-            } else {
-                spanX = info.spanX;
-                spanY = info.spanY;
-            }
-
             // First we find the cell nearest to point at which the item is
             // dropped, without any consideration to whether there is an item there.
             if (touchXY != null) {
@@ -3004,7 +3035,6 @@
             doDragExit(null);
             ((CellLayout) getChildAt(mDragInfo.screen)).onDropChild(mDragInfo.cell);
         }
-        mLauncher.unlockScreenOrientation();
         mDragOutline = null;
         mDragInfo = null;
     }