Prevent flicker when starting a drag.

Also, animate item the view to its new position when dragging.
diff --git a/res/values-xlarge/config.xml b/res/values-xlarge/config.xml
index fa7af5e..3654753 100644
--- a/res/values-xlarge/config.xml
+++ b/res/values-xlarge/config.xml
@@ -37,7 +37,7 @@
     <!-- 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>
+    <integer name="config_dragViewOffsetY">-12</integer>
 
     <!-- When items are dropped on the mini screens in customize mode, we have a bounce animation
          of the bright green hover outline, and then fade out the outline at the end. These are
diff --git a/src/com/android/launcher2/AllApps2D.java b/src/com/android/launcher2/AllApps2D.java
index 9764f23..66d9395 100644
--- a/src/com/android/launcher2/AllApps2D.java
+++ b/src/com/android/launcher2/AllApps2D.java
@@ -201,10 +201,16 @@
         }
     }
 
+    @Override
     public void setDragController(DragController dragger) {
         mDragController = dragger;
     }
 
+    @Override
+    public void onDragViewVisible() {
+    }
+
+    @Override
     public void onDropCompleted(View target, boolean success) {
     }
 
diff --git a/src/com/android/launcher2/AllApps3D.java b/src/com/android/launcher2/AllApps3D.java
index b56a9c9..3599775 100644
--- a/src/com/android/launcher2/AllApps3D.java
+++ b/src/com/android/launcher2/AllApps3D.java
@@ -735,10 +735,16 @@
         return false;
     }
 
+    @Override
     public void setDragController(DragController dragger) {
         mDragController = dragger;
     }
 
+    @Override
+    public void onDragViewVisible() {
+    }
+
+    @Override
     public void onDropCompleted(View target, boolean success) {
     }
 
diff --git a/src/com/android/launcher2/AllAppsPagedView.java b/src/com/android/launcher2/AllAppsPagedView.java
index 1f3df5f..4ca5b47 100644
--- a/src/com/android/launcher2/AllAppsPagedView.java
+++ b/src/com/android/launcher2/AllAppsPagedView.java
@@ -237,6 +237,10 @@
     }
 
     @Override
