Move the drag thing into its own window that goes around on top of everything else.
diff --git a/src/com/android/launcher2/AllAppsGridView.java b/src/com/android/launcher2/AllAppsGridView.java
index cca9ed2..711e213 100644
--- a/src/com/android/launcher2/AllAppsGridView.java
+++ b/src/com/android/launcher2/AllAppsGridView.java
@@ -30,8 +30,9 @@
 public class AllAppsGridView extends GridView implements AdapterView.OnItemClickListener,
         AdapterView.OnItemLongClickListener, DragSource {
 
-    private DragController mDragger;
+    private DragController mDragController;
     private Launcher mLauncher;
+    private boolean mDraw = true;
 
     public AllAppsGridView(Context context) {
         super(context);
@@ -64,20 +65,33 @@
         ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position);
         app = new ApplicationInfo(app);
 
-        mDragger.startDrag(view, this, app, DragController.DRAG_ACTION_COPY);
-        mLauncher.closeAllApplications();
-
+        mDragController.startDrag(view, this, app, DragController.DRAG_ACTION_COPY);
+        mLauncher.showWorkspace();
+        mDraw = false;
+        invalidate();
         return true;
     }
 
-    public void setDragger(DragController dragger) {
-        mDragger = dragger;
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        if (mDraw) {
+            super.dispatchDraw(canvas);
+        }
+    }
+
+    public void setDragController(DragController dragController) {
+        mDragController = dragController;
     }
 
     public void onDropCompleted(View target, boolean success) {
+        mLauncher.closeAllAppsDialog(false);
     }
 
     void setLauncher(Launcher launcher) {
         mLauncher = launcher;
     }
+
+    void onPrepareDialog() {
+        mDraw = true;
+    }
 }
diff --git a/src/com/android/launcher2/DeleteZone.java b/src/com/android/launcher2/DeleteZone.java
index f726625..8a2545f 100644
--- a/src/com/android/launcher2/DeleteZone.java
+++ b/src/com/android/launcher2/DeleteZone.java
@@ -19,6 +19,9 @@
 import android.widget.ImageView;
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.View;
@@ -46,15 +49,12 @@
     private Animation mHandleOutAnimation;
 
     private int mOrientation;
-    private DragLayer mDragLayer;
+    private DragController mDragController;
 
     private final RectF mRegion = new RectF();
     private TransitionDrawable mTransition;
     private View mHandle;
-
-    public DeleteZone(Context context) {
-        super(context);
-    }
+    private final Paint mTrashPaint = new Paint();
 
     public DeleteZone(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -63,6 +63,9 @@
     public DeleteZone(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
+        final int srcColor = context.getResources().getColor(R.color.delete_color_filter);
+        mTrashPaint.setColorFilter(new PorterDuffColorFilter(srcColor, PorterDuff.Mode.SRC_ATOP));
+
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DeleteZone, defStyle, 0);
         mOrientation = a.getInt(R.styleable.DeleteZone_direction, ORIENTATION_HORIZONTAL);
         a.recycle();
@@ -75,15 +78,17 @@
     }
 
     public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
-            Object dragInfo) {
+            DragView dragView, Object dragInfo) {
         return true;
     }
     
-    public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo, Rect recycle) {
+    public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo, Rect recycle) {
         return null;
     }
 
-    public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
+    public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo) {
         final ItemInfo item = (ItemInfo) dragInfo;
 
         if (item.container == -1) return;
@@ -117,17 +122,19 @@
     }
 
     public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
-            Object dragInfo) {
+            DragView dragView, Object dragInfo) {
         mTransition.reverseTransition(TRANSITION_DURATION);
+        dragView.setPaint(mTrashPaint);
     }
 
     public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
-            Object dragInfo) {
+            DragView dragView, Object dragInfo) {
     }
 
     public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
