summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Cohen <adamcohen@google.com>2011-07-02 18:03:00 -0700
committerAdam Cohen <adamcohen@google.com>2011-07-02 18:42:25 -0700
commit3e8f811f31a2275e778244427271f77f4116c08b (patch)
tree53a8530718c95bee2830ca80863bff60f4d1fbf2
parent04dc2bc6139ff414e49fc423d28edbd5801cdc03 (diff)
downloadandroid_packages_apps_Trebuchet-3e8f811f31a2275e778244427271f77f4116c08b.tar.gz
android_packages_apps_Trebuchet-3e8f811f31a2275e778244427271f77f4116c08b.tar.bz2
android_packages_apps_Trebuchet-3e8f811f31a2275e778244427271f77f4116c08b.zip
Added transitions when dropping items onto Folders, fixed bugs
-> Changed the ordering of the FolderIcon preview to show first items first -> Folder now closes immediately upon drop of an item from folder to workspace Change-Id: I66361b604dc5ef81da2413b7dda53d0c4691377e
-rw-r--r--res/drawable-hdpi/portal_container_holo.9.pngbin10516 -> 9722 bytes
-rw-r--r--res/drawable-mdpi/portal_container_holo.9.pngbin5894 -> 5392 bytes
-rw-r--r--res/values/config.xml2
-rw-r--r--src/com/android/launcher2/DragLayer.java112
-rw-r--r--src/com/android/launcher2/DragView.java16
-rw-r--r--src/com/android/launcher2/Folder.java48
-rw-r--r--src/com/android/launcher2/FolderIcon.java33
-rw-r--r--src/com/android/launcher2/Workspace.java23
8 files changed, 149 insertions, 85 deletions
diff --git a/res/drawable-hdpi/portal_container_holo.9.png b/res/drawable-hdpi/portal_container_holo.9.png
index e2a1bd55e..ab846f66e 100644
--- a/res/drawable-hdpi/portal_container_holo.9.png
+++ b/res/drawable-hdpi/portal_container_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/portal_container_holo.9.png b/res/drawable-mdpi/portal_container_holo.9.png
index 7eef5d7c5..56a5b8754 100644
--- a/res/drawable-mdpi/portal_container_holo.9.png
+++ b/res/drawable-mdpi/portal_container_holo.9.png
Binary files differ
diff --git a/res/values/config.xml b/res/values/config.xml
index 70ee42361..5b7376912 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -67,7 +67,7 @@
<integer name="config_dropAnimMaxDuration">400</integer>
<!-- The duration of the UserFolder opening and closing animation -->
- <integer name="config_folderAnimDuration">100</integer>
+ <integer name="config_folderAnimDuration">120</integer>
<!-- The distance at which the animation should take the max duration -->
<integer name="config_dropAnimMaxDist">800</integer>
diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java
index 0ce153e70..d76b902da 100644
--- a/src/com/android/launcher2/DragLayer.java
+++ b/src/com/android/launcher2/DragLayer.java
@@ -32,6 +32,8 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewParent;
import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -57,8 +59,10 @@ public class DragLayer extends FrameLayout {
// Variables relating to animation of views after drop
private ValueAnimator mDropAnim = null;
private TimeInterpolator mQuintEaseOutInterpolator = new DecelerateInterpolator(2.5f);
- private int[] mDropViewPos = new int[] { -1, -1 };
private View mDropView = null;
+ private int[] mDropViewPos = new int[2];
+ private float mDropViewScale;
+ private float mDropViewAlpha;
/**
* Used to create a new DragLayer from XML.
@@ -181,17 +185,19 @@ public class DragLayer extends FrameLayout {
}
}
- public void getViewLocationRelativeToSelf(View v, int[] location) {
- getLocationOnScreen(location);
- int x = location[0];
- int y = location[1];
+ public void getViewRectRelativeToSelf(View v, Rect r) {
+ int[] loc = new int[2];
+ getLocationOnScreen(loc);
+ int x = loc[0];
+ int y = loc[1];
- v.getLocationOnScreen(location);
- int vX = location[0];
- int vY = location[1];
+ v.getLocationOnScreen(loc);
+ int vX = loc[0];
+ int vY = loc[1];
- location[0] = vX - x;
- location[1] = vY - y;
+ int left = vX - x;
+ int top = vY - y;
+ r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
}
@Override
@@ -308,55 +314,59 @@ public class DragLayer extends FrameLayout {
((CellLayoutChildren) child.getParent()).measureChild(child);
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
- int[] loc = new int[2];
- getViewLocationRelativeToSelf(dragView, loc);
+ Rect r = new Rect();
+ getViewRectRelativeToSelf(dragView, r);
int coord[] = new int[2];
coord[0] = lp.x;
coord[1] = lp.y;
getDescendantCoordRelativeToSelf(child, coord);
- final int fromX = loc[0] + (dragView.getWidth() - child.getMeasuredWidth()) / 2;
- final int fromY = loc[1] + (dragView.getHeight() - child.getMeasuredHeight()) / 2;
- final int dx = coord[0] - fromX;
- final int dy = coord[1] - fromY;
-
+ final int fromX = r.left + (dragView.getWidth() - child.getMeasuredWidth()) / 2;
+ final int fromY = r.top + (dragView.getHeight() - child.getMeasuredHeight()) / 2;
child.setVisibility(INVISIBLE);
- animateViewIntoPosition(child, fromX, fromY, dx, dy);
+ animateViewIntoPosition(child, fromX, fromY, coord[0], coord[1]);
}
private void animateViewIntoPosition(final View view, final int fromX, final int fromY,
- final int dX, final int dY) {
+ final int toX, final int toY) {
+ Rect from = new Rect(fromX, fromY, fromX + view.getMeasuredWidth(), fromY + view.getMeasuredHeight());
+ Rect to = new Rect(toX, toY, toX + view.getMeasuredWidth(), toY + view.getMeasuredHeight());
+ animateView(view, from, to, 1f, -1);
+ }
+ public void animateView(final View view, final Rect from, final Rect to,
+ final float finalAlpha, int duration) {
+ animateView(view, from, to, finalAlpha, 1.0f, duration, null, null);
+ }
+
+ public void animateView(final View view, final Rect from, final Rect to, final float finalAlpha,
+ final float finalScale, int duration, final Interpolator motionInterpolator,
+ final Interpolator alphaInterpolator) {
// Calculate the duration of the animation based on the object's distance
- final float dist = (float) Math.sqrt(dX*dX + dY*dY);
+ final float dist = (float) Math.sqrt(Math.pow(to.left - from.left, 2) +
+ Math.pow(to.top - from.top, 2));
final Resources res = getResources();
final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
- int duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
- if (dist < maxDist) {
- duration *= mQuintEaseOutInterpolator.getInterpolation(dist / maxDist);
+
+ // If duration < 0, this is a cue to compute the duration based on the distance
+ if (duration < 0) {
+ duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
+ if (dist < maxDist) {
+ duration *= mQuintEaseOutInterpolator.getInterpolation(dist / maxDist);
+ }
}
if (mDropAnim != null) {
mDropAnim.end();
}
- mDropAnim = new ValueAnimator();
- mDropAnim.setInterpolator(mQuintEaseOutInterpolator);
-
- // The view is invisible during the animation; we render it manually.
- mDropAnim.addListener(new AnimatorListenerAdapter() {
- public void onAnimationStart(Animator animation) {
- // Set this here so that we don't render it until the animation begins
- mDropView = view;
- }
- public void onAnimationEnd(Animator animation) {
- if (mDropView != null) {
- mDropView.setVisibility(View.VISIBLE);
- mDropView = null;
- }
- }
- });
+ mDropView = view;
+ final float initialAlpha = view.getAlpha();
+ mDropAnim = new ValueAnimator();
+ if (alphaInterpolator == null || motionInterpolator == null) {
+ mDropAnim.setInterpolator(mQuintEaseOutInterpolator);
+ }
mDropAnim.setDuration(duration);
mDropAnim.setFloatValues(0.0f, 1.0f);
@@ -370,12 +380,27 @@ public class DragLayer extends FrameLayout {
invalidate(mDropViewPos[0], mDropViewPos[1],
mDropViewPos[0] + width, mDropViewPos[1] + height);
- mDropViewPos[0] = fromX + (int) (percent * dX + 0.5f);
- mDropViewPos[1] = fromY + (int) (percent * dY + 0.5f);
+ float alphaPercent = alphaInterpolator == null ? percent :
+ alphaInterpolator.getInterpolation(percent);
+ float motionPercent = motionInterpolator == null ? percent :
+ motionInterpolator.getInterpolation(percent);
+
+ mDropViewPos[0] = from.left + (int) ((to.left - from.left) * motionPercent);
+ mDropViewPos[1] = from.top + (int) ((to.top - from.top) * motionPercent);
+ mDropViewScale = percent * finalScale + (1 - percent);
+ mDropViewAlpha = alphaPercent * finalAlpha + (1 - alphaPercent) * initialAlpha;
invalidate(mDropViewPos[0], mDropViewPos[1],
mDropViewPos[0] + width, mDropViewPos[1] + height);
}
});
+ mDropAnim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ if (mDropView != null) {
+ mDropView.setVisibility(View.VISIBLE);
+ mDropView = null;
+ }
+ }
+ });
mDropAnim.start();
}
@@ -388,7 +413,12 @@ public class DragLayer extends FrameLayout {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
final int xPos = mDropViewPos[0] - mDropView.getScrollX();
final int yPos = mDropViewPos[1] - mDropView.getScrollY();
+ int width = mDropView.getMeasuredWidth();
+ int height = mDropView.getMeasuredHeight();
canvas.translate(xPos, yPos);
+ canvas.translate((1 - mDropViewScale) * width / 2, (1 - mDropViewScale) * height / 2);
+ canvas.scale(mDropViewScale, mDropViewScale);
+ mDropView.setAlpha(mDropViewAlpha);
mDropView.draw(canvas);
canvas.restore();
}
diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java
index 4cc2c5543..d4dc785f7 100644
--- a/src/com/android/launcher2/DragView.java
+++ b/src/com/android/launcher2/DragView.java
@@ -195,6 +195,16 @@ public class DragView extends View {
invalidate();
}
+ @Override
+ public void setAlpha(float alpha) {
+ super.setAlpha(alpha);
+ if (mPaint == null) {
+ mPaint = new Paint();
+ }
+ mPaint.setAlpha((int) (255 * alpha));
+ invalidate();
+ }
+
/**
* Create a window containing this view and show it.
*
@@ -242,7 +252,11 @@ public class DragView extends View {
}
void remove() {
- mWindowManager.removeView(this);
+ post(new Runnable() {
+ public void run() {
+ mWindowManager.removeView(DragView.this);
+ }
+ });
}
int[] getPosition(int[] result) {
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index 37368b98e..13815adbc 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -86,6 +86,7 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL
private int mMaxCountX;
private int mMaxCountY;
private Rect mNewSize = new Rect();
+ private Rect mIconRect = new Rect();
private ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
private Drawable mIconDrawable;
boolean mItemsInvalidated = false;
@@ -134,6 +135,7 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL
if (sHintText == null) {
sHintText = res.getString(R.string.folder_hint_text);
}
+ setLayerType(LAYER_TYPE_HARDWARE, null);
}
@Override
@@ -141,7 +143,6 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL
super.onFinishInflate();
mContent = (CellLayout) findViewById(R.id.folder_content);
mContent.setGridSize(0, 0);
- mContent.enableHardwareLayers();
mFolderName = (TextView) findViewById(R.id.folder_name);
// We find out how tall the text view wants to be (it is set to wrap_content), so that
@@ -372,9 +373,8 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL
* to its associated FolderIcon. This allows for a seamless transition into the expanded state.
*/
private void positionAndSizeAsIcon() {
- if (!(getParent() instanceof CellLayoutChildren)) return;
+ if (!(getParent() instanceof DragLayer)) return;
- DragLayer.LayoutParams iconLp = (DragLayer.LayoutParams) mFolderIcon.getLayoutParams();
DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
if (mMode == PARTIAL_GROW) {
@@ -382,19 +382,19 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL
setScaleY(0.8f);
setAlpha(0f);
} else {
- lp.width = iconLp.width;
- lp.height = iconLp.height;
- lp.x = iconLp.x;
- lp.y = iconLp.y;
+ mLauncher.getDragLayer().getDescendantRectRelativeToSelf(mFolderIcon, mIconRect);
+ lp.width = mIconRect.width();
+ lp.height = mIconRect.height();
+ lp.x = mIconRect.left;
+ lp.y = mIconRect.top;
mContent.setAlpha(0);
}
mState = STATE_SMALL;
}
public void animateOpen() {
- if (mState != STATE_SMALL) {
- positionAndSizeAsIcon();
- }
+ positionAndSizeAsIcon();
+
if (!(getParent() instanceof DragLayer)) return;
ObjectAnimator oa;
@@ -449,13 +449,12 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL
PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 0.9f);
oa = ObjectAnimator.ofPropertyValuesHolder(this, alpha, scaleX, scaleY);
} else {
- DragLayer.LayoutParams iconLp = (DragLayer.LayoutParams) mFolderIcon.getLayoutParams();
DragLayer.LayoutParams lp = (DragLayer.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);
+ PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", mIconRect.width());
+ PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", mIconRect.height());
+ PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", mIconRect.left);
+ PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", mIconRect.top);
oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y);
oa.addUpdateListener(new AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
@@ -645,14 +644,18 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL
OnAlarmListener mOnExitAlarmListener = new OnAlarmListener() {
public void onAlarm(Alarm alarm) {
- mLauncher.closeFolder();
- mCurrentDragInfo = null;
- mCurrentDragView = null;
- mSuppressOnAdd = false;
- mRearrangeOnClose = true;
+ completeDragExit();
}
};
+ private void completeDragExit() {
+ mLauncher.closeFolder();
+ mCurrentDragInfo = null;
+ mCurrentDragView = null;
+ mSuppressOnAdd = false;
+ mRearrangeOnClose = true;
+ }
+
public void onDragExit(DragObject d) {
// We only close the folder if this is a true drag exit, ie. not because a drop
// has occurred above the folder.
@@ -674,6 +677,11 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL
}
}
// TODO: if the drag fails, we need to re-add the item
+ } else {
+ if (target != this) {
+ mOnExitAlarm.cancelAlarm();
+ completeDragExit();
+ }
}
}
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
index bae2fd77c..aff8761fd 100644
--- a/src/com/android/launcher2/FolderIcon.java
+++ b/src/com/android/launcher2/FolderIcon.java
@@ -25,11 +25,14 @@ import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PorterDuff;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -276,17 +279,30 @@ public class FolderIcon extends LinearLayout implements FolderListener {
mFolderRingAnimator.animateToNaturalState();
}
- public void onDrop(Object dragInfo) {
+ public void onDrop(DragObject d) {
ShortcutInfo item;
- if (dragInfo instanceof ApplicationInfo) {
+ if (d.dragInfo instanceof ApplicationInfo) {
// Came from all apps -- make a copy
- item = ((ApplicationInfo) dragInfo).makeShortcut();
+ item = ((ApplicationInfo) d.dragInfo).makeShortcut();
} else {
- item = (ShortcutInfo) dragInfo;
+ item = (ShortcutInfo) d.dragInfo;
}
item.cellX = -1;
item.cellY = -1;
addItem(item);
+ DragLayer dragLayer = mLauncher.getDragLayer();
+ Rect from = new Rect();
+ dragLayer.getViewRectRelativeToSelf(d.dragView, from);
+ Rect to = new Rect();
+ dragLayer.getDescendantRectRelativeToSelf(this, to);
+
+ int previewSize = FolderRingAnimator.sPreviewSize;
+ int vanishingPointX = (int) (previewSize * 0.7);
+ int vanishingPointY = (int) (previewSize * (1 - 0.88f));
+ to.offset(vanishingPointX - previewSize / 2 , vanishingPointY - previewSize / 2);
+
+ dragLayer.animateView(d.dragView, from, to, 0f, 0.2f, 400, new DecelerateInterpolator(2),
+ new AccelerateInterpolator(2));
}
public DropTarget getDropTargetDelegate(DragObject d) {
@@ -323,20 +339,17 @@ public class FolderIcon extends LinearLayout implements FolderListener {
float maxPerspectiveShift = baselineSize * PERSPECTIVE_SHIFT_FACTOR;
ArrayList<View> items = mFolder.getItemsInReadingOrder(false);
- int firstItemIndex = Math.max(0, items.size() - NUM_ITEMS_IN_PREVIEW);
int xShift = (mOriginalWidth - 2 * halfAvailableSpace) / 2;
int yShift = previewPadding;
canvas.translate(xShift, yShift);
- for (int i = firstItemIndex; i < items.size(); i++) {
- int index = i - firstItemIndex;
- index += Math.max(0, NUM_ITEMS_IN_PREVIEW - items.size());
+ int nItemsInPreview = Math.min(items.size(), NUM_ITEMS_IN_PREVIEW);
+ for (int i = nItemsInPreview - 1; i >= 0; i--) {
+ int index = NUM_ITEMS_IN_PREVIEW - i - 1;
float r = (index * 1.0f) / (NUM_ITEMS_IN_PREVIEW - 1);
float scale = (1 - PERSPECTIVE_SCALE_FACTOR * (1 - r));
- //r = (float) Math.pow(r, 2);
-
float offset = (1 - r) * maxPerspectiveShift;
float scaledSize = scale * baselineSize;
float scaleOffsetCorrection = (1 - scale) * baselineSize;
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 5ba9fd7af..d728001ea 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -2240,12 +2240,12 @@ public class Workspace extends SmoothPagedView
}
boolean addToExistingFolderIfNecessary(View newView, CellLayout target, int[] targetCell,
- Object dragInfo, boolean external) {
+ DragObject d, boolean external) {
View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);
if (dropOverView instanceof FolderIcon) {
FolderIcon fi = (FolderIcon) dropOverView;
- if (fi.acceptDrop(dragInfo)) {
- fi.onDrop(dragInfo);
+ if (fi.acceptDrop(d.dragInfo)) {
+ fi.onDrop(d);
// if the drag started here, we need to remove it from the workspace
if (!external) {
@@ -2281,7 +2281,7 @@ public class Workspace extends SmoothPagedView
if (d.dragSource != this) {
final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0],
(int) mDragViewVisualCenter[1] };
- onDropExternal(touchXY, d.dragInfo, dropTargetLayout, false, d.dragView);
+ onDropExternal(touchXY, d.dragInfo, dropTargetLayout, false, d);
} else if (mDragInfo != null) {
final View cell = mDragInfo.cell;
@@ -2305,8 +2305,7 @@ public class Workspace extends SmoothPagedView
return;
}
- if (addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell,
- d.dragInfo, false)) {
+ if (addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell, d, false)) {
return;
}
@@ -2936,7 +2935,7 @@ public class Workspace extends SmoothPagedView
* to add an item to one of the workspace screens.
*/
private void onDropExternal(int[] touchXY, Object dragInfo,
- CellLayout cellLayout, boolean insertAtFirst, DragView dragView) {
+ CellLayout cellLayout, boolean insertAtFirst, DragObject d) {
int screen = indexOfChild(cellLayout);
if (screen != mCurrentPage && mShrinkState != ShrinkState.SPRING_LOADED) {
snapToPage(screen);
@@ -2989,7 +2988,7 @@ public class Workspace extends SmoothPagedView
if (createUserFolderIfNecessary(view, cellLayout, mTargetCell, true)) {
return;
}
- if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, dragInfo, true)) {
+ if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, d, true)) {
return;
}
}
@@ -3008,13 +3007,13 @@ public class Workspace extends SmoothPagedView
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
cellLayout.getChildrenLayout().measureChild(view);
- if (dragView != null) {
- mLauncher.getDragLayer().animateViewIntoPosition(dragView, view);
- }
-
LauncherModel.addOrMoveItemInDatabase(mLauncher, info,
LauncherSettings.Favorites.CONTAINER_DESKTOP, screen,
lp.cellX, lp.cellY);
+
+ if (d.dragView != null) {
+ mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, view);
+ }
}
}