Merge "Adding visual feedback for folder creation`"

This commit is contained in:
Adam Cohen 2011-06-01 11:53:06 -07:00 committed by Android (Google) Code Review
commit 62ddd762ce
3 changed files with 207 additions and 110 deletions

View File

@ -78,10 +78,7 @@ public class FolderIcon extends FrameLayout implements DropTarget, FolderListene
private int mOriginalWidth = -1;
private int mOriginalHeight = -1;
private int mFolderLocX;
private int mFolderLocY;
private float mOuterRingScale;
private float mInnerRingScale;
FolderRingAnimator mFolderRingAnimator = null;
public FolderIcon(Context context, AttributeSet attrs) {
super(context, attrs);
@ -117,18 +114,107 @@ public class FolderIcon extends FrameLayout implements DropTarget, FolderListene
folder.setFolderIcon(icon);
folder.bind(folderInfo);
icon.mFolder = folder;
icon.mFolderRingAnimator = new FolderRingAnimator(launcher, icon);
folderInfo.addListener(icon);
if (sFolderOuterRingDrawable == null) {
sFolderOuterRingDrawable =
launcher.getResources().getDrawable(R.drawable.portal_ring_outer_holo);
return icon;
}
public static class FolderRingAnimator {
public int mFolderLocX;
public int mFolderLocY;
public float mOuterRingScale;
public float mInnerRingScale;
public FolderIcon mFolderIcon = null;
private Launcher mLauncher;
public FolderRingAnimator(Launcher launcher, FolderIcon folderIcon) {
mLauncher = launcher;
mFolderIcon = folderIcon;
if (sFolderOuterRingDrawable == null) {
sFolderOuterRingDrawable =
launcher.getResources().getDrawable(R.drawable.portal_ring_outer_holo);
}
if (sFolderInnerRingDrawable == null) {
sFolderInnerRingDrawable =
launcher.getResources().getDrawable(R.drawable.portal_ring_inner_holo);
}
}
if (sFolderInnerRingDrawable == null) {
sFolderInnerRingDrawable =
launcher.getResources().getDrawable(R.drawable.portal_ring_inner_holo);
public void setLocation(int x, int y) {
mFolderLocX = x;
mFolderLocY = y;
}
public void animateToAcceptState() {
ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
va.setDuration(CONSUMPTION_ANIMATION_DURATION);
va.addUpdateListener(new AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
final float percent = (Float) animation.getAnimatedValue();
mOuterRingScale = OUTER_RING_BASELINE_SCALE + percent * OUTER_RING_GROWTH_FACTOR;
mInnerRingScale = INNER_RING_BASELINE_SCALE + percent * INNER_RING_GROWTH_FACTOR;
mLauncher.getWorkspace().invalidate();
if (mFolderIcon != null) {
mFolderIcon.invalidate();
}
}
});
va.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// Instead of setting the background drawable to null, we set the color to
// transparent. Setting the background drawable to null results in onDraw
// not getting called.
if (mFolderIcon != null) {
mFolderIcon.setBackgroundColor(Color.TRANSPARENT);
mFolderIcon.requestLayout();
}
}
});
va.start();
}
public void animateToNaturalState() {
ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
va.setDuration(CONSUMPTION_ANIMATION_DURATION);
va.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;
mInnerRingScale = INNER_RING_BASELINE_SCALE + INNER_RING_GROWTH_FACTOR
- percent * INNER_RING_GROWTH_FACTOR;
mLauncher.getWorkspace().invalidate();
if (mFolderIcon != null) {
mFolderIcon.invalidate();
}
}
});
va.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (mFolderIcon != null) {
mFolderIcon.setBackgroundDrawable(sFolderInnerRingDrawable);
}
mLauncher.getWorkspace().hideFolderAccept(FolderRingAnimator.this);
}
});
va.start();
}
public void getLocation(int[] loc) {
loc[0] = mFolderLocX;
loc[1] = mFolderLocY;
}
public float getOuterRingScale() {
return mOuterRingScale;
}
public float getInnerRingScale() {
return mInnerRingScale;
}
return icon;
}
private boolean willAcceptItem(ItemInfo item) {
@ -166,69 +252,22 @@ public class FolderIcon extends FrameLayout implements DropTarget, FolderListene
mOriginalHeight = lp.height;
}
private void animateToAcceptState() {
ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
va.setDuration(CONSUMPTION_ANIMATION_DURATION);
va.addUpdateListener(new AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
final float percent = (Float) animation.getAnimatedValue();
mOuterRingScale = OUTER_RING_BASELINE_SCALE + percent * OUTER_RING_GROWTH_FACTOR;
mInnerRingScale = INNER_RING_BASELINE_SCALE + percent * INNER_RING_GROWTH_FACTOR;
mLauncher.getWorkspace().invalidate();
invalidate();
}
});
va.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// Instead of setting the background drawable to null, we set the color to
// transparent. Setting the background drawable to null results in onDraw
// not getting called.
setBackgroundColor(Color.TRANSPARENT);
requestLayout();
}
});
va.start();
}
private void animateToNaturalState() {
ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
va.setDuration(CONSUMPTION_ANIMATION_DURATION);
va.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;
mInnerRingScale = INNER_RING_BASELINE_SCALE + INNER_RING_GROWTH_FACTOR
- percent * INNER_RING_GROWTH_FACTOR;
mLauncher.getWorkspace().invalidate();
invalidate();
}
});
va.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
setBackgroundDrawable(sFolderInnerRingDrawable);
mLauncher.getWorkspace().hideFolderAccept(FolderIcon.this);
}
});
va.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;
int x = tvLocation[0] - wsLocation[0] + getMeasuredWidth() / 2;
int y = tvLocation[1] - wsLocation[1] + getMeasuredHeight() / 2;
mFolderRingAnimator.setLocation(x, y);
}
public void onDragEnter(DragObject d) {
if (!willAcceptItem((ItemInfo) d.dragInfo)) return;
determineFolderLocationInWorkspace();
mLauncher.getWorkspace().showFolderAccept(this);
animateToAcceptState();
mLauncher.getWorkspace().showFolderAccept(mFolderRingAnimator);
mFolderRingAnimator.animateToAcceptState();
}
public void onDragOver(DragObject d) {
@ -236,26 +275,13 @@ public class FolderIcon extends FrameLayout implements DropTarget, FolderListene
public void onDragExit(DragObject d) {
if (!willAcceptItem((ItemInfo) d.dragInfo)) return;
animateToNaturalState();
mFolderRingAnimator.animateToNaturalState();
}
public DropTarget getDropTargetDelegate(DragObject d) {
return null;
}
public void getFolderLocation(int[] loc) {
loc[0] = mFolderLocX;
loc[1] = mFolderLocY;
}
public float getOuterRingScale() {
return mOuterRingScale;
}
public float getInnerRingScale() {
return mInnerRingScale;
}
@Override
protected void onDraw(Canvas canvas) {
if (mFolder == null) return;

View File

@ -60,7 +60,7 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView
mHasPerformedLongPress = false;
return true;
}
// Watch for longpress events at this level to make sure
// users can always pick up this widget
switch (ev.getAction()) {
@ -68,7 +68,7 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView
postCheckForLongClick();
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mHasPerformedLongPress = false;
@ -77,7 +77,7 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView
}
break;
}
// Otherwise continue letting touch events fall through to children
return false;
}