-            Object dragInfo) {
+            DragView dragView, Object dragInfo) {
         mTransition.reverseTransition(TRANSITION_DURATION);
+        dragView.setPaint(null);
     }
 
     public void onDragStart(View v, DragSource source, Object info, int dragAction) {
@@ -139,7 +146,7 @@
             getLocationOnScreen(location);
             mRegion.set(location[0], location[1], location[0] + mRight - mLeft,
                     location[1] + mBottom - mTop);
-            mDragLayer.setDeleteRegion(mRegion);
+            mDragController.setDeleteRegion(mRegion);
             mTransition.resetTransition();
             startAnimation(mInAnimation);
             mHandle.startAnimation(mHandleOutAnimation);
@@ -150,7 +157,7 @@
     public void onDragEnd() {
         if (mTrashMode) {
             mTrashMode = false;
-            mDragLayer.setDeleteRegion(null);
+            mDragController.setDeleteRegion(null);
             startAnimation(mOutAnimation);
             mHandle.startAnimation(mHandleInAnimation);
             setVisibility(GONE);
@@ -221,8 +228,8 @@
         mLauncher = launcher;
     }
 
-    void setDragController(DragLayer dragLayer) {
-        mDragLayer = dragLayer;
+    void setDragController(DragController dragController) {
+        mDragController = dragController;
     }
 
     void setHandle(View view) {
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index f8c8077..da2df5c 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -16,14 +16,108 @@
 
 package com.android.launcher2;
 
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.os.IBinder;
+import android.os.Handler;
+import android.os.Vibrator;
+import android.os.SystemClock;
+import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
+import android.view.ViewGroup;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import java.util.ArrayList;
 
 /**
- * Interface for initiating a drag within a view or across multiple views.
- *
+ * Class for initiating a drag within a view or across multiple views.
  */
-public interface DragController {
-    
+public class DragController {
+    /** Indicates the drag is a move.  */
+    public static int DRAG_ACTION_MOVE = 0;
+
+    /** Indicates the drag is a copy.  */
+    public static int DRAG_ACTION_COPY = 1;
+
+    private static final int SCROLL_DELAY = 600;
+    private static final int SCROLL_ZONE = 20;
+    private static final int VIBRATE_DURATION = 35;
+
+    private static final boolean PROFILE_DRAWING_DURING_DRAG = false;
+
+    private static final int SCROLL_OUTSIDE_ZONE = 0;
+    private static final int SCROLL_WAITING_IN_ZONE = 1;
+
+    private static final int SCROLL_LEFT = 0;
+    private static final int SCROLL_RIGHT = 1;
+
+    private Context mContext;
+    private Handler mHandler;
+    private final Vibrator mVibrator = new Vibrator();
+
+    // temporaries to avoid gc thrash
+    private Rect mRectTemp = new Rect();
+    private final int[] mCoordinatesTemp = new int[2];
+
+    /** Whether or not we're dragging. */
+    private boolean mDragging;
+
+    /** X coordinate of the down event. */
+    private float mMotionDownX;
+
+    /** Y coordinate of the down event. */
+    private float mMotionDownY;
+
+    /** Original view that is being dragged.  */
+    private View mOriginator;
+
+    /** The contents of mOriginator with no scaling.  */
+    private Bitmap mDragBitmap;
+
+    /** X offset from the upper-left corner of the cell to where we touched.  */
+    private float mTouchOffsetX;
+
+    /** Y offset from the upper-left corner of the cell to where we touched.  */
+    private float mTouchOffsetY;
+
+    /** Where the drag originated */
+    private DragSource mDragSource;
+
+    /** The data associated with the object being dragged */
+    private Object mDragInfo;
+
+    /** The view that moves around while you drag.  */
+    private DragView mDragView;
+
+    /** Who can receive drop events */
+    private ArrayList<DropTarget> mDropTargets = new ArrayList<DropTarget>();
+
+    private DragListener mListener;
+
+    /** The window token used as the parent for the DragView. */
+    private IBinder mWindowToken;
+
+    /** The view that will be scrolled when dragging to the left and right edges of the screen. */
+    private View mScrollView;
+
+    private DragScroller mDragScroller;
+    private int mScrollState = SCROLL_OUTSIDE_ZONE;
+    private ScrollRunnable mScrollRunnable = new ScrollRunnable();
+
+    private RectF mDeleteRegion;
+    private DropTarget mLastDropTarget;
+
+    private InputMethodManager mInputMethodManager;
+
     /**
      * Interface to receive notifications when a drag starts or stops
      */
@@ -47,14 +141,15 @@
     }
     
     /**
-     * Indicates the drag is a move.
+     * Used to create a new DragLayer from XML.
+     *
+     * @param context The application's context.
+     * @param attrs The attribtues set containing the Workspace's customization values.
      */
-    public static int DRAG_ACTION_MOVE = 0;
-
-    /**
-     * Indicates the drag is a copy.
-     */
-    public static int DRAG_ACTION_COPY = 1;
+    public DragController(Context context) {
+        mContext = context;
+        mHandler = new Handler();
+    }
 
     /**
      * Starts a drag
@@ -65,15 +160,355 @@
      * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
      *        {@link #DRAG_ACTION_COPY}
      */
-    void startDrag(View v, DragSource source, Object info, int dragAction);
-    
+    public void startDrag(View v, DragSource source, Object dragInfo, int dragAction) {
+        if (PROFILE_DRAWING_DURING_DRAG) {
+            android.os.Debug.startMethodTracing("Launcher");
+        }
+
+        // Hide soft keyboard, if visible
+        if (mInputMethodManager == null) {
+            mInputMethodManager = (InputMethodManager)
+                    mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
+        }
+        mInputMethodManager.hideSoftInputFromWindow(mWindowToken, 0);
+
+        if (mListener != null) {
+            mListener.onDragStart(v, source, dragInfo, dragAction);
+        }
+
+        int[] loc = mCoordinatesTemp;
+        v.getLocationOnScreen(loc);
+        int screenX = loc[0];
+        int screenY = loc[1];
+
+        int registrationX = ((int)mMotionDownX) - screenX;
+        int registrationY = ((int)mMotionDownY) - screenY;
+
+        mTouchOffsetX = mMotionDownX - screenX;
+        mTouchOffsetY = mMotionDownY - screenY;
+
+        mDragging = true;
+        mOriginator = v;
+        mDragSource = source;
+        mDragInfo = dragInfo;
+
+        mVibrator.vibrate(VIBRATE_DURATION);
+
+        mDragBitmap = getViewBitmap(v);
+        DragView dragView = mDragView = new DragView(mContext, mDragBitmap,
+                registrationX, registrationY);
+        dragView.show(mWindowToken, (int)mMotionDownX, (int)mMotionDownY);
+
+        if (dragAction == DRAG_ACTION_MOVE) {
+            v.setVisibility(View.GONE);
+        }
+    }
+
+    /**
+     * Draw the view into a bitmap.
+     */
+    private Bitmap getViewBitmap(View v) {
+        v.clearFocus();
+        v.setPressed(false);
+
+        boolean willNotCache = v.willNotCacheDrawing();
+        v.setWillNotCacheDrawing(false);
+
+        // Reset the drawing cache background color to fully transparent
+        // for the duration of this operation
+        int color = v.getDrawingCacheBackgroundColor();
+        v.setDrawingCacheBackgroundColor(0);
+
+        if (color != 0) {
+            v.destroyDrawingCache();
+        }
+        v.buildDrawingCache();
+        Bitmap cacheBitmap = v.getDrawingCache();
+
+        Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
+
+        // Restore the view
+        v.destroyDrawingCache();
+        v.setWillNotCacheDrawing(willNotCache);
+        v.setDrawingCacheBackgroundColor(color);
+
+        return bitmap;
+    }
+
+    /**
+     * Call this from a drag source view like this:
+     *
+     * <pre>
+     *  @Override
+     *  public boolean dispatchKeyEvent(KeyEvent event) {
+     *      return mDragController.dispatchKeyEvent(this, event)
+     *              || super.dispatchKeyEvent(event);
+     * </pre>
+     */
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        return mDragging;
+    }
+
+    private void endDrag() {
+        if (mDragging) {
+            mDragging = false;
+            if (mOriginator != null) {
+                mOriginator.setVisibility(View.VISIBLE);
+            }
+            if (mListener != null) {
+                mListener.onDragEnd();
+            }
+            if (mDragView != null) {
+                mDragView.remove();
+                mDragView = null;
+            }
+            if (mDragBitmap != null) {
+                mDragBitmap.recycle();
+                mDragBitmap = null;
+            }
+        }
+    }
+
+    /**
+     * Call this from a drag source view.
+     */
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        final int action = ev.getAction();
+
+        final float screenX = ev.getRawX();
+        final float screenY = ev.getRawY();
+
+        switch (action) {
+            case MotionEvent.ACTION_MOVE:
+                break;
+
+            case MotionEvent.ACTION_DOWN:
+                // Remember location of down touch
+                mMotionDownX = screenX;
+                mMotionDownY = screenY;
+                mLastDropTarget = null;
+                break;
+
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                if (mDragging) {
+                    drop(screenX, screenY);
+                }
+                endDrag();
+                break;
+        }
+
+        return mDragging;
+    }
+
+    /**
+     * Call this from a drag source view.
+     */
+    public boolean onTouchEvent(MotionEvent ev) {
+        View scrollView = mScrollView;
+
+        if (!mDragging) {
+            return false;
+        }
+
+        final int action = ev.getAction();
+        final float x = ev.getRawX();
+        final float y = ev.getRawY();
+
+        switch (action) {
+        case MotionEvent.ACTION_DOWN:
+
+            // Remember where the motion event started
+            mMotionDownX = x;
+            mMotionDownY = y;
+
+            if ((x < SCROLL_ZONE) || (x > scrollView.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.
+            mDragView.move((int)ev.getRawX(), (int)ev.getRawY());
+
+            // Drop on someone?
+            final int[] coordinates = mCoordinatesTemp;
+            DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates);
+            if (dropTarget != null) {
+                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(ev.getRawX(), ev.getRawY());
+            }
+            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 > 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);
+                }
+            }
+
+            break;
+        case MotionEvent.ACTION_UP:
+            mHandler.removeCallbacks(mScrollRunnable);
+            if (mDragging) {
+                drop(x, y);
+            }
+            endDrag();
+
+            break;
+        case MotionEvent.ACTION_CANCEL:
+            endDrag();
+        }
+
+        return true;
+    }
+
+    private boolean drop(float x, float y) {
+        final int[] coordinates = mCoordinatesTemp;
+        DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates);
+
+        if (dropTarget != null) {
+            dropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
+                    (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
+            if (dropTarget.acceptDrop(mDragSource, coordinates[0], coordinates[1],
+                    (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo)) {
+                dropTarget.onDrop(mDragSource, coordinates[0], coordinates[1],
+                        (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
+                mDragSource.onDropCompleted((View) dropTarget, true);
+                return true;
+            } else {
+                mDragSource.onDropCompleted((View) dropTarget, false);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private DropTarget findDropTarget(int x, int y, int[] dropCoordinates) {
+        final Rect r = mRectTemp;
+
+        final ArrayList<DropTarget> dropTargets = mDropTargets;
+        final int count = dropTargets.size();
+        for (int i=count-1; i>=0; i--) {
+            final DropTarget target = dropTargets.get(i);
+            target.getHitRect(r);
+            target.getLocationOnScreen(dropCoordinates);
+            r.offset(dropCoordinates[0] - target.getLeft(), dropCoordinates[1] - target.getTop());
+            if (r.contains(x, y)) {
+                dropCoordinates[0] = x - dropCoordinates[0];
+                dropCoordinates[1] = y - dropCoordinates[1];
+                return target;
+            }
+        }
+        return null;
+    }
+
+    public void setDragScoller(DragScroller scroller) {
+        mDragScroller = scroller;
+    }
+
+    public void setWindowToken(IBinder token) {
+        mWindowToken = token;
+    }
+
     /**
      * Sets the drag listner which will be notified when a drag starts or ends.
      */
-    void setDragListener(DragListener l);
-    
+    public void setDragListener(DragListener l) {
+        mListener = l;
+    }
+
     /**
      * Remove a previously installed drag listener.
      */
-    void removeDragListener(DragListener l);
+    public void removeDragListener(DragListener l) {
+        mListener = null;
+    }
+
+    /**
+     * Add a DropTarget to the list of potential places to receive drop events.
+     */
+    public void addDropTarget(DropTarget target) {
+        mDropTargets.add(target);
+    }
+
+    /**
+     * Don't send drop events to <em>target</em> any more.
+     */
+    public void removeDropTarget(DropTarget target) {
+        mDropTargets.remove(target);
+    }
+
+    /**
+     * Set which view scrolls for touch events near the edge of the screen.
+     */
+    public void setScrollView(View v) {
+        mScrollView = v;
+    }
+
+    /**
+     * Specifies the delete region.  We won't scroll on touch events over the delete region.
+     *
+     * @param region The rectangle in screen coordinates of the delete region.
+     */
+    void setDeleteRegion(RectF region) {
+        mDeleteRegion = region;
+    }
+
+    private class ScrollRunnable implements Runnable {
+        private int mDirection;
+
+        ScrollRunnable() {
+        }
+
+        public void run() {
+            if (mDragScroller != null) {
+                if (mDirection == SCROLL_LEFT) {
+                    mDragScroller.scrollLeft();
+                } else {
+                    mDragScroller.scrollRight();
+                }
+                mScrollState = SCROLL_OUTSIDE_ZONE;
+            }
+        }
+
+        void setDirection(int direction) {
+            mDirection = direction;
+        }
+    }
 }
diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java
index fee8632..2839711 100644
--- a/src/com/android/launcher2/DragLayer.java
+++ b/src/com/android/launcher2/DragLayer.java
@@ -39,114 +39,9 @@
 /**
  * A ViewGroup that coordinated dragging across its dscendants
  */
-public class DragLayer extends FrameLayout implements DragController {
-    private static final int SCROLL_DELAY = 600;
-    private static final int SCROLL_ZONE = 20;
-    private static final int VIBRATE_DURATION = 35;
-    private static final int ANIMATION_SCALE_UP_DURATION = 110;
+public class DragLayer extends FrameLayout {
 
-    private static final boolean PROFILE_DRAWING_DURING_DRAG = false;
-
-    // Number of pixels to add to the dragged item for scaling
-    private static final float DRAG_SCALE = 24.0f;
-
-    private boolean mDragging = false;
-    private boolean mShouldDrop;
-    private float mLastMotionX;
-    private float mLastMotionY;
-
-    /**
-     * The bitmap that is currently being dragged
-     */
-    private Bitmap mDragBitmap = null;
-    private View mOriginator;
-
-    private int mBitmapOffsetX;
-    private int mBitmapOffsetY;
-
-    /**
-     * X offset from where we touched on the cell to its upper-left corner
-     */
-    private float mTouchOffsetX;
-
-    /**
-     * Y offset from where we touched on the cell to its upper-left corner
-     */
-    private float mTouchOffsetY;
-
-    /**
-     * Utility rectangle
-     */
-    private Rect mDragRect = new Rect();
-
-    /**
-     * Where the drag originated
-     */
-    private DragSource mDragSource;
-
-    /**
-     * The data associated with the object being dragged
-     */
-    private Object mDragInfo;
-
-    private final Rect mRect = new Rect();
-    private final int[] mDropCoordinates = new int[2];
-
-    private final Vibrator mVibrator = new Vibrator();
-
-    private DragListener mListener;
-
-    private DragScroller mDragScroller;
-
-    private static final int SCROLL_OUTSIDE_ZONE = 0;
-    private static final int SCROLL_WAITING_IN_ZONE = 1;
-
-    private static final int SCROLL_LEFT = 0;
-    private static final int SCROLL_RIGHT = 1;
-
-    private int mScrollState = SCROLL_OUTSIDE_ZONE;
-
-    private ScrollRunnable mScrollRunnable = new ScrollRunnable();
-    private View mIgnoredDropTarget;
-
-    private RectF mDragRegion;
-    private boolean mEnteredRegion;
-    private DropTarget mLastDropTarget;
-
-    private final Paint mTrashPaint = new Paint();
-    private final Paint mEstimatedPaint = new Paint();
-    private Paint mDragPaint;
-
-    /**
-     * If true, draw a "snag" showing where the object currently being dragged
-     * would end up if dropped from current location.
-     */
-    private static final boolean DRAW_TARGET_SNAG = false;
-
-    private Rect mEstimatedRect = new Rect();
-    private float[] mDragCenter = new float[2];
-    private float[] mEstimatedCenter = new float[2];
-    private boolean mDrawEstimated = false;
-
-    private int mTriggerWidth = -1;
-    private int mTriggerHeight = -1;
-
-    private static final int DISTANCE_DRAW_SNAG = 20;
-
-    private static final int ANIMATION_STATE_STARTING = 1;
-    private static final int ANIMATION_STATE_RUNNING = 2;
-    private static final int ANIMATION_STATE_DONE = 3;
-
-    private static final int ANIMATION_TYPE_SCALE = 1;
-
-    private float mAnimationFrom;
-    private float mAnimationTo;
-    private int mAnimationDuration;
-    private long mAnimationStartTime;
-    private int mAnimationType;
-    private int mAnimationState = ANIMATION_STATE_DONE;
-
-    private InputMethodManager mInputMethodManager;
+    DragController mDragController;
 
     /**
      * Used to create a new DragLayer from XML.
@@ -156,478 +51,24 @@
      */
     public DragLayer(Context context, AttributeSet attrs) {
         super(context, attrs);
-
-        final int srcColor = context.getResources().getColor(R.color.delete_color_filter);
-        mTrashPaint.setColorFilter(new PorterDuffColorFilter(srcColor, PorterDuff.Mode.SRC_ATOP));
-
-        // Make estimated paint area in gray
-        int snagColor = context.getResources().getColor(R.color.snag_callout_color);
-        mEstimatedPaint.setColor(snagColor);
-        mEstimatedPaint.setStrokeWidth(3);
-        mEstimatedPaint.setAntiAlias(true);
-
     }
 
-    public void startDrag(View v, DragSource source, Object dragInfo, int dragAction) {
-        if (PROFILE_DRAWING_DURING_DRAG) {
-            android.os.Debug.startMethodTracing("Launcher");
-        }
-
-        // Hide soft keyboard, if visible
-        if (mInputMethodManager == null) {
-            mInputMethodManager = (InputMethodManager)
-                getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
-        }
-        mInputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
-
-        if (mListener != null) {
-            mListener.onDragStart(v, source, dragInfo, dragAction);
-        }
-
-        Rect r = mDragRect;
-        r.set(v.getScrollX(), v.getScrollY(), 0, 0);
-
-        offsetDescendantRectToMyCoords(v, r);
-        mTouchOffsetX = mLastMotionX - r.left;
-        mTouchOffsetY = mLastMotionY - r.top;
-
-        v.clearFocus();
-        v.setPressed(false);
-
-        boolean willNotCache = v.willNotCacheDrawing();
-        v.setWillNotCacheDrawing(false);
-
-        // Reset the drawing cache background color to fully transparent
-        // for the duration of this operation
-        int color = v.getDrawingCacheBackgroundColor();
-        v.setDrawingCacheBackgroundColor(0);
-
-        if (color != 0) {
-            v.destroyDrawingCache();
-        }
-        v.buildDrawingCache();
-        Bitmap viewBitmap = v.getDrawingCache();
-        int width = viewBitmap.getWidth();
-        int height = viewBitmap.getHeight();
-
-        mTriggerWidth = width * 2 / 3;
-        mTriggerHeight = height * 2 / 3;
-
-        Matrix scale = new Matrix();
-        float scaleFactor = v.getWidth();
-        scaleFactor = (scaleFactor + DRAG_SCALE) /scaleFactor;
-        scale.setScale(scaleFactor, scaleFactor);
-
-        mAnimationTo = 1.0f;
-        mAnimationFrom = 1.0f / scaleFactor;
-        mAnimationDuration = ANIMATION_SCALE_UP_DURATION;
-        mAnimationState = ANIMATION_STATE_STARTING;
-        mAnimationType = ANIMATION_TYPE_SCALE;
-
-        mDragBitmap = Bitmap.createBitmap(viewBitmap, 0, 0, width, height, scale, true);
-        v.destroyDrawingCache();
-        v.setWillNotCacheDrawing(willNotCache);
-        v.setDrawingCacheBackgroundColor(color);
-
-        final Bitmap dragBitmap = mDragBitmap;
-        mBitmapOffsetX = (dragBitmap.getWidth() - width) / 2;
-        mBitmapOffsetY = (dragBitmap.getHeight() - height) / 2;
-
-        if (dragAction == DRAG_ACTION_MOVE) {
-            v.setVisibility(GONE);
-        }
-
-        mDragPaint = null;
-        mDragging = true;
-        mShouldDrop = true;
-        mOriginator = v;
-        mDragSource = source;
-        mDragInfo = dragInfo;
-
-        mVibrator.vibrate(VIBRATE_DURATION);
-
-        mEnteredRegion = false;
-
-        invalidate();
+    public void setDragController(DragController controller) {
+        mDragController = controller;
     }
-
+    
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
-        return mDragging || super.dispatchKeyEvent(event);
-    }
-
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        super.dispatchDraw(canvas);
-
-        if (mDragging && mDragBitmap != null) {
-            if (mAnimationState == ANIMATION_STATE_STARTING) {
-                mAnimationStartTime = SystemClock.uptimeMillis();
-                mAnimationState = ANIMATION_STATE_RUNNING;
-            }
-
-            if (mAnimationState == ANIMATION_STATE_RUNNING) {
-                float normalized = (float) (SystemClock.uptimeMillis() - mAnimationStartTime) /
-                        mAnimationDuration;
-                if (normalized >= 1.0f) {
-                    mAnimationState = ANIMATION_STATE_DONE;
-                }
-                normalized = Math.min(normalized, 1.0f);
-                final float value = mAnimationFrom  + (mAnimationTo - mAnimationFrom) * normalized;
-
-                switch (mAnimationType) {
-                    case ANIMATION_TYPE_SCALE:
-                        final Bitmap dragBitmap = mDragBitmap;
-                        canvas.save();
-                        canvas.translate(mScrollX + mLastMotionX - mTouchOffsetX - mBitmapOffsetX,
-                                mScrollY + mLastMotionY - mTouchOffsetY - mBitmapOffsetY);
-                        canvas.translate((dragBitmap.getWidth() * (1.0f - value)) / 2,
-                                (dragBitmap.getHeight() * (1.0f - value)) / 2);
-                        canvas.scale(value, value);
-                        canvas.drawBitmap(dragBitmap, 0.0f, 0.0f, mDragPaint);
-                        canvas.restore();
-                        break;
-                }
-            } else {
-                // Only draw estimate drop "snag" when requested
-                if (DRAW_TARGET_SNAG && mDrawEstimated) {
-                    canvas.drawLine(mDragCenter[0], mDragCenter[1], mEstimatedCenter[0], mEstimatedCenter[1], mEstimatedPaint);
-                    canvas.drawCircle(mEstimatedCenter[0], mEstimatedCenter[1], 8, mEstimatedPaint);
-                }
-
-                // Draw actual icon being dragged
-                canvas.drawBitmap(mDragBitmap,
-                        mScrollX + mLastMotionX - mTouchOffsetX - mBitmapOffsetX,
-                        mScrollY + mLastMotionY - mTouchOffsetY - mBitmapOffsetY, mDragPaint);
-            }
-        }
-    }
-
-    private void endDrag() {
-        if (mDragging) {
-            mDragging = false;
-            if (mDragBitmap != null) {
-                mDragBitmap.recycle();
-            }
-            if (mOriginator != null) {
-                mOriginator.setVisibility(VISIBLE);
-            }
-            if (mListener != null) {
-                mListener.onDragEnd();
-            }
-        }
+        return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
     }
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        final int action = ev.getAction();
-
-        final float x = ev.getX();
-        final float y = ev.getY();
-
-        switch (action) {
-            case MotionEvent.ACTION_MOVE:
-                break;
-
-            case MotionEvent.ACTION_DOWN:
-                // Remember location of down touch
-                mLastMotionX = x;
-                mLastMotionY = y;
-                mLastDropTarget = null;
-                break;
-
-            case MotionEvent.ACTION_CANCEL:
-            case MotionEvent.ACTION_UP:
-                if (mShouldDrop && drop(x, y)) {
-                    mShouldDrop = false;
-                }
-                endDrag();
-                break;
-        }
-
-        return mDragging;
+        return mDragController.onInterceptTouchEvent(ev);
     }
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-        if (!mDragging) {
-            return false;
-        }
-
-        final int action = ev.getAction();
-        final float x = ev.getX();
-        final float y = ev.getY();
-
-        switch (action) {
-        case MotionEvent.ACTION_DOWN:
-
-            // Remember where the motion event started
-            mLastMotionX = x;
-            mLastMotionY = y;
-
-            if ((x < SCROLL_ZONE) || (x > getWidth() - SCROLL_ZONE)) {
-                mScrollState = SCROLL_WAITING_IN_ZONE;
-                postDelayed(mScrollRunnable, SCROLL_DELAY);
-            } else {
-                mScrollState = SCROLL_OUTSIDE_ZONE;
-            }
-
-            break;
-        case MotionEvent.ACTION_MOVE:
-            final int scrollX = mScrollX;
-            final int scrollY = mScrollY;
-
-            final float touchX = mTouchOffsetX;
-            final float touchY = mTouchOffsetY;
-
-            final int offsetX = mBitmapOffsetX;
-            final int offsetY = mBitmapOffsetY;
-
-            int left = (int) (scrollX + mLastMotionX - touchX - offsetX);
-            int top = (int) (scrollY + mLastMotionY - touchY - offsetY);
-
-            final Bitmap dragBitmap = mDragBitmap;
-            final int width = dragBitmap.getWidth();
-            final int height = dragBitmap.getHeight();
-
-            final Rect rect = mRect;
-            rect.set(left - 1, top - 1, left + width + 1, top + height + 1);
-
-            mLastMotionX = x;
-            mLastMotionY = y;
-
-            left = (int) (scrollX + x - touchX - offsetX);
-            top = (int) (scrollY + y - touchY - offsetY);
-
-            // Invalidate current icon position
-            rect.union(left - 1, top - 1, left + width + 1, top + height + 1);
-
-            mDragCenter[0] = rect.centerX();
-            mDragCenter[1] = rect.centerY();
-
-            // Invalidate any old estimated location
-            if (DRAW_TARGET_SNAG && mDrawEstimated) {
-                rect.union(mEstimatedRect);
-            }
-
-            final int[] coordinates = mDropCoordinates;
-            DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates);
-            if (dropTarget != null) {
-                if (mLastDropTarget == dropTarget) {
-                    dropTarget.onDragOver(mDragSource, coordinates[0], coordinates[1],
-                        (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
-                } else {
-                    if (mLastDropTarget != null) {
-                        mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
-                            (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
-                    }
-                    dropTarget.onDragEnter(mDragSource, coordinates[0], coordinates[1],
-                        (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
-                }
-            } else {
-                if (mLastDropTarget != null) {
-                    mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
-                        (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
-                }
-            }
-
-            // Render estimated drop "snag" only outside of width
-            mDrawEstimated = false;
-            if (DRAW_TARGET_SNAG && dropTarget != null) {
-                Rect foundEstimate = dropTarget.estimateDropLocation(mDragSource,
-                        (int) (scrollX + mLastMotionX), (int) (scrollY + mLastMotionY),
-                        (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo, mEstimatedRect);
-
-                if (foundEstimate != null) {
-                    mEstimatedCenter[0] = foundEstimate.centerX();
-                    mEstimatedCenter[1] = foundEstimate.centerY();
-
-                    int deltaX = (int) Math.abs(mEstimatedCenter[0] - mDragCenter[0]);
-                    int deltaY = (int) Math.abs(mEstimatedCenter[1] - mDragCenter[1]);
-
-                    if (deltaX > mTriggerWidth || deltaY > mTriggerHeight) {
-                        mDrawEstimated = true;
-                    }
-                }
-            }
-
-            // Include new estimated area in invalidated rectangle
-            if (DRAW_TARGET_SNAG && mDrawEstimated) {
-                rect.union(mEstimatedRect);
-            }
-            invalidate(rect);
-
-            mLastDropTarget = dropTarget;
-
-            boolean inDragRegion = false;
-            if (mDragRegion != null) {
-                final RectF region = mDragRegion;
-                final boolean inRegion = region.contains(ev.getRawX(), ev.getRawY());
-                if (!mEnteredRegion && inRegion) {
-                    mDragPaint = mTrashPaint;
-                    mEnteredRegion = true;
-                    inDragRegion = true;
-                } else if (mEnteredRegion && !inRegion) {
-                    mDragPaint = null;
-                    mEnteredRegion = false;
-                }
-            }
-
-            if (!inDragRegion && x < SCROLL_ZONE) {
-                if (mScrollState == SCROLL_OUTSIDE_ZONE) {
-                    mScrollState = SCROLL_WAITING_IN_ZONE;
-                    mScrollRunnable.setDirection(SCROLL_LEFT);
-                    postDelayed(mScrollRunnable, SCROLL_DELAY);
-                }
-            } else if (!inDragRegion && x > getWidth() - SCROLL_ZONE) {
-                if (mScrollState == SCROLL_OUTSIDE_ZONE) {
-                    mScrollState = SCROLL_WAITING_IN_ZONE;
-                    mScrollRunnable.setDirection(SCROLL_RIGHT);
-                    postDelayed(mScrollRunnable, SCROLL_DELAY);
-                }
-            } else {
-                if (mScrollState == SCROLL_WAITING_IN_ZONE) {
-                    mScrollState = SCROLL_OUTSIDE_ZONE;
-                    mScrollRunnable.setDirection(SCROLL_RIGHT);
-                    removeCallbacks(mScrollRunnable);
-                }
-            }
-
-            break;
-        case MotionEvent.ACTION_UP:
-            removeCallbacks(mScrollRunnable);
-            if (mShouldDrop) {
-                drop(x, y);
-                mShouldDrop = false;
-            }
-            endDrag();
-
-            break;
-        case MotionEvent.ACTION_CANCEL:
-            endDrag();
-        }
-
-        return true;
-    }
-
-    private boolean drop(float x, float y) {
-        invalidate();
-
-        final int[] coordinates = mDropCoordinates;
-        DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates);
-
-        if (dropTarget != null) {
-            dropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
-                    (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
-            if (dropTarget.acceptDrop(mDragSource, coordinates[0], coordinates[1],
-                    (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo)) {
-                dropTarget.onDrop(mDragSource, coordinates[0], coordinates[1],
-                        (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
-                mDragSource.onDropCompleted((View) dropTarget, true);
-                return true;
-            } else {
-                mDragSource.onDropCompleted((View) dropTarget, false);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    DropTarget findDropTarget(int x, int y, int[] dropCoordinates) {
-        return findDropTarget(this, x, y, dropCoordinates);
-    }
-
-    private DropTarget findDropTarget(ViewGroup container, int x, int y, int[] dropCoordinates) {
-        final Rect r = mDragRect;
-        final int count = container.getChildCount();
-        final int scrolledX = x + container.getScrollX();
-        final int scrolledY = y + container.getScrollY();
-        final View ignoredDropTarget = mIgnoredDropTarget;
-
-        for (int i = count - 1; i >= 0; i--) {
-            final View child = container.getChildAt(i);
-            if (child.getVisibility() == VISIBLE && child != ignoredDropTarget) {
-                child.getHitRect(r);
-                if (r.contains(scrolledX, scrolledY)) {
-                    DropTarget target = null;
-                    if (child instanceof ViewGroup) {
-                        x = scrolledX - child.getLeft();
-                        y = scrolledY - child.getTop();
-                        target = findDropTarget((ViewGroup) child, x, y, dropCoordinates);
-                    }
-                    if (target == null) {
-                        if (child instanceof DropTarget) {
-                            // Only consider this child if they will accept
-                            DropTarget childTarget = (DropTarget) child;
-                            if (childTarget.acceptDrop(mDragSource, x, y, 0, 0, mDragInfo)) {
-                                dropCoordinates[0] = x;
-                                dropCoordinates[1] = y;
-                                return (DropTarget) child;
-                            } else {
-                                return null;
-                            }
-                        }
-                    } else {
-                        return target;
-                    }
-                }
-            }
-        }
-
-        return null;
-    }
-
-    public void setDragScoller(DragScroller scroller) {
-        mDragScroller = scroller;
-    }
-
-    public void setDragListener(DragListener l) {
-        mListener = l;
-    }
-
-    public void removeDragListener(DragListener l) {
-        mListener = null;
-    }
-
-    /**
-     * Specifies the view that must be ignored when looking for a drop target.
-     *
-     * @param view The view that will not be taken into account while looking
-     *        for a drop target.
-     */
-    void setIgnoredDropTarget(View view) {
-        mIgnoredDropTarget = view;
-    }
-
-    /**
-     * Specifies the delete region.
-     *
-     * @param region The rectangle in screen coordinates of the delete region.
-     */
-    void setDeleteRegion(RectF region) {
-        mDragRegion = region;
-    }
-
-    private class ScrollRunnable implements Runnable {
-        private int mDirection;
-
-        ScrollRunnable() {
-        }
-
-        public void run() {
-            if (mDragScroller != null) {
-                mDrawEstimated = false;
-                if (mDirection == SCROLL_LEFT) {
-                    mDragScroller.scrollLeft();
-                } else {
-                    mDragScroller.scrollRight();
-                }
-                mScrollState = SCROLL_OUTSIDE_ZONE;
-            }
-        }
-
-        void setDirection(int direction) {
-            mDirection = direction;
-        }
+        return mDragController.onTouchEvent(ev);
     }
 }
diff --git a/src/com/android/launcher2/DragSource.java b/src/com/android/launcher2/DragSource.java
index 3c0a09d..7c6ca58 100644
--- a/src/com/android/launcher2/DragSource.java
+++ b/src/com/android/launcher2/DragSource.java
@@ -23,6 +23,6 @@
  *
  */
 public interface DragSource {
-    void setDragger(DragController dragger);
+    void setDragController(DragController dragger);
     void onDropCompleted(View target, boolean success);
 }
diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java
new file mode 100644
index 0000000..911a6ce
--- /dev/null
+++ b/src/com/android/launcher2/DragView.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.launcher2;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.os.IBinder;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.KeyEvent;
+import android.view.WindowManager;
+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 = 24;
+
+    private Bitmap mBitmap;
+    private Paint mPaint;
+    private int mRegistrationX;
+    private int mRegistrationY;
+
+    SymmetricalLinearTween mTween;
+    private float mScale;
+    private float mAnimationScale = 1.0f;
+
+    private WindowManager.LayoutParams mLayoutParams;
+    private WindowManager mWindowManager;
+
+    /**
+     * Construct the drag view.
+     * <p>
+     * The registration point is the point inside our view that the touch events should
+     * be centered upon.
+     *
+     * @param context A context
+     * @param bitmap The view that we're dragging around.  We scale it up when we draw it.
+     * @param registrationX The x coordinate of the registration point.
+     * @param registrationY The y coordinate of the registration point.
+     */
+    public DragView(Context context, Bitmap bitmap, int registrationX, int registrationY) {
+        super(context);
+
+        mWindowManager = WindowManagerImpl.getDefault();
+        
+        mTween = new SymmetricalLinearTween(false, 110 /*ms duration*/, this);
+
+        int width = bitmap.getWidth();
+        int height = bitmap.getHeight();
+
+        Matrix scale = new Matrix();
+        float scaleFactor = width;
+        scaleFactor = mScale = (scaleFactor + DRAG_SCALE) / scaleFactor;
+        scale.setScale(scaleFactor, scaleFactor);
+
+        mBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, scale, true);
+
+        // The point in our scaled bitmap that the touch events are located
+        mRegistrationX = registrationX + (DRAG_SCALE / 2);
+        mRegistrationY = registrationY + (DRAG_SCALE / 2);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int widthSize = resolveSize(mBitmap.getWidth(), widthMeasureSpec);
+        int heightSize = resolveSize(mBitmap.getHeight(), heightMeasureSpec);
+        setMeasuredDimension(widthSize, heightSize);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        if (false) {
+            // for debugging
+            Paint p = new Paint();
+            p.setStyle(Paint.Style.FILL);
+            p.setColor(0xaaffffff);
+            canvas.drawRect(0, 0, getWidth(), getHeight(), p);
+        }
+        float scale = mAnimationScale;
+        if (scale < 0.999f) { // allow for some float error
+            float width = mBitmap.getWidth();
+            float offset = (width-(width*scale))/2;
+            canvas.translate(offset, offset);
+            canvas.scale(scale, scale);
+        }
+        canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mBitmap.recycle();
+    }
+
+    public void onTweenValueChanged(float value, float oldValue) {
+        mAnimationScale = (1.0f+((mScale-1.0f)*value))/mScale;
+        invalidate();
+    }
+
+    public void onTweenStarted() {
+    }
+
+    public void onTweenFinished() {
+    }
+
+    public void setPaint(Paint paint) {
+        mPaint = paint;
+        invalidate();
+    }
+
+    /**
+     * Create a window containing this view and show it.
+     *
+     * @param windowToken obtained from v.getWindowToken() from one of your views
+     * @param touchX the x coordinate the user touched in screen coordinates
+     * @param touchY the y coordinate the user touched in screen coordinates
+     */
+    public void show(IBinder windowToken, int touchX, int touchY) {
+        WindowManager.LayoutParams lp;
+        int pixelFormat;
+
+        pixelFormat = PixelFormat.TRANSLUCENT;
+
+        lp = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                touchX-mRegistrationX, touchY-mRegistrationY,
+                WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL,
+                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                    /*| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM*/,
+                pixelFormat);
+//        lp.token = mStatusBarView.getWindowToken();
+        lp.gravity = Gravity.LEFT | Gravity.TOP;
+        lp.token = windowToken;
+        lp.setTitle("DragView");
+        mLayoutParams = lp;
+
+        mWindowManager.addView(this, lp);
+
+        mAnimationScale = 1.0f/mScale;
+        mTween.start(true);
+    }
+    
+    /**
+     * Move the window containing this view.
+     *
+     * @param touchX the x coordinate the user touched in screen coordinates
+     * @param touchY the y coordinate the user touched in screen coordinates
+     */
+    void move(int touchX, int touchY) {
+        WindowManager.LayoutParams lp = mLayoutParams;
+        lp.x = touchX - mRegistrationX;
+        lp.y = touchY - mRegistrationY;
+        mWindowManager.updateViewLayout(this, lp);
+    }
+
+    void remove() {
+        mWindowManager.removeView(this);
+    }
+}
+
diff --git a/src/com/android/launcher2/DropTarget.java b/src/com/android/launcher2/DropTarget.java
index e092e50..72eb330 100644
--- a/src/com/android/launcher2/DropTarget.java
+++ b/src/com/android/launcher2/DropTarget.java
@@ -30,18 +30,25 @@
      * @param source DragSource where the drag started
      * @param x X coordinate of the drop location
      * @param y Y coordinate of the drop location
-     * @param xOffset Horizontal offset with the object being dragged where the original touch happened
-     * @param yOffset Vertical offset with the object being dragged where the original touch happened
+     * @param xOffset Horizontal offset with the object being dragged where the original
+     *          touch happened
+     * @param yOffset Vertical offset with the object being dragged where the original
+     *          touch happened
+     * @param dragView The DragView that's being dragged around on screen.
      * @param dragInfo Data associated with the object being dragged
      * 
      */
-    void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);
+    void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo);
     
-    void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);
+    void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo);
 
-    void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);
+    void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo);
 
-    void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);
+    void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo);
 
     /**
      * Check if a drop action can occur at, or near, the requested location.
@@ -55,10 +62,12 @@
      *            original touch happened
      * @param yOffset Vertical offset with the object being dragged where the
      *            original touch happened
+     * @param dragView The DragView that's being dragged around on screen.
      * @param dragInfo Data associated with the object being dragged
      * @return True if the drop will be accepted, false otherwise.
      */
-    boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);
+    boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo);
 
     /**
      * Estimate the surface area where this object would land if dropped at the
@@ -71,11 +80,19 @@
      *            original touch happened
      * @param yOffset Vertical offset with the object being dragged where the
      *            original touch happened
+     * @param dragView The DragView that's being dragged around on screen.
      * @param dragInfo Data associated with the object being dragged
      * @param recycle {@link Rect} object to be possibly recycled.
      * @return Estimated area that would be occupied if object was dropped at
      *         the given location. Should return null if no estimate is found,
      *         or if this target doesn't provide estimations.
      */
-    Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo, Rect recycle);
+    Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo, Rect recycle);
+
+    // These methods are implemented in Views
+    void getHitRect(Rect outRect);
+    void getLocationOnScreen(int[] loc);
+    int getLeft();
+    int getTop();
 }
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index 6281ebf..bc5f9fd 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -35,7 +35,7 @@
         OnItemClickListener, OnClickListener, View.OnLongClickListener {
 
     protected AbsListView mContent;
-    protected DragController mDragger;
+    protected DragController mDragController;
     
     protected Launcher mLauncher;
 
@@ -98,7 +98,7 @@
             app = new ApplicationInfo(app);
         }
 
