3029324 wip: Drop target crossfades as it moves from position to position
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 08560e9..0f1d469 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -31,13 +31,14 @@
 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;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.view.animation.Animation;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
 import android.view.animation.LayoutAnimationController;
 
 import java.util.Arrays;
@@ -79,15 +80,23 @@
     private Drawable mBackground;
     private Drawable mBackgroundMini;
     private Drawable mBackgroundMiniHover;
-    // If we're actively dragging something over this screen and it's small,
-    // mHover is true
+    // If we're actively dragging something over this screen and it's small, mHover is true
     private boolean mHover = false;
 
-    private final RectF mDragRect = new RectF();
     private final Point mDragCenter = new Point();
 
     private Drawable mDragRectDrawable;
 
+    // These arrays are used to implement the drag visualization on x-large screens.
+    // They are used as circular arrays, indexed by mDragRectCurrent.
+    private Rect[] mDragRects = new Rect[8];
+    private int[] mDragRectAlphas = new int[mDragRects.length];
+    private InterruptibleInOutAnimator[] mDragRectAnims =
+        new InterruptibleInOutAnimator[mDragRects.length];
+
+    // Used as an index into the above 3 arrays; indicates which is the most current value.
+    private int mDragRectCurrent = 0;
+
     private Drawable mCrosshairsDrawable = null;
     private ValueAnimator mCrosshairsAnimator = null;
     private float mCrosshairsVisibility = 0.0f;
@@ -139,15 +148,18 @@
         if (LauncherApplication.isScreenXLarge()) {
             final Resources res = getResources();
 
-            mBackgroundMini = getResources().getDrawable(R.drawable.mini_home_screen_bg);
+            mBackgroundMini = res.getDrawable(R.drawable.mini_home_screen_bg);
             mBackgroundMini.setFilterBitmap(true);
-            mBackground = getResources().getDrawable(R.drawable.home_screen_bg);
+            mBackground = res.getDrawable(R.drawable.home_screen_bg);
             mBackground.setFilterBitmap(true);
-            mBackgroundMiniHover = getResources().getDrawable(R.drawable.mini_home_screen_bg_hover);
+            mBackgroundMiniHover = res.getDrawable(R.drawable.mini_home_screen_bg_hover);
             mBackgroundMiniHover.setFilterBitmap(true);
 
+            // Initialize the data structures used for the drag visualization.
+
             mDragRectDrawable = res.getDrawable(R.drawable.rounded_rect_green);
             mCrosshairsDrawable = res.getDrawable(R.drawable.gardening_crosshairs);
+            Interpolator interp = new DecelerateInterpolator(2.5f); // Quint ease out
 
             // Set up the animation for fading the crosshairs in and out
             int animDuration = res.getInteger(R.integer.config_crosshairsFadeInTime);
@@ -158,6 +170,32 @@
                     CellLayout.this.invalidate();
                 }
             });
+            mCrosshairsAnimator.setInterpolator(interp);
+
+            for (int i = 0; i < mDragRects.length; i++) {
+                mDragRects[i] = new Rect();
+            }
+
+            // When dragging things around the home screens, we show a green outline of
+            // where the item will land. The outlines gradually fade out, leaving a trail
+            // behind the drag path.
+            // Set up all the animations that are used to implement this fading.
+            final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime);
+            final int fromAlphaValue = 0;
+            final int toAlphaValue = res.getInteger(R.integer.config_dragOutlineMaxAlpha);
+            for (int i = 0; i < mDragRectAnims.length; i++) {
+                final InterruptibleInOutAnimator anim =
+                    new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);
+                anim.setInterpolator(interp);
+                final int thisIndex = i;
+                anim.addUpdateListener(new AnimatorUpdateListener() {
+                    public void onAnimationUpdate(ValueAnimator animation) {
+                        mDragRectAlphas[thisIndex] = (Integer) animation.getAnimatedValue();
+                        CellLayout.this.invalidate(mDragRects[thisIndex]);
+                    }
+                });
+                mDragRectAnims[i] = anim;
+            }
         }
     }
 
@@ -200,16 +238,6 @@
             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;
@@ -236,6 +264,15 @@
                 }
                 x += mCellWidth + mWidthGap;
             }
+
+            for (int i = 0; i < mDragRects.length; i++) {
+                int alpha = mDragRectAlphas[i];
+                if (alpha > 0) {
+                    mDragRectDrawable.setAlpha(alpha);
+                    mDragRectDrawable.setBounds(mDragRects[i]);
+                    mDragRectDrawable.draw(canvas);
+                }
+            }
         }
     }
 
@@ -751,13 +788,23 @@
             final int left = topLeft[0];
             final int top = topLeft[1];
 
-            // Now find the bottom right
-            final int[] bottomRight = mTmpPoint;
-            cellToPoint(nearest[0] + spanX - 1, nearest[1] + spanY - 1, bottomRight);
-            bottomRight[0] += mCellWidth;
-            bottomRight[1] += mCellHeight;
-            mDragRect.set(left, top, bottomRight[0], bottomRight[1]);
-            invalidate();
+            final Rect dragRect = mDragRects[mDragRectCurrent];
+
+            if (dragRect.isEmpty() || left != dragRect.left || top != dragRect.top) {
+                // Now find the bottom right
+                final int[] bottomRight = mTmpPoint;
+                cellToPoint(nearest[0] + spanX - 1, nearest[1] + spanY - 1, bottomRight);
+                bottomRight[0] += mCellWidth;
+                bottomRight[1] += mCellHeight;
+
+                final int oldIndex = mDragRectCurrent;
+                mDragRectCurrent = (oldIndex + 1) % mDragRects.length;
+
+                mDragRects[mDragRectCurrent].set(left, top, bottomRight[0], bottomRight[1]);
+
+                mDragRectAnims[oldIndex].animateOut();
+                mDragRectAnims[mDragRectCurrent].animateIn();
+            }
         }
     }
 
@@ -973,6 +1020,10 @@
         if (mCrosshairsAnimator != null) {
             animateCrosshairsTo(0.0f);
         }
+
+        mDragRectAnims[mDragRectCurrent].animateOut();
+        mDragRectCurrent = (mDragRectCurrent + 1) % mDragRects.length;
+        mDragRects[mDragRectCurrent].setEmpty();
     }
 
     /**
@@ -1015,7 +1066,6 @@
      * 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);