Merge "Re-updating widget set in customization drawer when applications are changed."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 4918aab..4aa5d68 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -67,7 +67,7 @@
         android:process="@string/process"
         android:label="@string/application_name"
         android:icon="@drawable/ic_launcher_home"
-        android:hardwareAccelerated="@integer/config_hardwareAccelerated">
+        android:hardwareAccelerated="@bool/config_hardwareAccelerated">
 
         <activity
             android:name="com.android.launcher2.Launcher"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index b84e1b6..444dbd8 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -44,6 +44,8 @@
 #$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
 #$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
 
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Launcher2_intermediates)
+
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
+# ************************************************
\ No newline at end of file
diff --git a/proguard.flags b/proguard.flags
index 82411eb..22a7ddc 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -11,6 +11,23 @@
 -keep class com.android.launcher2.CellLayout {
   public float getBackgroundAlpha();
   public void setBackgroundAlpha(float);
+  public float getDimmableProgress();
+  public void setDimmableProgress(float);
+}
+
+-keep class com.android.launcher2.DimmableBubbleTextView {
+  public float getDimmableProgress();
+  public void setDimmableProgress(float);
+}
+
+-keep class com.android.launcher2.DimmableAppWidgetHostView {
+  public float getDimmableProgress();
+  public void setDimmableProgress(float);
+}
+
+-keep class com.android.launcher2.Workspace {
+  public float getBackgroundAlpha();
+  public void setBackgroundAlpha(float);
 }
 
 -keep class com.android.launcher2.AllApps3D$Defines {
@@ -19,4 +36,4 @@
 
 -keep class com.android.launcher2.ClippedImageView {
   *;
-}
+}
\ No newline at end of file
diff --git a/res/drawable/gardening_crosshairs.png b/res/drawable/gardening_crosshairs.png
new file mode 100644
index 0000000..cbaee78
--- /dev/null
+++ b/res/drawable/gardening_crosshairs.png
Binary files differ
diff --git a/res/values-xlarge/config.xml b/res/values-xlarge/config.xml
index 9b1bc0d..f6f6646 100644
--- a/res/values-xlarge/config.xml
+++ b/res/values-xlarge/config.xml
@@ -26,4 +26,16 @@
          animations between all apps, customize, & the workspace. -->
     <integer name="config_toolbarButtonFadeInTime">350</integer>
     <integer name="config_toolbarButtonFadeOutTime">350</integer>
+
+    <integer name="config_crosshairsFadeInTime">600</integer>
+
+    <!-- When dragging items on the workspace, how much bigger (in pixels) the dragged view
+         should be, as compared to the original view. If 0, it will not be scaled at all.
+         Should be an even number, for pixel alignment. -->
+    <integer name="config_dragViewExtraPixels">0</integer>
+
+    <!-- When dragging items on the workspace, the number of pixels by which the position of
+         the drag view should be offset from the position of the original view. -->
+    <integer name="config_dragViewOffsetX">0</integer>
+    <integer name="config_dragViewOffsetY">12</integer>
 </resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index f532fd6..db967ea 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -3,5 +3,16 @@
     <integer name="config_allAppsFadeOutTime">700</integer>
     <integer name="config_allAppsBatchLoadDelay">0</integer>
     <integer name="config_allAppsBatchSize">0</integer>
-    <integer name="config_hardwareAccelerated">0</integer>
+    <bool name="config_hardwareAccelerated">false</bool>
+
+    <!--  When dragging an item on the workspace, how much bigger (in pixels) the dragged view
+          should be, as compared to the original view. If 0, it will not be scaled at all.
+          Should be an even number, for pixel alignment. -->
+    <integer name="config_dragViewExtraPixels">40</integer>
+
+    <!-- When dragging items on the workspace, the number of pixels by which the position of
+         the drag view should be offset from the position of the original view.
+         Setting to 1/2 of config_dragViewExtraPixels keeps it centered on its old position. -->
+    <integer name="config_dragViewOffsetX">20</integer>
+    <integer name="config_dragViewOffsetY">20</integer>
 </resources>
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 585d1c3..84b26f2 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -18,15 +18,20 @@
 
 import com.android.launcher.R;
 
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.app.WallpaperManager;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.ContextMenu;
 import android.view.MotionEvent;
 import android.view.View;