-        mDragger.startDrag(view, this, app, DragController.DRAG_ACTION_COPY);
+        mDragController.startDrag(view, this, app, DragController.DRAG_ACTION_COPY);
         mLauncher.closeFolder(this);
         mDragItem = app;
 
@@ -109,8 +109,8 @@
         mCloneInfo = cloneInfo;
     }
 
-    public void setDragger(DragController dragger) {
-        mDragger = dragger;
+    public void setDragController(DragController dragController) {
+        mDragController = dragController;
     }
 
     public void onDropCompleted(View target, boolean success) {
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
index 1531538..85fc3a7 100644
--- a/src/com/android/launcher2/FolderIcon.java
+++ b/src/com/android/launcher2/FolderIcon.java
@@ -62,7 +62,7 @@
     }
 
     public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
-            Object dragInfo) {
+            DragView dragView, Object dragInfo) {
         final ItemInfo item = (ItemInfo) dragInfo;
         final int itemType = item.itemType;
         return (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
@@ -70,11 +70,13 @@
                 && item.container != mInfo.id;
     }
 
-    public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo, Rect recycle) {
+    public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo, Rect recycle) {
         return null;
     }
 
-    public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
+    public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo) {
         final ApplicationInfo item = (ApplicationInfo) dragInfo;
         // TODO: update open folder that is looking at this data
         mInfo.add(item);
@@ -82,16 +84,16 @@
     }
 
     public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