+    public void onDragViewVisible() {
+    }
+
+    @Override
     public void onDropCompleted(View target, boolean success) {
         // close the choice action mode if we have a proper drop
         if (target != this) {
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index e340101..023e9f4 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -1241,7 +1241,6 @@
     void onDragChild(View child) {
         LayoutParams lp = (LayoutParams) child.getLayoutParams();
         lp.isDragging = true;
-        child.setVisibility(View.GONE);
     }
 
     /**
diff --git a/src/com/android/launcher2/CustomizePagedView.java b/src/com/android/launcher2/CustomizePagedView.java
index 6db6aa9..b48d4ab 100644
--- a/src/com/android/launcher2/CustomizePagedView.java
+++ b/src/com/android/launcher2/CustomizePagedView.java
@@ -312,6 +312,10 @@
     }
 
     @Override
+    public void onDragViewVisible() {
+    }
+
+    @Override
     public void onClick(View v) {
         // Return early if this is not initiated from a touch
         if (!v.isInTouchMode()) return;
@@ -490,16 +494,14 @@
 
             mLauncher.getWorkspace().onDragStartedWithItemMinSize(
                     createWidgetInfo.minWidth, createWidgetInfo.minHeight);
-            mDragController.startDrag(v, b, this, createWidgetInfo, DragController.DRAG_ACTION_COPY,
-                    null);
+            mDragController.startDrag(v, b, this, createWidgetInfo, DragController.DRAG_ACTION_COPY, null);
 
             // Cleanup the icon
             b.recycle();
             return true;
         case ShortcutCustomization:
             createItemInfo = (PendingAddItemInfo) v.getTag();
-            mDragController.startDrag(
-                    v, this, createItemInfo, DragController.DRAG_ACTION_COPY, null);
+            mDragController.startDrag(v, this, createItemInfo, DragController.DRAG_ACTION_COPY);
             mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1);
             return true;
         case ApplicationCustomization:
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index 2b566b7..a0a44a5 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -320,6 +320,13 @@
         DragView dragView = mDragView = new DragView(mContext, b, registrationX, registrationY,
                 textureLeft, textureTop, textureWidth, textureHeight);
 
+        final DragSource dragSource = source;
+        dragView.setOnDrawRunnable(new Runnable() {
+            public void run() {
+                dragSource.onDragViewVisible();
+            };
+        });
+
         if (dragRegion != null) {
             dragView.setDragRegion(dragRegionLeft, dragRegion.top,
                     dragRegion.right - dragRegionLeft, dragRegion.bottom - dragRegionTop);
diff --git a/src/com/android/launcher2/DragSource.java b/src/com/android/launcher2/DragSource.java
index 7c6ca58..11cdcc9 100644
--- a/src/com/android/launcher2/DragSource.java
+++ b/src/com/android/launcher2/DragSource.java
@@ -24,5 +24,12 @@
  */
 public interface DragSource {
     void setDragController(DragController dragger);
+
+    /**
+     * Callback from the DragController when it begins drawing the drag view.
+     * This allows the DragSource to dim or hide the original view.
+     */
+    void onDragViewVisible();
+
     void onDropCompleted(View target, boolean success);
 }
diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java
index ca0e7b4..947184f 100644
--- a/src/com/android/launcher2/DragView.java
+++ b/src/com/android/launcher2/DragView.java
@@ -19,6 +19,8 @@
 
 import com.android.launcher.R;
 
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -32,8 +34,9 @@
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
+import android.view.animation.DecelerateInterpolator;
 
-public class DragView extends View implements TweenCallback {
+public class DragView extends View {
     private Bitmap mBitmap;
     private Paint mPaint;
     private int mRegistrationX;
@@ -44,14 +47,22 @@
     private int mDragRegionWidth;
     private int mDragRegionHeight;
 
-    SymmetricalLinearTween mTween;
-    private float mScale;
-    private float mAnimationScale = 1.0f;
+    ValueAnimator mAnim;
+    private float mScale = 1.0f;
+    private float mOffsetX = 0.0f;
+    private float mOffsetY = 0.0f;
 
     private WindowManager.LayoutParams mLayoutParams;
     private WindowManager mWindowManager;
 
     /**
+     * A callback to be called the first time this view is drawn.
+     * This allows the originator of the drag to dim or hide the original view as soon
+     * as the DragView is drawn.
+     */
+    private Runnable mOnDrawRunnable = null;
+
+    /**
      * Construct the drag view.
      * <p>
      * The registration point is the point inside our view that the touch events should
@@ -70,20 +81,48 @@
         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 + dragScale) / scaleFactor;
-        scale.setScale(scaleFactor, scaleFactor);
+        final float scaleFactor = (width + dragScale) / width;
+        if (scaleFactor != 1.0f) {
+            scale.setScale(scaleFactor, scaleFactor);
+        }
+
+        final int offsetX = res.getInteger(R.integer.config_dragViewOffsetX);
+        final int offsetY = res.getInteger(R.integer.config_dragViewOffsetY);
+
+        // Animate the view into the correct position
+        mAnim = ValueAnimator.ofFloat(0.0f, 1.0f);
+        mAnim.setDuration(110);
+        mAnim.setInterpolator(new DecelerateInterpolator(2.5f));
+        mAnim.addUpdateListener(new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                final float value = (Float) animation.getAnimatedValue();
+
+                final int deltaX = (int) ((value * offsetX) - mOffsetX);
+                final int deltaY = (int) ((value * offsetY) - mOffsetY);
+
+                mOffsetX += deltaX;
+                mOffsetY += deltaY;
+
+                if (getParent() == null) {
+                    animation.cancel();
+                } else {
+                    WindowManager.LayoutParams lp = mLayoutParams;
+                    lp.x += deltaX;
+                    lp.y += deltaY;
+                    mWindowManager.updateViewLayout(DragView.this, lp);
+                }
+            }
+        });
 
         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 + res.getInteger(R.integer.config_dragViewOffsetX);
-        mRegistrationY = registrationY + res.getInteger(R.integer.config_dragViewOffsetY);
+        mRegistrationX = registrationX;
+        mRegistrationY = registrationY;
     }
 
     public void setDragRegion(int left, int top, int width, int height) {
@@ -93,6 +132,10 @@
         mDragRegionHeight = height;
     }
 
+    public void setOnDrawRunnable(Runnable r) {
+        mOnDrawRunnable = r;
+    }
+
     public int getScaledDragRegionXOffset() {
         return -(int)((mScale - 1.0f) * mDragRegionWidth / 2);
     }
@@ -139,13 +182,15 @@
             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);
+
+        // Call the callback if we haven't already been detached
+        if (getParent() != null) {
+            if (mOnDrawRunnable != null) {
+                mOnDrawRunnable.run();
+                mOnDrawRunnable = null;
+            }
         }
+
         canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
     }
 
@@ -155,17 +200,6 @@
         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();
@@ -187,7 +221,7 @@
         lp = new WindowManager.LayoutParams(
                 ViewGroup.LayoutParams.WRAP_CONTENT,
                 ViewGroup.LayoutParams.WRAP_CONTENT,
-                touchX-mRegistrationX, touchY-mRegistrationY,
+                touchX - mRegistrationX, touchY - mRegistrationY,
                 WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL,
                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                     | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
@@ -201,8 +235,7 @@
 
         mWindowManager.addView(this, lp);
 
-        mAnimationScale = 1.0f/mScale;
-        mTween.start(true);
+        mAnim.start();
     }
     
     /**
@@ -213,8 +246,8 @@
      */
     void move(int touchX, int touchY) {
         WindowManager.LayoutParams lp = mLayoutParams;
-        lp.x = touchX - mRegistrationX;
-        lp.y = touchY - mRegistrationY;
+        lp.x = touchX - mRegistrationX + (int) mOffsetX;
+        lp.y = touchY - mRegistrationY + (int) mOffsetY;
         mWindowManager.updateViewLayout(this, lp);
     }
 
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index 018b284..cb450b9 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -108,13 +108,19 @@
         return true;
     }
 
+    @Override
     public void setDragController(DragController dragController) {
         mDragController = dragController;
     }
 
+    @Override
     public void onDropCompleted(View target, boolean success) {
     }
 
+    @Override
+    public void onDragViewVisible() {
+    }
+
     /**
      * Sets the adapter used to populate the content area. The adapter must only
      * contains ShortcutInfo items.
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index f9d087d..bfe5718 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -1360,7 +1360,6 @@
         CellLayout current = getCurrentDropLayout();
 
         current.onDragChild(child);
-        child.setVisibility(View.GONE);
 
         child.clearFocus();
         child.setPressed(false);
@@ -1406,8 +1405,8 @@
         // Based on the position of the drag view, find the top left of the original view
         int viewX = dragViewX + (dragView.getWidth() - child.getWidth()) / 2;
         int viewY = dragViewY + (dragView.getHeight() - child.getHeight()) / 2;
-        viewX -= getResources().getInteger(R.integer.config_dragViewOffsetX);
-        viewY -= getResources().getInteger(R.integer.config_dragViewOffsetY);
+        viewX += getResources().getInteger(R.integer.config_dragViewOffsetX);
+        viewY += getResources().getInteger(R.integer.config_dragViewOffsetY);
 
         // Set its old pos (in the new parent's coordinates); it will be animated
         // in animateViewIntoPosition after the next layout pass
@@ -2176,6 +2175,11 @@
         mDragInfo = null;
     }
 
+    @Override
+    public void onDragViewVisible() {
+        ((View) mDragInfo.cell).setVisibility(View.GONE);
+    }
+
     public boolean isDropEnabled() {
         return true;
     }