@@ -58,9 +63,11 @@
     private final RectF mRectF = new RectF();
     private final CellInfo mCellInfo = new CellInfo();
 
-    // This is a temporary variable to prevent having to allocate a new object just to
-    // return an (x, y) value from helper functions. Do NOT use it to maintain other state.
+    // These are temporary variables to prevent having to allocate a new object just to
+    // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
     private final int[] mTmpCellXY = new int[2];
+    private final int[] mTmpPoint = new int[2];
+    private final PointF mTmpPointF = new PointF();
 
     boolean[][] mOccupied;
 
@@ -75,16 +82,14 @@
     private boolean mHover = false;
 
     private final RectF mDragRect = new RectF();
+    private final Point mDragCenter = new Point();
 
-    // When dragging, used to indicate a vacant drop location
-    private Drawable mVacantDrawable;
-
-    // When dragging, used to indicate an occupied drop location
-    private Drawable mOccupiedDrawable;
-
-    // Updated to point to mVacantDrawable or mOccupiedDrawable, as appropriate
     private Drawable mDragRectDrawable;
 
+    private Drawable mCrosshairsDrawable = null;
+    private ValueAnimator mCrosshairsAnimator = null;
+    private float mCrosshairsVisibility = 0.0f;
+
     // When a drag operation is in progress, holds the nearest cell to the touch point
     private final int[] mDragCell = new int[2];
 
@@ -104,15 +109,6 @@
         // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show
         // the user where a dragged item will land when dropped.
         setWillNotDraw(false);
-        mVacantDrawable = getResources().getDrawable(R.drawable.rounded_rect_green);
-        mOccupiedDrawable = getResources().getDrawable(R.drawable.rounded_rect_red);
-
-        if (LauncherApplication.isScreenXLarge()) {
-            mBackground = getResources().getDrawable(R.drawable.mini_home_screen_bg);
-            mBackground.setFilterBitmap(true);
-            mBackgroundHover = getResources().getDrawable(R.drawable.mini_home_screen_bg_hover);
-            mBackgroundHover.setFilterBitmap(true);
-        }
 
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
 
@@ -136,7 +132,29 @@
 
         setAlwaysDrawnWithCacheEnabled(false);
 
-        mWallpaperManager = WallpaperManager.getInstance(getContext());
+        mWallpaperManager = WallpaperManager.getInstance(context);
+
+        if (LauncherApplication.isScreenXLarge()) {
+            final Resources res = getResources();
+
+            mBackground = res.getDrawable(R.drawable.mini_home_screen_bg);
+            mBackground.setFilterBitmap(true);
+            mBackgroundHover = res.getDrawable(R.drawable.mini_home_screen_bg_hover);
+            mBackgroundHover.setFilterBitmap(true);
+
+            mDragRectDrawable = res.getDrawable(R.drawable.rounded_rect_green);
+            mCrosshairsDrawable = res.getDrawable(R.drawable.gardening_crosshairs);
+
+            // Set up the animation for fading the crosshairs in and out
+            int animDuration = res.getInteger(R.integer.config_crosshairsFadeInTime);
+            mCrosshairsAnimator = new ValueAnimator<Float>(animDuration);
+            mCrosshairsAnimator.addUpdateListener(new AnimatorUpdateListener() {
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    mCrosshairsVisibility = ((Float) animation.getAnimatedValue()).floatValue();
+                    CellLayout.this.invalidate();
+                }
+            });
+        }
     }
 
     public void setHover(boolean value) {
@@ -146,6 +164,15 @@
         mHover = value;
     }
 