-            Object dragInfo) {
+            DragView dragView, Object dragInfo) {
         setCompoundDrawablesWithIntrinsicBounds(null, mOpenIcon, null, null);
     }
 
     public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
-            Object dragInfo) {
+            DragView dragView, Object dragInfo) {
     }
 
     public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
-            Object dragInfo) {
+            DragView dragView, Object dragInfo) {
         setCompoundDrawablesWithIntrinsicBounds(null, mCloseIcon, null, null);
     }
 }
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index 661fbdb..759af28 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -166,6 +166,7 @@
 
     private LayoutInflater mInflater;
 
+    private DragController mDragController;
     private DragLayer mDragLayer;
     private WallpaperView mWallpaperView;
     private Workspace mWorkspace;
@@ -528,10 +529,14 @@
      * Finds all the views we need and configure them properly.
      */
     private void setupViews() {
+        mDragController = new DragController(this);
+        DragController dragController = mDragController;
+
         mDragLayer = (DragLayer) findViewById(R.id.drag_layer);
         final DragLayer dragLayer = mDragLayer;
+        dragLayer.setDragController(dragController);
 
-        mWallpaperView = (WallpaperView) dragLayer.findViewById(R.id.wallpaper);
+        mWallpaperView = (WallpaperView) findViewById(R.id.wallpaper);
         final WallpaperView wallpaper = mWallpaperView;
 
         mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace);