View File

@ -67,6 +67,7 @@ import android.widget.TextView;
import android.widget.Toast;
import com.android.launcher.R;
import com.android.launcher2.FolderIcon.FolderRingAnimator;
import com.android.launcher2.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
/**
@ -219,7 +220,16 @@ public class Workspace extends SmoothPagedView
private int mLastDragXOffset;
private int mLastDragYOffset;
private ArrayList<FolderIcon> mFolderOuterRings = new ArrayList<FolderIcon>();
private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>();
// Variables relating to the creation of user folders by hovering shortcuts over shortcuts
private static final int FOLDER_CREATION_TIMEOUT = 400;
private final Alarm mFolderCreationAlarm = new Alarm();
private FolderRingAnimator mDragFolderRingAnimator = null;
private View mLastDragOverView = null;
private boolean mCreateUserFolderOnDrop = false;
private int mCellWidth = -1;
private int mCellHeight = -1;
// Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget)
private float mXDown;
@ -896,7 +906,6 @@ public class Workspace extends SmoothPagedView
}
float fractionToCatchUpIn1MsVertical = mVerticalCatchupConstant;
fractionToCatchUpIn1MsHorizontal /= 33f;
fractionToCatchUpIn1MsVertical /= 33f;
@ -1184,14 +1193,15 @@ public class Workspace extends SmoothPagedView
}
}
public void showFolderAccept(FolderIcon fi) {
mFolderOuterRings.add(fi);
public void showFolderAccept(FolderRingAnimator fra) {
mFolderOuterRings.add(fra);
}
public void hideFolderAccept(FolderIcon fi) {
if (mFolderOuterRings.contains(fi)) {
mFolderOuterRings.remove(fi);
public void hideFolderAccept(FolderRingAnimator fra) {
if (mFolderOuterRings.contains(fra)) {
mFolderOuterRings.remove(fra);
}
invalidate();
}
@Override
@ -1234,24 +1244,28 @@ public class Workspace extends SmoothPagedView
for (int i = 0; i < mFolderOuterRings.size(); i++) {
// Draw outer ring
FolderIcon fi = mFolderOuterRings.get(i);
FolderRingAnimator fra = mFolderOuterRings.get(i);
Drawable d = FolderIcon.sFolderOuterRingDrawable;
int width = (int) (d.getIntrinsicWidth() * fi.getOuterRingScale());
int height = (int) (d.getIntrinsicHeight() * fi.getOuterRingScale());
fi.getFolderLocation(mTempLocation);
int width = (int) (d.getIntrinsicWidth() * fra.getOuterRingScale());
int height = (int) (d.getIntrinsicHeight() * fra.getOuterRingScale());
fra.getLocation(mTempLocation);
int x = mTempLocation[0] + mScrollX - width / 2;
int y = mTempLocation[1] + mScrollY - height / 2;
d.setBounds(x, y, x + width, y + height);
d.draw(canvas);
// Draw inner ring
d = FolderIcon.sFolderInnerRingDrawable;
width = (int) (fi.getMeasuredWidth() * fi.getInnerRingScale());
height = (int) (fi.getMeasuredHeight() * fi.getInnerRingScale());
x = mTempLocation[0] + mScrollX - width / 2;
y = mTempLocation[1] + mScrollY - height / 2;
d.setBounds(x, y, x + width, y + height);
d.draw(canvas);
if (fra.mFolderIcon != null) {
int folderWidth = fra.mFolderIcon != null ? fra.mFolderIcon.getMeasuredWidth() : mCellWidth;
int folderHeight = fra.mFolderIcon != null ? fra.mFolderIcon.getMeasuredWidth() : mCellHeight;
d = FolderIcon.sFolderInnerRingDrawable;
width = (int) (folderWidth * fra.getInnerRingScale());
height = (int) (folderHeight * fra.getInnerRingScale());
x = mTempLocation[0] + mScrollX - width / 2;
y = mTempLocation[1] + mScrollY - height / 2;
d.setBounds(x, y, x + width, y + height);
d.draw(canvas);
}
}
super.onDraw(canvas);
}
@ -2404,9 +2418,7 @@ public class Workspace extends SmoothPagedView
}
boolean willCreateUserFolder(ItemInfo info, CellLayout target, int originX, int originY) {
mTargetCell = findNearestArea(originX, originY,
1, 1, target,
mTargetCell);
mTargetCell = findNearestArea(originX, originY, 1, 1, target, mTargetCell);
View v = target.getChildAt(mTargetCell[0], mTargetCell[1]);
boolean hasntMoved = mDragInfo != null && (mDragInfo.cellX == mTargetCell[0] &&
@ -2437,8 +2449,8 @@ public class Workspace extends SmoothPagedView
boolean hasntMoved = mDragInfo != null && (mDragInfo.cellX == mTargetCell[0] &&
mDragInfo.cellY == mTargetCell[1]);
if (v == null || hasntMoved) return false;
if (v == null || hasntMoved || !mCreateUserFolderOnDrop) return false;
mCreateUserFolderOnDrop = false;
final int screen = (mTargetCell == null) ?
mDragInfo.screen : indexOfChild(target);
@ -3047,24 +3059,83 @@ public class Workspace extends SmoothPagedView
mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null);
ItemInfo info = (ItemInfo) d.dragInfo;
if (!willCreateUserFolder(info, mDragTargetLayout,
(int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1])) {
boolean willCreateUserFolder = willCreateUserFolder(info, mDragTargetLayout,
(int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1]);
View newDropOver = null;
if (willCreateUserFolder) {
newDropOver = mDragTargetLayout.getChildAt(mTargetCell[0], mTargetCell[1]);
}
if (newDropOver != mLastDragOverView || !willCreateUserFolder) {
if (mDragFolderRingAnimator != null && mCreateUserFolderOnDrop) {
mDragFolderRingAnimator.animateToNaturalState();
}
mCreateUserFolderOnDrop = false;
mFolderCreationAlarm.cancelAlarm();
mIsDraggingOverIcon = false;
}
if (willCreateUserFolder && !mIsDraggingOverIcon) {
mIsDraggingOverIcon = true;
mLastDragOverView = mDragTargetLayout.getChildAt(mTargetCell[0], mTargetCell[1]);
mFolderCreationAlarm.setOnAlarmListener(new FolderCreationAlarmListener(mLastDragOverView));
mFolderCreationAlarm.setAlarm(FOLDER_CREATION_TIMEOUT);
mDragTargetLayout.clearDragOutlines();
}
if (!mCreateUserFolderOnDrop) {
mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
(int) mDragViewVisualCenter[0],
(int) mDragViewVisualCenter[1],
item.spanX, item.spanY);
} else if (!mIsDraggingOverIcon) {
mIsDraggingOverIcon = true;
mDragTargetLayout.clearDragOutlines();
}
}
}
}
}
class FolderCreationAlarmListener implements OnAlarmListener {
View v;
public FolderCreationAlarmListener(View v) {
this.v = v;
}
public void onAlarm(Alarm alarm) {
int tvLocation[] = new int[2];
int wsLocation[] = new int[2];
v.getLocationOnScreen(tvLocation);
getLocationOnScreen(wsLocation);
if (mCellWidth < 0 || mCellHeight < 0) {
mCellWidth = mDragTargetLayout.getCellWidth();
mCellHeight = mDragTargetLayout.getCellHeight();
}
int x = tvLocation[0] - wsLocation[0] + mCellWidth / 2;
int y = tvLocation[1] - wsLocation[1] + mCellHeight / 2;
if (mDragFolderRingAnimator == null) {
mDragFolderRingAnimator = new FolderRingAnimator(mLauncher, null);
}
mDragFolderRingAnimator.setLocation(x, y);
mDragFolderRingAnimator.animateToAcceptState();
showFolderAccept(mDragFolderRingAnimator);
mCreateUserFolderOnDrop = true;
mDragTargetLayout.clearDragOutlines();
}
}
private void doDragExit() {
mWasSpringLoadedOnDragExit = mShrinkState == ShrinkState.SPRING_LOADED;
if (mDragFolderRingAnimator != null && mCreateUserFolderOnDrop) {
mDragFolderRingAnimator.animateToNaturalState();
}
mFolderCreationAlarm.cancelAlarm();
if (mDragTargetLayout != null) {
mDragTargetLayout.onDragExit();
}