Changed folder hover animations

-> Added outer ring to hover animation
-> Fixed location of items in folder during hover animation
-> Cleaned up the code

Change-Id: I57c5f3cadbd2f289a18f7420a57ced6053fb06db
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
index aa7d079..31c5ea0 100644
--- a/src/com/android/launcher2/FolderIcon.java
+++ b/src/com/android/launcher2/FolderIcon.java
@@ -45,11 +45,22 @@
 
     private static final int NUM_ITEMS_IN_PREVIEW = 4;
     private static final float ICON_ANGLE = 15f;
+    private static final int CONSUMPTION_ANIMATION_DURATION = 60;
+    private static final float INNER_RING_GROWTH_FACTOR = 0.1f;
+    private static final float OUTER_RING_BASELINE_SCALE = 0.7f;
+    private static final float OUTER_RING_GROWTH_FACTOR = 0.3f;
 
-    int mOriginalWidth;
-    int mOriginalHeight;
-    int mOriginalX;
-    int mOriginalY;
+    public static Drawable sFolderOuterRingDrawable = null;
+
+    private int mOriginalWidth = -1;
+    private int mOriginalHeight = -1;
+    private int mOriginalX = -1;
+    private int mOriginalY = -1;
+    private boolean mIsAnimating = false;
+
+    private int mFolderLocX;
+    private int mFolderLocY;
+    private float mOuterRingScale;
 
     public FolderIcon(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -87,17 +98,25 @@
         icon.mFolder = folder;
 
         folderInfo.addListener(icon);
+        if (sFolderOuterRingDrawable == null) {
+            sFolderOuterRingDrawable =
+                    launcher.getResources().getDrawable(R.drawable.portal_ring_outer_holo);
+        }
 
         return icon;
     }
 
+    private boolean willAcceptItem(ItemInfo item) {
+        final int itemType = item.itemType;
+        return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
+                itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) &&
+                !mFolder.isFull() && item != mInfo);
+    }
+
     public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
             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) &&
-                !mFolder.isFull());
+        return willAcceptItem(item);
     }
 
     public void addItem(ShortcutInfo item) {
@@ -126,55 +145,112 @@
         mOriginalY = lp.y;
     }
 
-    public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
-            DragView dragView, Object dragInfo) {
+    private void animateToAcceptState() {
         CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
+
         lp.isLockedToGrid = false;
         saveState(lp);
 
-        PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", (int) (1.1 * lp.width));
-        PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", (int) (1.1 * lp.height));
-        PropertyValuesHolder newX = PropertyValuesHolder.ofInt("x", lp.x - (int) (0.05 * lp.width));
-        PropertyValuesHolder newY = PropertyValuesHolder.ofInt("y", lp.y - (int) (0.05 * lp.height));
-        ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, newX, newY);
+        int newWidth = (int) ((1 + INNER_RING_GROWTH_FACTOR) * lp.width);
+        int newHeight = (int) ((1 + INNER_RING_GROWTH_FACTOR) * lp.width);
+        int newX = lp.x - (int) ((INNER_RING_GROWTH_FACTOR / 2) * lp.width);
+        int newY = lp.y - (int) ((INNER_RING_GROWTH_FACTOR / 2) * lp.height);
+        PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", newWidth);
+        PropertyValuesHolder height = PropertyValuesHolder.ofInt("height",newHeight);
+        PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", newX);
+        PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", newY);
+        ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y);
+        oa.setDuration(CONSUMPTION_ANIMATION_DURATION);
         oa.addUpdateListener(new AnimatorUpdateListener() {
             public void onAnimationUpdate(ValueAnimator animation) {
-                invalidate();
                 requestLayout();
+                invalidate();
             }
         });
-        oa.setDuration(50);
+        oa.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mIsAnimating = true;
+            }
+        });
+        ValueAnimator outerRingScale = ValueAnimator.ofFloat(0f, 1f);
+        outerRingScale.setDuration(CONSUMPTION_ANIMATION_DURATION);
+        outerRingScale.addUpdateListener(new AnimatorUpdateListener() {
+            public void onAnimationUpdate(ValueAnimator animation) {
+                final float percent = (Float) animation.getAnimatedValue();
+                mOuterRingScale = OUTER_RING_BASELINE_SCALE + percent * OUTER_RING_GROWTH_FACTOR;
+                mLauncher.getWorkspace().invalidate();
+            }
+        });
+
+        outerRingScale.start();
         oa.start();
     }
 