@@ -546,7 +551,7 @@
         mHandleIcon.setCrossFadeEnabled(true);
 
         workspace.setOnLongClickListener(this);
-        workspace.setDragger(dragLayer);
+        workspace.setDragController(dragController);
         workspace.setLauncher(this);
         workspace.setWallpaper(wallpaper);
 
@@ -554,12 +559,16 @@
         wallpaper.setScreenCount(workspace.getScreenCount());
 
         deleteZone.setLauncher(this);
-        deleteZone.setDragController(dragLayer);
+        deleteZone.setDragController(dragController);
         deleteZone.setHandle(mHandleView);
 
-        // TODO dragLayer.setIgnoredDropTarget(grid);
-        dragLayer.setDragScoller(workspace);
-        dragLayer.setDragListener(deleteZone);
+        dragController.setDragScoller(workspace);
+        dragController.setDragListener(deleteZone);
+        dragController.setScrollView(dragLayer);
+        
+        // The order here is bottom to top.
+        dragController.addDropTarget(workspace);
+        dragController.addDropTarget(deleteZone);
     }
 
     /**
@@ -1347,6 +1356,7 @@
         ViewGroup parent = (ViewGroup) folder.getParent();
         if (parent != null) {
             parent.removeView(folder);
+            mDragController.removeDropTarget((DropTarget)folder);
         }
         folder.onClose();
     }
@@ -1545,10 +1555,6 @@
         }
     }
 
-    DragController getDragController() {
-        return mDragLayer;
-    }
-
     /**
      * Launches the intent referred by the clicked shortcut.
      *
@@ -1646,7 +1652,7 @@
             return;
         }
 
-        openFolder.setDragger(mDragLayer);
+        openFolder.setDragController(mDragController);
         openFolder.setLauncher(this);
 
         openFolder.bind(folderInfo);
@@ -1703,11 +1709,6 @@
         return sModel;
     }
 
-    void closeAllApplications() {
-        // TODO mDrawer.close();
-        mAllAppsDialog.dismiss();
-    }
-
     View getDrawerHandle() {
         return mHandleView;
     }
@@ -1744,6 +1745,7 @@
     protected void onPrepareDialog(int id, Dialog dialog) {
         switch (id) {
             case DIALOG_ALL_APPS:
+                mAllAppsGrid.onPrepareDialog();
                 break;
             case DIALOG_CREATE_SHORTCUT:
                 break;
@@ -1886,8 +1888,11 @@
             setContentView(R.layout.all_apps);
             AllAppsGridView grid = mAllAppsGrid = (AllAppsGridView)findViewById(R.id.all_apps);
 
+            DragLayer dragLayer = (DragLayer)findViewById(R.id.drag_layer);
+            dragLayer.setDragController(mDragController);
+
             grid.setTextFilterEnabled(false);
-            // TODO grid.setDragger(dragLayer);
+            grid.setDragController(mDragController);
             grid.setLauncher(Launcher.this);
         }
 
@@ -1930,7 +1935,11 @@
         mWorkspace.hide();
     }
 
-    private void closeAllAppsDialog(boolean animated) {
+    void showWorkspace() {
+        mWorkspace.show();
+    }
+
+    void closeAllAppsDialog(boolean animated) {
         if (mAllAppsDialog.isOpen) {
             if (animated) {
                 // TODO mDrawer.animateClose();
diff --git a/src/com/android/launcher2/LiveFolderIcon.java b/src/com/android/launcher2/LiveFolderIcon.java
index 4e19041..1876f2e 100644
--- a/src/com/android/launcher2/LiveFolderIcon.java
+++ b/src/com/android/launcher2/LiveFolderIcon.java
@@ -54,23 +54,28 @@
     }
 
     @Override
-    public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
+    public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo) {
         return false;
     }
 
     @Override
-    public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
+    public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo) {
     }
 
     @Override
-    public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
+    public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo) {
     }
 
     @Override
-    public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
+    public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo) {
     }
 
     @Override
-    public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
+    public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo) {
     }
 }
diff --git a/src/com/android/launcher2/UserFolder.java b/src/com/android/launcher2/UserFolder.java
index a5e9058..1379be6 100644
--- a/src/com/android/launcher2/UserFolder.java
+++ b/src/com/android/launcher2/UserFolder.java
@@ -28,31 +28,36 @@
     }
 
     public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
-            Object dragInfo) {
+            DragView dragView, Object dragInfo) {
         final ItemInfo item = (ItemInfo) dragInfo;
         final int itemType = item.itemType;
         return (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
                 itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) && item.container != mInfo.id;
     }
     
-    public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo, Rect recycle) {
+    public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo, Rect recycle) {
         return null;
     }
 
-    public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
+    public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo) {
         final ApplicationInfo item = (ApplicationInfo) dragInfo;
         //noinspection unchecked
         ((ArrayAdapter<ApplicationInfo>) mContent.getAdapter()).add((ApplicationInfo) dragInfo);
         LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, 0, 0);
     }
 
-    public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
+    public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo) {
     }
 
-    public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
+    public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo) {
     }
 
-    public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
+    public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo) {
     }
 
     @Override
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 43a6f78..bb32e02 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -90,7 +90,7 @@
     private OnLongClickListener mLongClickListener;
 
     private Launcher mLauncher;
-    private DragController mDragger;
+    private DragController mDragController;
     
     /**
      * Cache of vacant cells, used during drag events and invalidated as needed.
@@ -363,6 +363,9 @@
         if (!(child instanceof Folder)) {
             child.setOnLongClickListener(mLongClickListener);
         }
+        if (child instanceof DropTarget) {
+            mDragController.addDropTarget((DropTarget)child);
+        }
     }
 
     void addWidget(View view, Widget widget) {
@@ -436,6 +439,9 @@
             if (!(child instanceof Folder)) {
                 child.setOnLongClickListener(mLongClickListener);
             }
+            if (child instanceof DropTarget) {
+                mDragController.addDropTarget((DropTarget)child);
+            }
         }
     }
 
@@ -512,6 +518,11 @@
         }
     }
 
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mDragController.setWindowToken(getWindowToken());
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -854,7 +865,7 @@
         CellLayout current = ((CellLayout) getChildAt(mCurrentScreen));
 
         current.onDragChild(child);
-        mDragger.startDrag(child, this, child.getTag(), DragController.DRAG_ACTION_MOVE);
+        mDragController.startDrag(child, this, child.getTag(), DragController.DRAG_ACTION_MOVE);
         invalidate();
     }
 
@@ -888,7 +899,8 @@
         onDropExternal(result[0], result[1], info, layout, insertAtFirst);
     }
 
-    public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
+    public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo) {
         final CellLayout cellLayout = getCurrentDropLayout();
         if (source != this) {
             onDropExternal(x - xOffset, y - yOffset, dragInfo, cellLayout);
@@ -914,16 +926,16 @@
     }
 
     public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
-            Object dragInfo) {
+            DragView dragView, Object dragInfo) {
         clearVacantCache();
     }
 
     public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
-            Object dragInfo) {
+            DragView dragView, Object dragInfo) {
     }
 
     public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
-            Object dragInfo) {
+            DragView dragView, Object dragInfo) {
         clearVacantCache();
     }
 
@@ -958,6 +970,10 @@
 
         cellLayout.addView(view, insertAtFirst ? 0 : -1);
         view.setOnLongClickListener(mLongClickListener);
+        if (view instanceof DropTarget) {
+            mDragController.addDropTarget((DropTarget)view);
+        }
+
         mTargetCell = estimateDropCell(x, y, 1, 1, view, cellLayout, mTargetCell);
         cellLayout.onDropChild(view, mTargetCell);
         CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
@@ -981,7 +997,7 @@
      * {@inheritDoc}
      */
     public boolean acceptDrop(DragSource source, int x, int y,
-            int xOffset, int yOffset, Object dragInfo) {
+            int xOffset, int yOffset, DragView dragView, Object dragInfo) {
         final CellLayout layout = getCurrentDropLayout();
         final CellLayout.CellInfo cellInfo = mDragInfo;
         final int spanX = cellInfo == null ? 1 : cellInfo.spanX;
@@ -999,7 +1015,7 @@
      * {@inheritDoc}
      */
     public Rect estimateDropLocation(DragSource source, int x, int y,
-            int xOffset, int yOffset, Object dragInfo, Rect recycle) {
+            int xOffset, int yOffset, DragView dragView, Object dragInfo, Rect recycle) {
         final CellLayout layout = getCurrentDropLayout();
         
         final CellLayout.CellInfo cellInfo = mDragInfo;
@@ -1047,8 +1063,8 @@
         mLauncher = launcher;
     }
 
-    public void setDragger(DragController dragger) {
-        mDragger = dragger;
+    public void setDragController(DragController dragController) {
+        mDragController = dragController;
     }
 
     public void onDropCompleted(View target, boolean success) {
@@ -1056,6 +1072,9 @@
             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);
+                }
                 final Object tag = mDragInfo.cell.getTag();
                 Launcher.getModel().removeDesktopItem((ItemInfo) tag);
             }
@@ -1247,7 +1266,11 @@
 
             childCount = childrenToRemove.size();
             for (int j = 0; j < childCount; j++) {
-                layout.removeViewInLayout(childrenToRemove.get(j));
+                View child = childrenToRemove.get(j);
+                layout.removeViewInLayout(child);
+                if (child instanceof DropTarget) {
+                    mDragController.removeDropTarget((DropTarget)child);
+                }
             }
 
             if (childCount > 0) {