summaryrefslogtreecommitdiffstats
path: root/src/com
diff options
context:
space:
mode:
authorAdam Cohen <adamcohen@google.com>2011-06-13 16:55:12 -0700
committerAdam Cohen <adamcohen@google.com>2011-06-13 16:55:12 -0700
commitbfbfd26c627a18f8e1e3e6d0e53e78feab360203 (patch)
tree0f823f053dcd28e303d19733e73f8215e0598b3d /src/com
parent61fa4197c4316bb0f9b05fcefb676f86197a2273 (diff)
downloadandroid_packages_apps_Trebuchet-bfbfd26c627a18f8e1e3e6d0e53e78feab360203.tar.gz
android_packages_apps_Trebuchet-bfbfd26c627a18f8e1e3e6d0e53e78feab360203.tar.bz2
android_packages_apps_Trebuchet-bfbfd26c627a18f8e1e3e6d0e53e78feab360203.zip
Initial implementation of folder reordering
Change-Id: I9f700e71f46e3b91afa96742d9e3890d519c391d
Diffstat (limited to 'src/com')
-rw-r--r--src/com/android/launcher2/CellLayout.java63
-rw-r--r--src/com/android/launcher2/CellLayoutChildren.java4
-rw-r--r--src/com/android/launcher2/DragController.java3
-rw-r--r--src/com/android/launcher2/DropTarget.java6
-rw-r--r--src/com/android/launcher2/Folder.java230
-rw-r--r--src/com/android/launcher2/Workspace.java37
6 files changed, 240 insertions, 103 deletions
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index e5aa7a96a..a9ba88d94 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -20,6 +20,7 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
@@ -48,6 +49,7 @@ import android.view.animation.LayoutAnimationController;
import com.android.launcher.R;
import java.util.Arrays;
+import java.util.HashMap;
public class CellLayout extends ViewGroup {
static final String TAG = "CellLayout";
@@ -118,6 +120,9 @@ public class CellLayout extends ViewGroup {
private InterruptibleInOutAnimator mCrosshairsAnimator = null;
private float mCrosshairsVisibility = 0.0f;
+ private HashMap<CellLayout.LayoutParams, ObjectAnimator> mReorderAnimators = new
+ HashMap<CellLayout.LayoutParams, ObjectAnimator>();
+
// When a drag operation is in progress, holds the nearest cell to the touch point
private final int[] mDragCell = new int[2];
@@ -966,6 +971,64 @@ public class CellLayout extends ViewGroup {
return mChildren.getChildAt(x, y);
}
+ public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration) {
+ CellLayoutChildren clc = getChildrenLayout();
+ if (clc.indexOfChild(child) != -1 && !mOccupied[cellX][cellY]) {
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ final ItemInfo info = (ItemInfo) child.getTag();
+
+ // We cancel any existing animations
+ if (mReorderAnimators.containsKey(lp)) {
+ mReorderAnimators.get(lp).cancel();
+ mReorderAnimators.remove(lp);
+ }
+
+ int oldX = lp.x;
+ int oldY = lp.y;
+ mOccupied[lp.cellX][lp.cellY] = false;
+ mOccupied[cellX][cellY] = true;
+
+ lp.isLockedToGrid = true;
+ lp.cellX = info.cellX = cellX;
+ lp.cellY = info.cellY = cellY;
+ clc.setupLp(lp);
+ lp.isLockedToGrid = false;
+ int newX = lp.x;
+ int newY = lp.y;
+
+ PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", oldX, newX);
+ PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", oldY, newY);
+ ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, x, y);
+ oa.setDuration(duration);
+ mReorderAnimators.put(lp, oa);
+ oa.addUpdateListener(new AnimatorUpdateListener() {
+ public void onAnimationUpdate(ValueAnimator animation) {
+ child.requestLayout();
+ }
+ });
+ oa.addListener(new AnimatorListenerAdapter() {
+ boolean cancelled = false;
+ public void onAnimationEnd(Animator animation) {
+ // If the animation was cancelled, it means that another animation
+ // has interrupted this one, and we don't want to lock the item into
+ // place just yet.
+ if (!cancelled) {
+ lp.isLockedToGrid = true;
+ }
+ if (mReorderAnimators.containsKey(lp)) {
+ mReorderAnimators.remove(lp);
+ }
+ }
+ public void onAnimationCancel(Animator animation) {
+ cancelled = true;
+ }
+ });
+ oa.start();
+ return true;
+ }
+ return false;
+ }
+
/**
* Estimate where the top left cell of the dragged item will land if it is dropped.
*
diff --git a/src/com/android/launcher2/CellLayoutChildren.java b/src/com/android/launcher2/CellLayoutChildren.java
index 59db9c9ed..6e78885de 100644
--- a/src/com/android/launcher2/CellLayoutChildren.java
+++ b/src/com/android/launcher2/CellLayoutChildren.java
@@ -79,6 +79,10 @@ public class CellLayoutChildren extends ViewGroup {
setMeasuredDimension(widthSpecSize, heightSpecSize);
}
+ public void setupLp(CellLayout.LayoutParams lp) {
+ lp.setup(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
+ }
+
public void measureChild(View child) {
final int cellWidth = mCellWidth;
final int cellHeight = mCellHeight;
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index 8ad5c7ce5..5b1b20a68 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -284,6 +284,7 @@ public class DragController {
mDragging = true;
+ mDragObject.dragComplete = false;
mDragObject.xOffset = mMotionDownX - (screenX + dragRegionLeft);
mDragObject.yOffset = mMotionDownY - (screenY + dragRegionTop);
mDragObject.dragSource = source;
@@ -373,6 +374,7 @@ public class DragController {
public void cancelDrag() {
if (mDragging) {
// Should we also be calling onDragExit() here?
+ mDragObject.dragComplete = true;
mDragObject.dragSource.onDropCompleted(null, mDragObject, false);
}
endDrag();
@@ -565,6 +567,7 @@ public class DragController {
mDragObject.y = coordinates[1];
boolean accepted = false;
if (dropTarget != null) {
+ mDragObject.dragComplete = true;
dropTarget.onDragExit(mDragObject);
if (dropTarget.acceptDrop(mDragObject)) {
dropTarget.onDrop(mDragObject);
diff --git a/src/com/android/launcher2/DropTarget.java b/src/com/android/launcher2/DropTarget.java
index 9c0faf31f..6e18479ac 100644
--- a/src/com/android/launcher2/DropTarget.java
+++ b/src/com/android/launcher2/DropTarget.java
@@ -34,6 +34,12 @@ public interface DropTarget {
/** Y offset from the upper-left corner of the cell to where we touched. */
public int yOffset = -1;
+ /** This indicates whether a drag is in final stages, either drop or cancel. It
+ * differentiates onDragExit, since this is called when the drag is ending, above
+ * the current drag target, or when the drag moves off the current drag object.
+ */
+ public boolean dragComplete = false;
+
/** The view that moves around while you drag. */
public DragView dragView = null;
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index d6be3072c..d81183c6b 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -23,6 +23,7 @@ import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
+import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
@@ -54,11 +55,6 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL
protected Launcher mLauncher;
protected FolderInfo mInfo;
-
- /**
- * Which item is being dragged
- */
- protected ShortcutInfo mDragItem;
private static final String TAG = "Launcher.Folder";
@@ -75,6 +71,8 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL
private int[] mDragItemPosition = new int[2];
private static final int FULL_GROW = 0;
private static final int PARTIAL_GROW = 1;
+ private static final int REORDER_ANIMATION_DURATION = 230;
+ private static final int ON_EXIT_CLOSE_DELAY = 800;
private int mMode = PARTIAL_GROW;
private boolean mRearrangeOnClose = false;
private FolderIcon mFolderIcon;
@@ -84,7 +82,14 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL
private ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
private Drawable mIconDrawable;
boolean mItemsInvalidated = false;
- ShortcutInfo mCurrentDragInfo;
+ private ShortcutInfo mCurrentDragInfo;
+ private View mCurrentDragView;
+ boolean mSuppressOnAdd = false;
+ private int[] mTargetCell = new int[2];
+ private int[] mPreviousTargetCell = new int[2];
+ private int[] mEmptyCell = new int[2];
+ private Alarm mReorderAlarm = new Alarm();
+ private Alarm mOnExitAlarm = new Alarm();
/**
* Used to inflate the Workspace from XML.
@@ -136,8 +141,6 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL
public boolean onLongClick(View v) {
Object tag = v.getTag();
if (tag instanceof ShortcutInfo) {
- mLauncher.closeFolder(this);
-
ShortcutInfo item = (ShortcutInfo) tag;
if (!v.isInTouchMode()) {
return false;
@@ -150,10 +153,11 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL
mIconDrawable = ((TextView) v).getCompoundDrawables()[1];
mCurrentDragInfo = item;
- mItemsInvalidated = true;
- mInfo.itemsChanged();
-
- mDragItem = item;
+ mEmptyCell[0] = item.cellX;
+ mEmptyCell[1] = item.cellY;
+ mCurrentDragView = v;
+ mContent.removeView(mCurrentDragView);
+ mInfo.remove(item);
} else {
mLauncher.closeFolder(this);
mLauncher.showRenameDialog(mInfo);
@@ -182,8 +186,6 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL
mDragController.startDrag(view, this, app, DragController.DRAG_ACTION_COPY);
mLauncher.closeFolder(this);
- mDragItem = app;
-
return true;
}
@@ -382,25 +384,6 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL
!isFull());
}
- public void onDrop(DragObject d) {
- ShortcutInfo item;
- if (d.dragInfo instanceof ApplicationInfo) {
- // Came from all apps -- make a copy
- item = ((ApplicationInfo) d.dragInfo).makeShortcut();
- item.spanX = 1;
- item.spanY = 1;
- } else {
- item = (ShortcutInfo) d.dragInfo;
- }
-
- // Dragged from self onto self
- if (item == mCurrentDragInfo) {
- mInfo.remove(item);
- }
-
- mInfo.add(item);
- }
-
protected boolean findAndSetEmptyCells(ShortcutInfo item) {
int[] emptyCell = new int[2];
if (mContent.findCellForSpan(emptyCell, item.spanX, item.spanY)) {
@@ -430,46 +413,135 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL
}
public void onDragEnter(DragObject d) {
+ mPreviousTargetCell[0] = -1;
+ mPreviousTargetCell[1] = -1;
mContent.onDragEnter();
+ mOnExitAlarm.cancelAlarm();
}
- public void onDragOver(DragObject d) {
- float[] r = mapPointFromScreenToContent(d.x, d.y, null);
- mContent.visualizeDropLocation(null, null, (int) r[0], (int) r[1], 1, 1);
+ OnAlarmListener mReorderAlarmListener = new OnAlarmListener() {
+ public void onAlarm(Alarm alarm) {
+ realTimeReorder(mEmptyCell, mTargetCell);
+ }
+ };
+
+ boolean readingOrderGreaterThan(int[] v1, int[] v2) {
+ if (v1[1] > v2[1] || (v1[1] == v2[1] && v1[0] > v2[0])) {
+ return true;
+ } else {
+ return false;
+ }
}
- public void onDragExit(DragObject d) {
- mContent.onDragExit();
+ private void realTimeReorder(int[] empty, int[] target) {
+ boolean wrap;
+ int startX;
+ int endX;
+ int startY;
+ if (readingOrderGreaterThan(target, empty)) {
+ wrap = empty[0] >= mContent.getCountX() - 1;
+ startY = wrap ? empty[1] + 1 : empty[1];
+ for (int y = startY; y <= target[1]; y++) {
+ startX = y == empty[1] ? empty[0] + 1 : 0;
+ endX = y < target[1] ? mContent.getCountX() - 1 : target[0];
+ for (int x = startX; x <= endX; x++) {
+ View v = mContent.getChildAt(x,y);
+ if (mContent.animateChildToPosition(v, empty[0], empty[1],
+ REORDER_ANIMATION_DURATION)) {
+ empty[0] = x;
+ empty[1] = y;
+ }
+ }
+ }
+ } else {
+ wrap = empty[0] == 0;
+ startY = wrap ? empty[1] - 1 : empty[1];
+ for (int y = startY; y >= target[1]; y--) {
+ startX = y == empty[1] ? empty[0] - 1 : mContent.getCountX() - 1;
+ endX = y > target[1] ? 0 : target[0];
+ for (int x = startX; x >= endX; x--) {
+ View v = mContent.getChildAt(x,y);
+ if (mContent.animateChildToPosition(v, empty[0], empty[1],
+ REORDER_ANIMATION_DURATION)) {
+ empty[0] = x;
+ empty[1] = y;
+ }
+ }
+ }
+ }
}
- public float[] mapPointFromScreenToContent(int x, int y, float[] r) {
- if (r == null) {
- r = new float[2];
+ public void onDragOver(DragObject d) {
+ float[] r = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView, null);
+ mTargetCell = mContent.findNearestArea((int) r[0], (int) r[1], 1, 1, mTargetCell);
+
+ if (mTargetCell[0] != mPreviousTargetCell[0] || mTargetCell[1] != mPreviousTargetCell[1]) {
+ mReorderAlarm.cancelAlarm();
+ mReorderAlarm.setOnAlarmListener(mReorderAlarmListener);
+ mReorderAlarm.setAlarm(150);
+ mPreviousTargetCell[0] = mTargetCell[0];
+ mPreviousTargetCell[1] = mTargetCell[1];
}
+ }
+
+ // This is used to compute the visual center of the dragView. The idea is that
+ // the visual center represents the user's interpretation of where the item is, and hence
+ // is the appropriate point to use when determining drop location.
+ private float[] getDragViewVisualCenter(int x, int y, int xOffset, int yOffset,
+ DragView dragView, float[] recycle) {
+ float res[];
+ if (recycle == null) {
+ res = new float[2];
+ } else {
+ res = recycle;
+ }
+
+ // These represent the visual top and left of drag view if a dragRect was provided.
+ // If a dragRect was not provided, then they correspond to the actual view left and
+ // top, as the dragRect is in that case taken to be the entire dragView.
+ // R.dimen.dragViewOffsetY.
+ int left = x - xOffset;
+ int top = y - yOffset;
+
+ // In order to find the visual center, we shift by half the dragRect
+ res[0] = left + dragView.getDragRegion().width() / 2;
+ res[1] = top + dragView.getDragRegion().height() / 2;
+
+ return res;
+ }
- int[] screenLocation = new int[2];
- mContent.getLocationOnScreen(screenLocation);
+ OnAlarmListener mOnExitAlarmListener = new OnAlarmListener() {
+ public void onAlarm(Alarm alarm) {
+ mLauncher.closeFolder(Folder.this);
+ mCurrentDragInfo = null;
+ mCurrentDragView = null;
+ mSuppressOnAdd = false;
+ mRearrangeOnClose = true;
+ }
+ };
- r[0] = x - screenLocation[0];
- r[1] = y - screenLocation[1];
- return r;
+ 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.
+ if (!d.dragComplete) {
+ mOnExitAlarm.setOnAlarmListener(mOnExitAlarmListener);
+ mOnExitAlarm.setAlarm(ON_EXIT_CLOSE_DELAY);
+ }
+ mReorderAlarm.cancelAlarm();
+ mContent.onDragExit();
}
public void onDropCompleted(View target, DragObject d, boolean success) {
+ mCurrentDragInfo = null;
+ mCurrentDragView = null;
+ mSuppressOnAdd = false;
if (!success) {
if (d.dragView != null) {
if (target instanceof CellLayout) {
// TODO: we should animate the item back to the folder in this case
}
}
- mCurrentDragInfo = null;
- mItemsInvalidated = true;
- mInfo.itemsChanged();
- } else {
- if (target != this) {
- mInfo.remove(mCurrentDragInfo);
- mCurrentDragInfo = null;
- }
+ // TODO: if the drag fails, we need to re-add the item
}
}
@@ -594,18 +666,6 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL
mItemsInvalidated = true;
}
- public void onAdd(ShortcutInfo item) {
- mItemsInvalidated = true;
- if (!findAndSetEmptyCells(item)) {
- // The current layout is full, can we expand it?
- setupContentForNumItems(getItemCount() + 1);
- findAndSetEmptyCells(item);
- }
- createAndAddShortcut(item);
- LauncherModel.addOrMoveItemInDatabase(
- mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
- }
-
public int getItemCount() {
return mContent.getChildrenLayout().getChildCount();
}
@@ -621,8 +681,46 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL
}
}
+ public void onDrop(DragObject d) {
+ ShortcutInfo item;
+ if (d.dragInfo instanceof ApplicationInfo) {
+ // Came from all apps -- make a copy
+ item = ((ApplicationInfo) d.dragInfo).makeShortcut();
+ item.spanX = 1;
+ item.spanY = 1;
+ } else {
+ item = (ShortcutInfo) d.dragInfo;
+ }
+ // Dragged from self onto self
+ if (item == mCurrentDragInfo) {
+ ShortcutInfo si = (ShortcutInfo) mCurrentDragView.getTag();
+ CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mCurrentDragView.getLayoutParams();
+ si.cellX = lp.cellX = mEmptyCell[0];
+ si.cellX = lp.cellY = mEmptyCell[1];
+ mContent.addViewToCellLayout(mCurrentDragView, -1, (int)item.id, lp, true);
+ mSuppressOnAdd = true;
+ mItemsInvalidated = true;
+ setupContentDimension(getItemCount());
+ }
+ mInfo.add(item);
+ }
+
+ public void onAdd(ShortcutInfo item) {
+ mItemsInvalidated = true;
+ if (mSuppressOnAdd) return;
+ if (!findAndSetEmptyCells(item)) {
+ // The current layout is full, can we expand it?
+ setupContentForNumItems(getItemCount() + 1);
+ findAndSetEmptyCells(item);
+ }
+ createAndAddShortcut(item);
+ LauncherModel.addOrMoveItemInDatabase(
+ mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
+ }
+
public void onRemove(ShortcutInfo item) {
mItemsInvalidated = true;
+ if (item == mCurrentDragInfo) return;
View v = mContent.getChildAt(mDragItemPosition[0], mDragItemPosition[1]);
mContent.removeView(v);
if (mState == STATE_ANIMATING) {
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index ff2dede6e..1e012540b 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -2555,42 +2555,6 @@ public class Workspace extends SmoothPagedView
}
public DropTarget getDropTargetDelegate(DragObject d) {
-
- if (mIsSmall || mIsInUnshrinkAnimation) {
- // If we're shrunken, don't let anyone drag on folders/etc that are on the mini-screens
- return null;
- }
- // We may need to delegate the drag to a child view. If a 1x1 item
- // would land in a cell occupied by a DragTarget (e.g. a Folder),
- // then drag events should be handled by that child.
-
- ItemInfo item = (ItemInfo) d.dragInfo;
- CellLayout currentLayout = getCurrentDropLayout();
-
- int dragPointX, dragPointY;
- if (item.spanX == 1 && item.spanY == 1) {
- // For a 1x1, calculate the drop cell exactly as in onDragOver
- dragPointX = d.x - d.xOffset;
- dragPointY = d.y - d.yOffset;
- } else {
- // Otherwise, use the exact drag coordinates
- dragPointX = d.x;
- dragPointY = d.y;
- }
- dragPointX += mScrollX - currentLayout.getLeft();
- dragPointY += mScrollY - currentLayout.getTop();
-
- // If we are dragging over a cell that contains a DropTarget that will
- // accept the drop, delegate to that DropTarget.
- final int[] cellXY = mTempCell;
- currentLayout.estimateDropCell(dragPointX, dragPointY, item.spanX, item.spanY, cellXY);
- View child = currentLayout.getChildAt(cellXY[0], cellXY[1]);
- if (child instanceof DropTarget) {
- DropTarget target = (DropTarget)child;
- if (target.acceptDrop(d)) {
- return target;
- }
- }
return null;
}
@@ -3559,5 +3523,4 @@ public class Workspace extends SmoothPagedView
@Override
public void syncPageItems(int page) {
}
-
}