+    private void animateCrosshairsTo(float value) {
+        final ValueAnimator anim = mCrosshairsAnimator;
+        long fullDuration = getResources().getInteger(R.integer.config_crosshairsFadeInTime);
+        anim.setDuration(fullDuration - anim.getCurrentPlayTime());
+        anim.setValues(mCrosshairsVisibility, value);
+        anim.cancel();
+        anim.start();
+    }
+
     @Override
     public void dispatchDraw(Canvas canvas) {
         if (mBackgroundAlpha > 0.0f) {
@@ -158,15 +185,47 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
-        if (!mDragRect.isEmpty()) {
-            mDragRectDrawable.setBounds(
-                    (int)mDragRect.left,
-                    (int)mDragRect.top,
-                    (int)mDragRect.right,
-                    (int)mDragRect.bottom);
-            mDragRectDrawable.draw(canvas);
+        if (mCrosshairsVisibility > 0.0f) {
+            final int countX = mCountX;
+            final int countY = mCountY;
+
+            if (!mDragRect.isEmpty()) {
+                mDragRectDrawable.setBounds(
+                        (int)mDragRect.left,
+                        (int)mDragRect.top,
+                        (int)mDragRect.right,
+                        (int)mDragRect.bottom);
+                mDragRectDrawable.setAlpha((int) (mCrosshairsVisibility * 255));
+                mDragRectDrawable.draw(canvas);
+            }
+
+            final float MAX_ALPHA = 0.4f;
+            final int MAX_VISIBLE_DISTANCE = 600;
+            final float DISTANCE_MULTIPLIER = 0.002f;
+
+            final Drawable d = mCrosshairsDrawable;
+            final int width = d.getIntrinsicWidth();
+            final int height = d.getIntrinsicHeight();
+
+            int x = getLeftPadding() - (mWidthGap / 2) - (width / 2);
+            for (int col = 0; col <= countX; col++) {
+                int y = getTopPadding() - (mHeightGap / 2) - (height / 2);
+                for (int row = 0; row <= countY; row++) {
+                    mTmpPointF.set(x - mDragCenter.x, y - mDragCenter.y);
+                    float dist = mTmpPointF.length();
+                    // Crosshairs further from the drag point are more faint
+                    float alpha = Math.min(MAX_ALPHA,
+                            DISTANCE_MULTIPLIER * (MAX_VISIBLE_DISTANCE - dist));
+                    if (alpha > 0.0f) {
+                        d.setBounds(x, y, x + width, y + height);
+                        d.setAlpha((int) (alpha * 255 * mCrosshairsVisibility));
+                        d.draw(canvas);
+                    }
+                    y += mCellHeight + mHeightGap;
+                }
+                x += mCellWidth + mWidthGap;
+            }
         }
-        super.onDraw(canvas);
     }
 
     @Override
@@ -193,7 +252,6 @@
         return mCountY;
     }
 
-    // Takes canonical layout parameters
     public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params) {
         final LayoutParams lp = params;
 
@@ -652,34 +710,24 @@
         result[1] = Math.max(0, result[1]); // Snap to top
     }
 
