diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java index aa7d079c04..31c5ea0693 100644 --- a/src/com/android/launcher2/FolderIcon.java +++ b/src/com/android/launcher2/FolderIcon.java @@ -45,11 +45,22 @@ public class FolderIcon extends FrameLayout implements DropTarget, FolderListene 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 @@ public class FolderIcon extends FrameLayout implements DropTarget, FolderListene 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 @@ public class FolderIcon extends FrameLayout implements DropTarget, FolderListene 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 @@ public class FolderIcon extends FrameLayout implements DropTarget, FolderListene 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 @@ public class FolderIcon extends FrameLayout implements DropTarget, FolderListene 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 24160f056c..fed991c39a 100644 --- a/src/com/android/launcher2/Workspace.java +++ b/src/com/android/launcher2/Workspace.java @@ -161,6 +161,7 @@ public class Workspace extends SmoothPagedView 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 @@ public class Workspace extends SmoothPagedView private int mLastDragXOffset; private int mLastDragYOffset; + private ArrayList mFolderOuterRings = new ArrayList(); + // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget) private float mXDown; private float mYDown; @@ -1185,6 +1188,16 @@ public class Workspace extends SmoothPagedView } } + 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 @@ public class Workspace extends SmoothPagedView 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); }