diff --git a/proguard.flags b/proguard.flags index 94dd2609b7..c2b2c65f6d 100644 --- a/proguard.flags +++ b/proguard.flags @@ -31,6 +31,17 @@ public int getY(); } +-keep class com.android.launcher2.CellLayout$LayoutParams { + public void setWidth(int); + public int getWidth(); + public void setHeight(int); + public int getHeight(); + public void setX(int); + public int getX(); + public void setY(int); + public int getY(); +} + -keep class com.android.launcher2.Workspace { public float getBackgroundAlpha(); public void setBackgroundAlpha(float); diff --git a/res/values/config.xml b/res/values/config.xml index ec01fa8408..ba9034fb1d 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -24,6 +24,9 @@ 400 + + 150 + 800 diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java index 80e92c4922..218f3b1f07 100644 --- a/src/com/android/launcher2/CellLayout.java +++ b/src/com/android/launcher2/CellLayout.java @@ -263,17 +263,16 @@ public class CellLayout extends ViewGroup { setHoverAlpha(1.0f); mChildren = new CellLayoutChildren(context); - mChildren.setCellDimensions( - mCellWidth, mCellHeight, mLeftPadding, mTopPadding, mWidthGap, mHeightGap); + mChildren.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap); addView(mChildren); } private void invalidateBubbleTextView(BubbleTextView icon) { final int padding = icon.getPressedOrFocusedBackgroundPadding(); - invalidate(icon.getLeft() - padding, - icon.getTop() - padding, - icon.getRight() + padding, - icon.getBottom() + padding); + invalidate(icon.getLeft() + getLeftPadding() - padding, + icon.getTop() + getTopPadding() - padding, + icon.getRight() + getLeftPadding() + padding, + icon.getBottom() + getTopPadding() + padding); } void setPressedOrFocusedIcon(BubbleTextView icon) { @@ -487,8 +486,8 @@ public class CellLayout extends ViewGroup { final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground(); if (b != null) { canvas.drawBitmap(b, - mPressedOrFocusedIcon.getLeft() - padding, - mPressedOrFocusedIcon.getTop() - padding, + mPressedOrFocusedIcon.getLeft() + getLeftPadding() - padding, + mPressedOrFocusedIcon.getTop() + getTopPadding() - padding, null); } } @@ -783,6 +782,18 @@ public class CellLayout extends ViewGroup { return mBottomPadding; } + Rect getContentRect(Rect r) { + if (r == null) { + r = new Rect(); + } + int left = getPaddingLeft(); + int top = getPaddingTop(); + int right = left + getWidth() - mLeftPadding - mRightPadding; + int bottom = top + getHeight() - mTopPadding - mBottomPadding; + r.set(left, top, right, bottom); + return r; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO: currently ignoring padding @@ -842,7 +853,7 @@ public class CellLayout extends ViewGroup { int count = getChildCount(); for (int i = 0; i < count; i++) { View child = getChildAt(i); - child.layout(0, 0, r - l, b - t); + child.layout(mLeftPadding, mTopPadding, r - mRightPadding , b - mBottomPadding); } } @@ -1651,8 +1662,7 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { this.cellVSpan = cellVSpan; } - public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap, - int hStartPadding, int vStartPadding) { + public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap) { if (isLockedToGrid) { final int myCellHSpan = cellHSpan; final int myCellVSpan = cellVSpan; @@ -1663,14 +1673,46 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { leftMargin - rightMargin; height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) - topMargin - bottomMargin; - x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin; - y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin; + x = myCellX * (cellWidth + widthGap) + leftMargin; + y = myCellY * (cellHeight + heightGap) + topMargin; } } public String toString() { return "(" + this.cellX + ", " + this.cellY + ")"; } + + public void setWidth(int width) { + this.width = width; + } + + public int getWidth() { + return width; + } + + public void setHeight(int height) { + this.height = height; + } + + public int getHeight() { + return height; + } + + public void setX(int x) { + this.x = x; + } + + public int getX() { + return x; + } + + public void setY(int y) { + this.y = y; + } + + public int getY() { + return y; + } } // This class stores info for two purposes: diff --git a/src/com/android/launcher2/CellLayoutChildren.java b/src/com/android/launcher2/CellLayoutChildren.java index ed814199cb..eea38f1424 100644 --- a/src/com/android/launcher2/CellLayoutChildren.java +++ b/src/com/android/launcher2/CellLayoutChildren.java @@ -34,9 +34,6 @@ public class CellLayoutChildren extends ViewGroup { private final WallpaperManager mWallpaperManager; - private int mLeftPadding; - private int mTopPadding; - private int mCellWidth; private int mCellHeight; @@ -49,12 +46,9 @@ public class CellLayoutChildren extends ViewGroup { setLayerType(LAYER_TYPE_HARDWARE, null); } - public void setCellDimensions(int cellWidth, int cellHeight, - int leftPadding, int topPadding, int widthGap, int heightGap ) { + public void setCellDimensions(int cellWidth, int cellHeight, int widthGap, int heightGap ) { mCellWidth = cellWidth; mCellHeight = cellHeight; - mLeftPadding = leftPadding; - mTopPadding = topPadding; mWidthGap = widthGap; mHeightGap = heightGap; } @@ -90,9 +84,7 @@ public class CellLayoutChildren extends ViewGroup { final int cellHeight = mCellHeight; CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); - lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, - mLeftPadding, mTopPadding); - + lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap); int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY); int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java index 60cab8ecb8..4981cb4d47 100644 --- a/src/com/android/launcher2/Launcher.java +++ b/src/com/android/launcher2/Launcher.java @@ -1983,15 +1983,23 @@ public final class Launcher extends Activity void closeFolder(Folder folder) { folder.getInfo().opened = false; + ViewGroup parent = (ViewGroup) folder.getParent().getParent(); if (parent != null) { CellLayout cl = (CellLayout) parent; - cl.removeViewWithoutMarkingCells(folder); + if (!(folder instanceof UserFolder)) { + // User folders will remove themselves + cl.removeViewWithoutMarkingCells(folder); + } if (folder instanceof DropTarget) { // Live folders aren't DropTargets. mDragController.removeDropTarget((DropTarget)folder); } } + if (folder instanceof UserFolder) { + UserFolder uf = (UserFolder) folder; + uf.animateClosed(); + } folder.onClose(); } @@ -2207,6 +2215,10 @@ public final class Launcher extends Activity folderInfo.opened = true; mWorkspace.addInFullScreen(openFolder, folderInfo.screen); + if (openFolder instanceof UserFolder) { + UserFolder uf = (UserFolder) openFolder; + uf.animateOpen(); + } openFolder.onOpen(); } diff --git a/src/com/android/launcher2/UserFolder.java b/src/com/android/launcher2/UserFolder.java index 24b9ae241a..5c87e094da 100644 --- a/src/com/android/launcher2/UserFolder.java +++ b/src/com/android/launcher2/UserFolder.java @@ -2,7 +2,17 @@ package com.android.launcher2; import java.util.ArrayList; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; +import android.animation.ValueAnimator; +import android.animation.Animator.AnimatorListener; +import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.appwidget.AppWidgetProviderInfo; import android.content.Context; +import android.graphics.Color; import android.graphics.Rect; import android.util.AttributeSet; import android.view.LayoutInflater; @@ -18,23 +28,30 @@ import com.android.launcher.R; public class UserFolder extends Folder implements DropTarget { private static final String TAG = "Launcher.UserFolder"; + static final int STATE_NONE = -1; + static final int STATE_SMALL = 0; + static final int STATE_ANIMATING = 1; + static final int STATE_OPEN = 2; + + private int mExpandDuration; protected CellLayout mContent; private final LayoutInflater mInflater; private final IconCache mIconCache; + private int mState = STATE_NONE; public UserFolder(Context context, AttributeSet attrs) { super(context, attrs); mInflater = LayoutInflater.from(context); mIconCache = ((LauncherApplication)context.getApplicationContext()).getIconCache(); + mExpandDuration = getResources().getInteger(R.integer.config_folderAnimDuration); } @Override protected void onFinishInflate() { super.onFinishInflate(); - mContent = (CellLayout) findViewById(R.id.folder_content); } - + /** * Creates a new UserFolder, inflated from R.layout.user_folder. * @@ -46,6 +63,115 @@ public class UserFolder extends Folder implements DropTarget { return (UserFolder) LayoutInflater.from(context).inflate(R.layout.user_folder, null); } + /** + * This method is intended to make the UserFolder to be visually identical in size and position + * to its associated FolderIcon. This allows for a seamless transition into the expanded state. + */ + private void positionAndSizeAsIcon() { + if (!(getParent() instanceof CellLayoutChildren)) return; + + CellLayoutChildren clc = (CellLayoutChildren) getParent(); + CellLayout cellLayout = (CellLayout) clc.getParent(); + + FolderIcon fi = (FolderIcon) cellLayout.getChildAt(mInfo.cellX, mInfo.cellY); + CellLayout.LayoutParams iconLp = (CellLayout.LayoutParams) fi.getLayoutParams(); + CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams(); + + lp.width = iconLp.width; + lp.height = iconLp.height; + lp.x = iconLp.x; + lp.y = iconLp.y; + + mContent.setAlpha(0f); + mState = STATE_SMALL; + } + + public void animateOpen() { + if (mState != STATE_SMALL) { + positionAndSizeAsIcon(); + } + if (!(getParent() instanceof CellLayoutChildren)) return; + + CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams(); + + CellLayoutChildren clc = (CellLayoutChildren) getParent(); + CellLayout cellLayout = (CellLayout) clc.getParent(); + Rect r = cellLayout.getContentRect(null); + + PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", r.width()); + PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", r.height()); + PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", 0); + PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", 0); + + ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y); + oa.addUpdateListener(new AnimatorUpdateListener() { + public void onAnimationUpdate(ValueAnimator animation) { + requestLayout(); + } + }); + + PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1.0f); + ObjectAnimator oaContentAlpha = ObjectAnimator.ofPropertyValuesHolder(mContent, alpha); + + AnimatorSet set = new AnimatorSet(); + set.playTogether(oa, oaContentAlpha); + set.setDuration(mExpandDuration); + set.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + mState = STATE_ANIMATING; + } + @Override + public void onAnimationEnd(Animator animation) { + mState = STATE_SMALL; + } + }); + set.start(); + } + + public void animateClosed() { + if (!(getParent() instanceof CellLayoutChildren)) return; + + CellLayoutChildren clc = (CellLayoutChildren) getParent(); + final CellLayout cellLayout = (CellLayout) clc.getParent(); + + FolderIcon fi = (FolderIcon) cellLayout.getChildAt(mInfo.cellX, mInfo.cellY); + CellLayout.LayoutParams iconLp = (CellLayout.LayoutParams) fi.getLayoutParams(); + CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams(); + + PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", iconLp.width); + PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", iconLp.height); + PropertyValuesHolder x = PropertyValuesHolder.ofInt("x",iconLp.x); + PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", iconLp.y); + + ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y); + oa.addUpdateListener(new AnimatorUpdateListener() { + public void onAnimationUpdate(ValueAnimator animation) { + requestLayout(); + } + }); + + PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0f); + ObjectAnimator oaContentAlpha = ObjectAnimator.ofPropertyValuesHolder(mContent, alpha); + + AnimatorSet set = new AnimatorSet(); + set.playTogether(oa, oaContentAlpha); + set.setDuration(mExpandDuration); + + set.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + cellLayout.removeViewWithoutMarkingCells(UserFolder.this); + mState = STATE_OPEN; + } + @Override + public void onAnimationStart(Animator animation) { + mState = STATE_ANIMATING; + } + }); + set.start(); + } + @Override void notifyDataSetChanged() { // recreate all the children if the data set changes under us. We may want to do this more diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java index b1aa410841..bf89c06113 100644 --- a/src/com/android/launcher2/Workspace.java +++ b/src/com/android/launcher2/Workspace.java @@ -471,6 +471,10 @@ public class Workspace extends SmoothPagedView lp.cellVSpan = spanY; } + if (spanX < 0 && spanY < 0) { + lp.isLockedToGrid = false; + } + // Get the canonical child id to uniquely represent this view in this screen int childId = LauncherModel.getCellLayoutChildId(-1, screen, x, y, spanX, spanY); boolean markCellsAsOccupied = !(child instanceof Folder); @@ -2189,10 +2193,12 @@ public class Workspace extends SmoothPagedView int viewX = dragViewX + (dragView.getWidth() - child.getMeasuredWidth()) / 2; int viewY = dragViewY + (dragView.getHeight() - child.getMeasuredHeight()) / 2; + CellLayout layout = (CellLayout) parent; + // Set its old pos (in the new parent's coordinates); it will be animated // in animateViewIntoPosition after the next layout pass - lp.oldX = viewX - (parent.getLeft() - mScrollX); - lp.oldY = viewY - (parent.getTop() - mScrollY); + lp.oldX = viewX - (layout.getLeft() + layout.getLeftPadding() - mScrollX); + lp.oldY = viewY - (layout.getTop() + layout.getTopPadding() - mScrollY); } /* @@ -2204,8 +2210,8 @@ public class Workspace extends SmoothPagedView final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams(); // Convert the animation params to be relative to the Workspace, not the CellLayout - final int fromX = lp.oldX + parent.getLeft(); - final int fromY = lp.oldY + parent.getTop(); + final int fromX = lp.oldX + parent.getLeft() + parent.getLeftPadding(); + final int fromY = lp.oldY + parent.getTop() + parent.getTopPadding(); final int dx = lp.x - lp.oldX; final int dy = lp.y - lp.oldY;