-    void visualizeDropLocation(
-            View view, int originX, int originY, int spanX, int spanY, View draggedItem) {
-        final int[] originCell = mDragCell;
-        final int[] cellXY = mTmpCellXY;
-        estimateDropCell(originX, originY, spanX, spanY, cellXY);
+    void visualizeDropLocation(View view, int originX, int originY, int spanX, int spanY) {
+        final int[] nearest = findNearestVacantArea(originX, originY, spanX, spanY, view, mDragCell);
+        mDragCenter.set(originX + (view.getWidth() / 2), originY + (view.getHeight() / 2));
 
-        // Only recalculate the bounding rect when necessary
-        if (!Arrays.equals(cellXY, originCell)) {
-            originCell[0] = cellXY[0];
-            originCell[1] = cellXY[1];
-
+        if (nearest != null) {
             // Find the top left corner of the rect the object will occupy
-            final int[] topLeft = mTmpCellXY;
-            cellToPoint(originCell[0], originCell[1], topLeft);
+            final int[] topLeft = mTmpPoint;
+            cellToPoint(nearest[0], nearest[1], topLeft);
+
+            // Need to copy these, because the next call to cellToPoint will overwrite them
             final int left = topLeft[0];
             final int top = topLeft[1];
 
             // Now find the bottom right
-            final int[] bottomRight = mTmpCellXY;
-            cellToPoint(originCell[0] + spanX - 1, originCell[1] + spanY - 1, bottomRight);
+            final int[] bottomRight = mTmpPoint;
+            cellToPoint(nearest[0] + spanX - 1, nearest[1] + spanY - 1, bottomRight);
             bottomRight[0] += mCellWidth;
             bottomRight[1] += mCellHeight;
-
-            boolean vacant =
-                isVacantIgnoring(originCell[0], originCell[1], spanX, spanY, draggedItem);
-            mDragRectDrawable = vacant ? mVacantDrawable : mOccupiedDrawable;
-
-            // mDragRect will be rendered in onDraw()
             mDragRect.set(left, top, bottomRight[0], bottomRight[1]);
             invalidate();
         }
@@ -693,14 +741,14 @@
      * @param pixelY The Y location at which you want to search for a vacant area.
      * @param spanX Horizontal span of the object.
      * @param spanY Vertical span of the object.
-     * @param vacantCells Pre-computed set of vacant cells to search.
-     * @param recycle Previously returned value to possibly recycle.
+     * @param result Array in which to place the result, or null (in which case a new array will
+     *        be allocated)
      * @return The X, Y cell of a vacant area that can contain this object,
      *         nearest the requested location.
      */
     int[] findNearestVacantArea(
-            int pixelX, int pixelY, int spanX, int spanY, int[] recycle) {
-        return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, recycle);
+            int pixelX, int pixelY, int spanX, int spanY, int[] result) {
+        return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result);
     }
 
     /**
@@ -711,27 +759,30 @@
      * @param pixelY The Y location at which you want to search for a vacant area.
      * @param spanX Horizontal span of the object.
      * @param spanY Vertical span of the object.
-     * @param vacantCells Pre-computed set of vacant cells to search.
-     * @param recycle Previously returned value to possibly recycle.
      * @param ignoreView Considers space occupied by this view as unoccupied
+     * @param result Previously returned value to possibly recycle.
      * @return The X, Y cell of a vacant area that can contain this object,
      *         nearest the requested location.
      */
     int[] findNearestVacantArea(
-            int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] recycle) {
+            int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
         if (ignoreView != null) {
             markCellsAsUnoccupiedForView(ignoreView);
         }
         // Keep track of best-scoring drop area
-        final int[] bestXY = recycle != null ? recycle : new int[2];
+        final int[] bestXY = result != null ? result : new int[2];
         double bestDistance = Double.MAX_VALUE;
 
-        for (int x = 0; x < mCountX - (spanX - 1); x++) {
+        final int countX = mCountX;
+        final int countY = mCountY;
+        final boolean[][] occupied = mOccupied;
+
+        for (int x = 0; x < countX - (spanX - 1); x++) {
             inner:
-            for (int y = 0; y < mCountY - (spanY - 1); y++) {
+            for (int y = 0; y < countY - (spanY - 1); y++) {
                 for (int i = 0; i < spanX; i++) {
                     for (int j = 0; j < spanY; j++) {
-                        if (mOccupied[x + i][y + j]) {
+                        if (occupied[x + i][y + j]) {
                             // small optimization: we can skip to below the row we just found
                             // an occupied cell
                             y += j;
@@ -891,12 +942,18 @@
         mDragCell[1] = -1;
 
         setHover(false);
-        mDragRect.setEmpty();
         invalidate();
+
+        // Fade out the drag indicators
+        if (mCrosshairsAnimator != null) {
+            animateCrosshairsTo(0.0f);
+        }
     }
 
     /**
      * Mark a child as having been dropped.
+     * At the beginning of the drag operation, the child may have been on another
+     * screen, but it is reparented before this method is called.
      *
      * @param child The child that is being dropped
      */
@@ -905,7 +962,6 @@
             LayoutParams lp = (LayoutParams) child.getLayoutParams();
             lp.isDragging = false;
             lp.dropped = true;
-            mDragRect.setEmpty();
             child.requestLayout();
         }
         onDragExit();
@@ -926,7 +982,19 @@
     void onDragChild(View child) {
         LayoutParams lp = (LayoutParams) child.getLayoutParams();
         lp.isDragging = true;
+    }
+
+    /**
+     * A drag event has begun over this layout.
+     * It may have begun over this layout (in which case onDragChild is called first),
+     * or it may have begun on another layout.
+     */
+    void onDragEnter(View dragView) {
         mDragRect.setEmpty();
+        // Fade in the drag indicators
+        if (mCrosshairsAnimator != null) {
+            animateCrosshairsTo(1.0f);
+        }
     }
 
     /**
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index 87b3473..185f704 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.os.Handler;
@@ -311,6 +310,8 @@
         }
 
         dragView.show(mWindowToken, (int)mMotionDownX, (int)mMotionDownY);
+
+        handleMoveEvent((int) mMotionDownX, (int) mMotionDownY);
     }
 
     /**
@@ -437,12 +438,68 @@
         return mMoveTarget != null && mMoveTarget.dispatchUnhandledMove(focused, direction);
     }
 
+    private void handleMoveEvent(int x, int y) {
+        mDragView.move(x, y);
+
+        // Drop on someone?
+        final int[] coordinates = mCoordinatesTemp;
+        DropTarget dropTarget = findDropTarget(x, y, coordinates);
+        if (dropTarget != null) {
+            DropTarget delegate = dropTarget.getDropTargetDelegate(
+                    mDragSource, coordinates[0], coordinates[1],
+                    (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
+            if (delegate != null) {
+                dropTarget = delegate;
+            }
+
+            if (mLastDropTarget != dropTarget) {
+                if (mLastDropTarget != null) {
+                    mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
+                        (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
+                }
+                dropTarget.onDragEnter(mDragSource, coordinates[0], coordinates[1],
+                    (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
+            }
+            dropTarget.onDragOver(mDragSource, coordinates[0], coordinates[1],
+                    (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
+        } else {
+            if (mLastDropTarget != null) {
+                mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
+                    (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
+            }
+        }
+        mLastDropTarget = dropTarget;
+
+        // Scroll, maybe, but not if we're in the delete region.
+        boolean inDeleteRegion = false;
+        if (mDeleteRegion != null) {
+            inDeleteRegion = mDeleteRegion.contains(x, y);
+        }
+        if (!inDeleteRegion && x < SCROLL_ZONE) {
+            if (mScrollState == SCROLL_OUTSIDE_ZONE) {
+                mScrollState = SCROLL_WAITING_IN_ZONE;
+                mScrollRunnable.setDirection(SCROLL_LEFT);
+                mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
+            }
+        } else if (!inDeleteRegion && x > mScrollView.getWidth() - SCROLL_ZONE) {
+            if (mScrollState == SCROLL_OUTSIDE_ZONE) {
+                mScrollState = SCROLL_WAITING_IN_ZONE;
+                mScrollRunnable.setDirection(SCROLL_RIGHT);
+                mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
+            }
+        } else {
+            if (mScrollState == SCROLL_WAITING_IN_ZONE) {
+                mScrollState = SCROLL_OUTSIDE_ZONE;
+                mScrollRunnable.setDirection(SCROLL_RIGHT);
+                mHandler.removeCallbacks(mScrollRunnable);
+            }
+        }
+    }
+
     /**
      * Call this from a drag source view.
      */
     public boolean onTouchEvent(MotionEvent ev) {
-        View scrollView = mScrollView;
-
         if (!mDragging) {
             return false;
         }
@@ -457,74 +514,15 @@
             mMotionDownX = screenX;
             mMotionDownY = screenY;
 
-            if ((screenX < SCROLL_ZONE) || (screenX > scrollView.getWidth() - SCROLL_ZONE)) {
+            if ((screenX < SCROLL_ZONE) || (screenX > mScrollView.getWidth() - SCROLL_ZONE)) {
                 mScrollState = SCROLL_WAITING_IN_ZONE;
                 mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
             } else {
                 mScrollState = SCROLL_OUTSIDE_ZONE;
             }
-
             break;
         case MotionEvent.ACTION_MOVE:
-            // Update the drag view.  Don't use the clamped pos here so the dragging looks
-            // like it goes off screen a little, intead of bumping up against the edge.
-            mDragView.move((int)ev.getRawX(), (int)ev.getRawY());
-
-            // Drop on someone?
-            final int[] coordinates = mCoordinatesTemp;
-            DropTarget dropTarget = findDropTarget(screenX, screenY, coordinates);
-            if (dropTarget != null) {
-                DropTarget delegate = dropTarget.getDropTargetDelegate(
-                        mDragSource, coordinates[0], coordinates[1],
-                        (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
-                if (delegate != null) {
-                    dropTarget = delegate;
-                }
-
-                if (mLastDropTarget == dropTarget) {
-                    dropTarget.onDragOver(mDragSource, coordinates[0], coordinates[1],
-                        (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
-                } else {
-                    if (mLastDropTarget != null) {
-                        mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
-                            (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
-                    }
-                    dropTarget.onDragEnter(mDragSource, coordinates[0], coordinates[1],
-                        (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
-                }
-            } else {
-                if (mLastDropTarget != null) {
-                    mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
-                        (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
-                }
-            }
-            mLastDropTarget = dropTarget;
-
-            // Scroll, maybe, but not if we're in the delete region.
-            boolean inDeleteRegion = false;
-            if (mDeleteRegion != null) {
-                inDeleteRegion = mDeleteRegion.contains(screenX, screenY);
-            }
-            if (!inDeleteRegion && screenX < SCROLL_ZONE) {
-                if (mScrollState == SCROLL_OUTSIDE_ZONE) {
-                    mScrollState = SCROLL_WAITING_IN_ZONE;
-                    mScrollRunnable.setDirection(SCROLL_LEFT);
-                    mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
-                }
-            } else if (!inDeleteRegion && screenX > scrollView.getWidth() - SCROLL_ZONE) {
-                if (mScrollState == SCROLL_OUTSIDE_ZONE) {
-                    mScrollState = SCROLL_WAITING_IN_ZONE;
-                    mScrollRunnable.setDirection(SCROLL_RIGHT);
-                    mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
-                }
-            } else {
-                if (mScrollState == SCROLL_WAITING_IN_ZONE) {
-                    mScrollState = SCROLL_OUTSIDE_ZONE;
-                    mScrollRunnable.setDirection(SCROLL_RIGHT);
-                    mHandler.removeCallbacks(mScrollRunnable);
-                }
-            }
-
+            handleMoveEvent(screenX, screenY);
             break;
         case MotionEvent.ACTION_UP:
             mHandler.removeCallbacks(mScrollRunnable);
diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java
index d14f5f7..ca0e7b4 100644
--- a/src/com/android/launcher2/DragView.java
+++ b/src/com/android/launcher2/DragView.java
@@ -17,7 +17,10 @@
 
 package com.android.launcher2;
 
+import com.android.launcher.R;
+
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
@@ -31,9 +34,6 @@
 import android.view.WindowManagerImpl;
 
 public class DragView extends View implements TweenCallback {
-    // Number of pixels to add to the dragged item for scaling.  Should be even for pixel alignment.
-    private static final int DRAG_SCALE = 40;
-
     private Bitmap mBitmap;
     private Paint mPaint;
     private int mRegistrationX;
@@ -66,21 +66,24 @@
             int left, int top, int width, int height) {
         super(context);
 
+        final Resources res = getResources();
+        final int dragScale = res.getInteger(R.integer.config_dragViewExtraPixels);
+
         mWindowManager = WindowManagerImpl.getDefault();
         
         mTween = new SymmetricalLinearTween(false, 110 /*ms duration*/, this);
 
         Matrix scale = new Matrix();
         float scaleFactor = width;
-        scaleFactor = mScale = (scaleFactor + DRAG_SCALE) / scaleFactor;
+        scaleFactor = mScale = (scaleFactor + dragScale) / scaleFactor;
         scale.setScale(scaleFactor, scaleFactor);
 
         mBitmap = Bitmap.createBitmap(bitmap, left, top, width, height, scale, true);
         setDragRegion(0, 0, width, height);
 
         // The point in our scaled bitmap that the touch events are located
-        mRegistrationX = registrationX + (DRAG_SCALE / 2);
-        mRegistrationY = registrationY + (DRAG_SCALE / 2);
+        mRegistrationX = registrationX + res.getInteger(R.integer.config_dragViewOffsetX);
+        mRegistrationY = registrationY + res.getInteger(R.integer.config_dragViewOffsetY);
     }
 
     public void setDragRegion(int left, int top, int width, int height) {
diff --git a/src/com/android/launcher2/LauncherAppWidgetHost.java b/src/com/android/launcher2/LauncherAppWidgetHost.java
index 29ffe6e..9352ec2 100644
--- a/src/com/android/launcher2/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher2/LauncherAppWidgetHost.java
@@ -30,7 +30,7 @@
     public LauncherAppWidgetHost(Context context, int hostId) {
         super(context, hostId);
     }
-    
+
     @Override
     protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
             AppWidgetProviderInfo appWidget) {
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 356286d..4d820cf 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -19,10 +19,10 @@
 import com.android.launcher.R;
 
 import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
-import android.animation.Animator.AnimatorListener;
 import android.app.WallpaperManager;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
@@ -44,7 +44,6 @@
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewGroup;
 import android.widget.TextView;
 
 import java.util.ArrayList;
@@ -736,6 +735,7 @@
 
         current.onDragChild(child);
         mDragController.startDrag(child, this, child.getTag(), DragController.DRAG_ACTION_MOVE);
+        current.onDragEnter(child);
         invalidate();
     }
 
@@ -809,6 +809,7 @@
 
     public void onDragEnter(DragSource source, int x, int y, int xOffset,
             int yOffset, DragView dragView, Object dragInfo) {
+        getCurrentDropLayout().onDragEnter(dragView);
     }
 
     public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
@@ -852,7 +853,6 @@
         return null;
     }
 
-
     private void mapPointGlobalToLocal(View v, float[] xy) {
         xy[0] = xy[0] + mScrollX - v.getLeft();
         xy[1] = xy[1] + mScrollY - v.getTop();
@@ -983,6 +983,7 @@
         if (currentLayout != mDragTargetLayout) {
             if (mDragTargetLayout != null) {
                 mDragTargetLayout.onDragExit();
+                currentLayout.onDragEnter(dragView);
             }
             mDragTargetLayout = currentLayout;
         }
@@ -995,7 +996,7 @@
             int localOriginX = originX - (mDragTargetLayout.getLeft() - mScrollX);
             int localOriginY = originY - (mDragTargetLayout.getTop() - mScrollY);
             mDragTargetLayout.visualizeDropLocation(
-                    child, localOriginX, localOriginY, item.spanX, item.spanY, child);
+                    child, localOriginX, localOriginY, item.spanX, item.spanY);
         }
     }
 
@@ -1085,7 +1086,7 @@
         if (view == null) {
             cellLayout.onDragExit();
         } else {
-            mTargetCell = findNearestVacantArea(x, y, 1, 1, view, cellLayout, mTargetCell);
+            mTargetCell = findNearestVacantArea(x, y, 1, 1, null, cellLayout, mTargetCell);
             addInScreen(view, indexOfChild(cellLayout), mTargetCell[0],
                     mTargetCell[1], info.spanX, info.spanY, insertAtFirst);
             cellLayout.onDropChild(view);