+    private void animateToNaturalState() {
+        final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
+        lp.isLockedToGrid = false;
+
+        PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", mOriginalWidth);
+        PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", mOriginalHeight);
+        PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", mOriginalX);
+        PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", mOriginalY);
+        ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y);
+        oa.addUpdateListener(new AnimatorUpdateListener() {
+            public void onAnimationUpdate(ValueAnimator animation) {
+                requestLayout();
+                invalidate();
+            }
+        });
+        oa.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                lp.isLockedToGrid = true;
+                mIsAnimating = false;
+            }
+        });
+
+        ValueAnimator outerRingScale = ValueAnimator.ofFloat(0f, 1f);
+        outerRingScale.setDuration(CONSUMPTION_ANIMATION_DURATION);
+        outerRingScale.addUpdateListener(new AnimatorUpdateListener() {
+            public void onAnimationUpdate(ValueAnimator animation) {
+                final float percent = (Float) animation.getAnimatedValue();
+                mOuterRingScale = OUTER_RING_BASELINE_SCALE + OUTER_RING_GROWTH_FACTOR
+                        - percent * OUTER_RING_GROWTH_FACTOR;
+                mLauncher.getWorkspace().invalidate();
+            }
+        });
+
+        oa.setDuration(CONSUMPTION_ANIMATION_DURATION);
+        oa.start();
+    }
+
+    private void determineFolderLocationInWorkspace() {
+        int tvLocation[] = new int[2];
+        int wsLocation[] = new int[2];
+        getLocationOnScreen(tvLocation);
+        mLauncher.getWorkspace().getLocationOnScreen(wsLocation);
+        mFolderLocX = tvLocation[0] - wsLocation[0] + getMeasuredWidth() / 2;
+        mFolderLocY = tvLocation[1] - wsLocation[1] + getMeasuredHeight() / 2;
+    }
+
+    public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo) {
+        if (!willAcceptItem((ItemInfo) dragInfo)) return;
+        determineFolderLocationInWorkspace();
+        mLauncher.getWorkspace().showFolderAccept(this);
+        animateToAcceptState();
+    }
+
     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,
             DragView dragView, Object dragInfo) {
-        final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
-        lp.isLockedToGrid = false;
-
-        PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", mOriginalWidth);
-        PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", mOriginalHeight);
-        PropertyValuesHolder newX = PropertyValuesHolder.ofInt("x", mOriginalX);
-        PropertyValuesHolder newY = PropertyValuesHolder.ofInt("y", mOriginalY);
-        ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, newX, newY);
-        oa.addUpdateListener(new AnimatorUpdateListener() {
-            public void onAnimationUpdate(ValueAnimator animation) {
-                invalidate();
-                requestLayout();
-            }
-        });
-        oa.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                lp.isLockedToGrid = true;
-            }
-        });
-        oa.setDuration(50);
-        oa.start();
+        if (!willAcceptItem((ItemInfo) dragInfo)) return;
+        mLauncher.getWorkspace().hideFolderAccept(this);
+        animateToNaturalState();
     }
 
     @Override
@@ -183,6 +259,15 @@
         return null;
     }
 
+    public void getFolderLocation(int[] loc) {
+        loc[0] = mFolderLocX;
+        loc[1] = mFolderLocY;
+    }
+
+    public float getOuterRingScale() {
+        return mOuterRingScale;
+    }
+
     @Override
     protected void onDraw(Canvas canvas) {
         if (mFolder == null) return;
@@ -192,12 +277,23 @@
         TextView v = (TextView) mFolder.getItemAt(0);
         Drawable d = v.getCompoundDrawables()[1];
 
-        canvas.translate( (getMeasuredWidth() - d.getIntrinsicWidth()) / 2,
-                (getMeasuredHeight() - d.getIntrinsicHeight()) / 2);
+        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
+        if (mOriginalWidth < 0 || mOriginalHeight < 0) {
+            mOriginalWidth = getMeasuredWidth();
+            mOriginalHeight = getMeasuredHeight();
+        }
 
+        int xShift = (mOriginalWidth - d.getIntrinsicWidth()) / 2;
+        int yShift = (mOriginalHeight - d.getIntrinsicHeight()) / 2;
+
+        if (mIsAnimating) {
+            xShift -= lp.x - mOriginalX;
+            yShift -= lp.y - mOriginalY;
+        }
+
+        canvas.translate(xShift, yShift);
         canvas.translate(d.getIntrinsicWidth() / 2, d.getIntrinsicHeight() / 2);
         canvas.rotate(ICON_ANGLE);
-
         canvas.translate(-d.getIntrinsicWidth() / 2, -d.getIntrinsicHeight() / 2);
 
         for (int i = Math.max(0, mFolder.getItemCount() - NUM_ITEMS_IN_PREVIEW);
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 24160f0..fed991c 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -161,6 +161,7 @@
     private float[] mTempCellLayoutCenterCoordinates = new float[2];
     private float[] mTempDragBottomRightCoordinates = new float[2];
     private Matrix mTempInverseMatrix = new Matrix();
+    private int[] mTempLocation = new int[2];
 
     private SpringLoadedDragController mSpringLoadedDragController;
 
@@ -222,6 +223,8 @@
     private int mLastDragXOffset;
     private int mLastDragYOffset;
 
+    private ArrayList<FolderIcon> mFolderOuterRings = new ArrayList<FolderIcon>();
+
     // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget)
     private float mXDown;
     private float mYDown;
@@ -1185,6 +1188,16 @@
         }
     }
 
+    public void showFolderAccept(FolderIcon fi) {
+        mFolderOuterRings.add(fi);
+    }
+
+    public void hideFolderAccept(FolderIcon fi) {
+        if (mFolderOuterRings.contains(fi)) {
+            mFolderOuterRings.remove(fi);
+        }
+    }
+
     @Override
     protected void onDraw(Canvas canvas) {
         updateWallpaperOffsets();
@@ -1220,6 +1233,19 @@
                 mBackground.draw(canvas);
             }
         }
+
+        // The folder outer ring image(s)
+        for (int i = 0; i < mFolderOuterRings.size(); i++) {
+            FolderIcon fi = mFolderOuterRings.get(i);
+            final Drawable d = FolderIcon.sFolderOuterRingDrawable;
+            final int width = (int) (d.getIntrinsicWidth() * fi.getOuterRingScale());
+            final int height = (int) (d.getIntrinsicHeight() * fi.getOuterRingScale());
+            fi.getFolderLocation(mTempLocation);
+            final int x = mTempLocation[0] + mScrollX - width / 2;
+            final int y = mTempLocation[1] + mScrollY - height / 2;
+            d.setBounds(x, y, x + width, y + height);
+            d.draw(canvas);
+        }
         super.onDraw(canvas);
     }