summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/values/colors.xml1
-rw-r--r--src/com/android/launcher/CellLayout.java108
-rw-r--r--src/com/android/launcher/DeleteZone.java5
-rw-r--r--src/com/android/launcher/DragLayer.java84
-rw-r--r--src/com/android/launcher/DropTarget.java38
-rw-r--r--src/com/android/launcher/FolderIcon.java5
-rw-r--r--src/com/android/launcher/UserFolder.java5
-rw-r--r--src/com/android/launcher/Workspace.java101
8 files changed, 271 insertions, 76 deletions
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 557494405..f9cb0c531 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -24,4 +24,5 @@
<color name="delete_color_filter">#A5FF0000</color>
<color name="appwidget_error_color">#fccc</color>
+ <color name="snag_callout_color">#f444</color>
</resources>
diff --git a/src/com/android/launcher/CellLayout.java b/src/com/android/launcher/CellLayout.java
index 91f04200a..fe6b193e1 100644
--- a/src/com/android/launcher/CellLayout.java
+++ b/src/com/android/launcher/CellLayout.java
@@ -174,7 +174,7 @@ public class CellLayout extends ViewGroup {
final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
final boolean[][] occupied = mOccupied;
- findOccupiedCells(xCount, yCount, occupied);
+ findOccupiedCells(xCount, yCount, occupied, null);
cellInfo.cell = null;
cellInfo.cellX = cellXY[0];
@@ -215,7 +215,7 @@ public class CellLayout extends ViewGroup {
final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
final boolean[][] occupied = mOccupied;
- findOccupiedCells(xCount, yCount, occupied);
+ findOccupiedCells(xCount, yCount, occupied, null);
findIntersectingVacantCells(info, info.cellX, info.cellY, xCount, yCount, occupied);
@@ -315,7 +315,7 @@ public class CellLayout extends ViewGroup {
return true;
}
- CellInfo findAllVacantCells(boolean[] occupiedCells) {
+ CellInfo findAllVacantCells(boolean[] occupiedCells, View ignoreView) {
final boolean portrait = mPortrait;
final int xCount = portrait ? mShortAxisCells : mLongAxisCells;
final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
@@ -329,7 +329,7 @@ public class CellLayout extends ViewGroup {
}
}
} else {
- findOccupiedCells(xCount, yCount, occupied);
+ findOccupiedCells(xCount, yCount, occupied, ignoreView);
}
CellInfo cellInfo = new CellInfo();
@@ -527,64 +527,72 @@ public class CellLayout extends ViewGroup {
super.setChildrenDrawnWithCacheEnabled(enabled);
}
- boolean acceptChildDrop(int x, int y, int cellHSpan, int cellVSpan, View cell) {
- int[] cellXY = mCellXY;
- pointToCellRounded(x, y, cellXY);
- int cellX = cellXY[0];
- int cellY = cellXY[1];
-
- return findCell(cellX, cellY, cellHSpan, cellVSpan, cell) == null;
- }
-
/**
- * Finds the first View intersecting with the specified cell. If the cell is outside
- * of the layout, this is returned.
- *
- * @param cellX The X location of the cell to test.
- * @param cellY The Y location of the cell to test.
- * @param cellHSpan The horizontal span of the cell to test.
- * @param cellVSpan The vertical span of the cell to test.
- * @param ignoreCell View to ignore during the test.
- *
- * @return Returns the first View intersecting with the specified cell, this if the cell
- * lies outside of this layout's grid or null if no View was found.
+ * Find a vacant area that will fit the given bounds nearest the requested
+ * cell location. Uses Euclidean distance to score multiple vacant areas.
+ *
+ * @param cellX The X location of the desired location.
+ * @param cellY The Y location of the desired location.
+ * @param spanX Horizontal span of the object.
+ * @param spanY Vertical span of the object.
+ * @param vacantCells Pre-computed set of vacant cells to search.
+ * @param recycle Previously returned value to possibly recycle.
+ * @return The X, Y cell of a vacant area that can contain this object,
+ * nearest the requested location.
*/
- View findCell(int cellX, int cellY, int cellHSpan, int cellVSpan, View ignoreCell) {
- if (cellX < 0 || cellX + cellHSpan > (mPortrait ? mShortAxisCells : mLongAxisCells) ||
- cellY < 0 || cellY + cellVSpan > (mPortrait ? mLongAxisCells : mShortAxisCells)) {
- return this;
+ int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY,
+ CellInfo vacantCells, int[] recycle) {
+
+ // Keep track of best-scoring drop area
+ final int[] bestXY = recycle != null ? recycle : new int[2];
+ final int[] cellXY = mCellXY;
+ double bestDistance = Double.MAX_VALUE;
+
+ // Bail early if vacant cells aren't valid
+ if (!vacantCells.valid) {
+ return null;
}
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- final View view = getChildAt(i);
- if (view == ignoreCell) {
+ // Look across all vacant cells for best fit
+ final int size = vacantCells.vacantCells.size();
+ for (int i = 0; i < size; i++) {
+ final CellInfo.VacantCell cell = vacantCells.vacantCells.get(i);
+
+ // Reject if vacant cell isn't our exact size
+ if (cell.spanX != spanX || cell.spanY != spanY) {
continue;
}
-
- final LayoutParams lp = (LayoutParams) view.getLayoutParams();
- if (cellX < lp.cellX + lp.cellHSpan && lp.cellX < cellX + cellHSpan &&
- cellY < lp.cellY + lp.cellVSpan && lp.cellY < cellY + cellVSpan) {
- return view;
+
+ // Score is center distance from requested pixel
+ cellToPoint(cell.cellX, cell.cellY, cellXY);
+
+ double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2) +
+ Math.pow(cellXY[1] - pixelY, 2));
+ if (distance <= bestDistance) {
+ bestDistance = distance;
+ bestXY[0] = cell.cellX;
+ bestXY[1] = cell.cellY;
}
}
- return null;
+ // Return null if no suitable location found
+ if (bestDistance < Double.MAX_VALUE) {
+ return bestXY;
+ } else {
+ return null;
+ }
}
-
+
/**
* Drop a child at the specified position
*
* @param child The child that is being dropped
- * @param cellX The child's new x location
- * @param cellY The child's new y location
+ * @param targetXY Destination area to move to
*/
- void onDropChild(View child, int cellX, int cellY) {
- int[] cellXY = mCellXY;
- pointToCellRounded(cellX, cellY, cellXY);
+ void onDropChild(View child, int[] targetXY) {
LayoutParams lp = (LayoutParams) child.getLayoutParams();
- lp.cellX = cellXY[0];
- lp.cellY = cellXY[1];
+ lp.cellX = targetXY[0];
+ lp.cellY = targetXY[1];
lp.isDragging = false;
mDragRect.setEmpty();
child.requestLayout();
@@ -688,7 +696,7 @@ public class CellLayout extends ViewGroup {
final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
final boolean[][] occupied = mOccupied;
- findOccupiedCells(xCount, yCount, occupied);
+ findOccupiedCells(xCount, yCount, occupied, null);
return findVacantCell(vacant, spanX, spanY, xCount, yCount, occupied);
}
@@ -723,7 +731,7 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
final boolean[][] occupied = mOccupied;
- findOccupiedCells(xCount, yCount, occupied);
+ findOccupiedCells(xCount, yCount, occupied, null);
final boolean[] flat = new boolean[xCount * yCount];
for (int y = 0; y < yCount; y++) {
@@ -735,7 +743,7 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
return flat;
}
- private void findOccupiedCells(int xCount, int yCount, boolean[][] occupied) {
+ private void findOccupiedCells(int xCount, int yCount, boolean[][] occupied, View ignoreView) {
for (int x = 0; x < xCount; x++) {
for (int y = 0; y < yCount; y++) {
occupied[x][y] = false;
@@ -745,7 +753,7 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
- if (child instanceof Folder) {
+ if (child instanceof Folder || child.equals(ignoreView)) {
continue;
}
LayoutParams lp = (LayoutParams) child.getLayoutParams();
diff --git a/src/com/android/launcher/DeleteZone.java b/src/com/android/launcher/DeleteZone.java
index 7f92c2334..02e8011d0 100644
--- a/src/com/android/launcher/DeleteZone.java
+++ b/src/com/android/launcher/DeleteZone.java
@@ -19,6 +19,7 @@ package com.android.launcher;
import android.widget.ImageView;
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.TranslateAnimation;
@@ -77,6 +78,10 @@ public class DeleteZone extends ImageView implements DropTarget, DragController.
Object dragInfo) {
return true;
}
+
+ public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo, Rect recycle) {
+ return null;
+ }
public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
final ItemInfo item = (ItemInfo) dragInfo;
diff --git a/src/com/android/launcher/DragLayer.java b/src/com/android/launcher/DragLayer.java
index b542de62a..b5b84b86e 100644
--- a/src/com/android/launcher/DragLayer.java
+++ b/src/com/android/launcher/DragLayer.java
@@ -113,8 +113,25 @@ public class DragLayer extends FrameLayout implements DragController {
private DropTarget mLastDropTarget;
private final Paint mTrashPaint = new Paint();
+ private final Paint mEstimatedPaint = new Paint();
private Paint mDragPaint;
+ /**
+ * If true, draw a "snag" showing where the object currently being dragged
+ * would end up if dropped from current location.
+ */
+ private static final boolean DRAW_TARGET_SNAG = false;
+
+ private Rect mEstimatedRect = new Rect();
+ private float[] mDragCenter = new float[2];
+ private float[] mEstimatedCenter = new float[2];
+ private boolean mDrawEstimated = false;
+
+ private int mTriggerWidth = -1;
+ private int mTriggerHeight = -1;
+
+ private static final int DISTANCE_DRAW_SNAG = 20;
+
private static final int ANIMATION_STATE_STARTING = 1;
private static final int ANIMATION_STATE_RUNNING = 2;
private static final int ANIMATION_STATE_DONE = 3;
@@ -141,6 +158,13 @@ public class DragLayer extends FrameLayout implements DragController {
final int srcColor = context.getResources().getColor(R.color.delete_color_filter);
mTrashPaint.setColorFilter(new PorterDuffColorFilter(srcColor, PorterDuff.Mode.SRC_ATOP));
+
+ // Make estimated paint area in gray
+ int snagColor = context.getResources().getColor(R.color.snag_callout_color);
+ mEstimatedPaint.setColor(snagColor);
+ mEstimatedPaint.setStrokeWidth(3);
+ mEstimatedPaint.setAntiAlias(true);
+
}
public void startDrag(View v, DragSource source, Object dragInfo, int dragAction) {
@@ -177,6 +201,9 @@ public class DragLayer extends FrameLayout implements DragController {
int width = viewBitmap.getWidth();
int height = viewBitmap.getHeight();
+ mTriggerWidth = width * 2 / 3;
+ mTriggerHeight = height * 2 / 3;
+
Matrix scale = new Matrix();
float scaleFactor = v.getWidth();
scaleFactor = (scaleFactor + DRAG_SCALE) /scaleFactor;
@@ -252,6 +279,13 @@ public class DragLayer extends FrameLayout implements DragController {
break;
}
} else {
+ // Only draw estimate drop "snag" when requested
+ if (DRAW_TARGET_SNAG && mDrawEstimated) {
+ canvas.drawLine(mDragCenter[0], mDragCenter[1], mEstimatedCenter[0], mEstimatedCenter[1], mEstimatedPaint);
+ canvas.drawCircle(mEstimatedCenter[0], mEstimatedCenter[1], 8, mEstimatedPaint);
+ }
+
+ // Draw actual icon being dragged
canvas.drawBitmap(mDragBitmap,
mScrollX + mLastMotionX - mTouchOffsetX - mBitmapOffsetX,
mScrollY + mLastMotionY - mTouchOffsetY - mBitmapOffsetY, mDragPaint);
@@ -355,8 +389,16 @@ public class DragLayer extends FrameLayout implements DragController {
left = (int) (scrollX + x - touchX - offsetX);
top = (int) (scrollY + y - touchY - offsetY);
+ // Invalidate current icon position
rect.union(left - 1, top - 1, left + width + 1, top + height + 1);
- invalidate(rect);
+
+ mDragCenter[0] = rect.centerX();
+ mDragCenter[1] = rect.centerY();
+
+ // Invalidate any old estimated location
+ if (DRAW_TARGET_SNAG && mDrawEstimated) {
+ rect.union(mEstimatedRect);
+ }
final int[] coordinates = mDropCoordinates;
DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates);
@@ -378,6 +420,33 @@ public class DragLayer extends FrameLayout implements DragController {
(int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
}
}
+
+ // Render estimated drop "snag" only outside of width
+ mDrawEstimated = false;
+ if (DRAW_TARGET_SNAG && dropTarget != null) {
+ Rect foundEstimate = dropTarget.estimateDropLocation(mDragSource,
+ (int) (scrollX + mLastMotionX), (int) (scrollY + mLastMotionY),
+ (int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo, mEstimatedRect);
+
+ if (foundEstimate != null) {
+ mEstimatedCenter[0] = foundEstimate.centerX();
+ mEstimatedCenter[1] = foundEstimate.centerY();
+
+ int deltaX = (int) Math.abs(mEstimatedCenter[0] - mDragCenter[0]);
+ int deltaY = (int) Math.abs(mEstimatedCenter[1] - mDragCenter[1]);
+
+ if (deltaX > mTriggerWidth || deltaY > mTriggerHeight) {
+ mDrawEstimated = true;
+ }
+ }
+ }
+
+ // Include new estimated area in invalidated rectangle
+ if (DRAW_TARGET_SNAG && mDrawEstimated) {
+ rect.union(mEstimatedRect);
+ }
+ invalidate(rect);
+
mLastDropTarget = dropTarget;
boolean inDragRegion = false;
@@ -478,9 +547,15 @@ public class DragLayer extends FrameLayout implements DragController {
}
if (target == null) {
if (child instanceof DropTarget) {
- dropCoordinates[0] = x;
- dropCoordinates[1] = y;
- return (DropTarget) child;
+ // Only consider this child if they will accept
+ DropTarget childTarget = (DropTarget) child;
+ if (childTarget.acceptDrop(mDragSource, x, y, 0, 0, mDragInfo)) {
+ dropCoordinates[0] = x;
+ dropCoordinates[1] = y;
+ return (DropTarget) child;
+ } else {
+ return null;
+ }
}
} else {
return target;
@@ -531,6 +606,7 @@ public class DragLayer extends FrameLayout implements DragController {
public void run() {
if (mDragScroller != null) {
+ mDrawEstimated = false;
if (mDirection == SCROLL_LEFT) {
mDragScroller.scrollLeft();
} else {
diff --git a/src/com/android/launcher/DropTarget.java b/src/com/android/launcher/DropTarget.java
index 812908906..4835323d8 100644
--- a/src/com/android/launcher/DropTarget.java
+++ b/src/com/android/launcher/DropTarget.java
@@ -16,6 +16,8 @@
package com.android.launcher;
+import android.graphics.Rect;
+
/**
* Interface defining an object that can receive a drag.
*
@@ -42,18 +44,38 @@ public interface DropTarget {
void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);
/**
- * Indicates whether a drop action can occur at the specified location. The method
- * {@link #onDrop(DragSource, int, int, int, int, Object)} will be invoked on this
- * drop target only if this method returns true.
- *
+ * Check if a drop action can occur at, or near, the requested location.
+ * This may be called repeatedly during a drag, so any calls should return
+ * quickly.
+ *
* @param source DragSource where the drag started
* @param x X coordinate of the drop location
* @param y Y coordinate of the drop location
- * @param xOffset Horizontal offset with the object being dragged where the original touch happened
- * @param yOffset Vertical offset with the object being dragged where the original touch happened
+ * @param xOffset Horizontal offset with the object being dragged where the
+ * original touch happened
+ * @param yOffset Vertical offset with the object being dragged where the
+ * original touch happened
* @param dragInfo Data associated with the object being dragged
- *
- * return True if the drop is accepted, false otherwise.
+ * @return True if the drop will be accepted, false otherwise.
*/
boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);
+
+ /**
+ * Estimate the surface area where this object would land if dropped at the
+ * given location.
+ *
+ * @param source DragSource where the drag started
+ * @param x X coordinate of the drop location
+ * @param y Y coordinate of the drop location
+ * @param xOffset Horizontal offset with the object being dragged where the
+ * original touch happened
+ * @param yOffset Vertical offset with the object being dragged where the
+ * original touch happened
+ * @param dragInfo Data associated with the object being dragged
+ * @param recycle {@link Rect} object to be possibly recycled.
+ * @return Estimated area that would be occupied if object was dropped at
+ * the given location. Should return null if no estimate is found,
+ * or if this target doesn't provide estimations.
+ */
+ Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo, Rect recycle);
}
diff --git a/src/com/android/launcher/FolderIcon.java b/src/com/android/launcher/FolderIcon.java
index 667f92ee1..a56101d51 100644
--- a/src/com/android/launcher/FolderIcon.java
+++ b/src/com/android/launcher/FolderIcon.java
@@ -18,6 +18,7 @@ package com.android.launcher;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -69,6 +70,10 @@ public class FolderIcon extends BubbleTextView implements DropTarget {
&& item.container != mInfo.id;
}
+ public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo, Rect recycle) {
+ return null;
+ }
+
public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
final ApplicationInfo item = (ApplicationInfo) dragInfo;
// TODO: update open folder that is looking at this data
diff --git a/src/com/android/launcher/UserFolder.java b/src/com/android/launcher/UserFolder.java
index 1044e969f..6cdfed950 100644
--- a/src/com/android/launcher/UserFolder.java
+++ b/src/com/android/launcher/UserFolder.java
@@ -1,6 +1,7 @@
package com.android.launcher;
import android.content.Context;
+import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@@ -33,6 +34,10 @@ public class UserFolder extends Folder implements DropTarget {
return (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) && item.container != mInfo.id;
}
+
+ public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo, Rect recycle) {
+ return null;
+ }
public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
final ApplicationInfo item = (ApplicationInfo) dragInfo;
diff --git a/src/com/android/launcher/Workspace.java b/src/com/android/launcher/Workspace.java
index 359767aea..12bdf7d0a 100644
--- a/src/com/android/launcher/Workspace.java
+++ b/src/com/android/launcher/Workspace.java
@@ -48,7 +48,7 @@ import java.util.ArrayList;
*/
public class Workspace extends ViewGroup implements DropTarget, DragSource, DragScroller {
private static final int INVALID_SCREEN = -1;
-
+
/**
* The velocity at which a fling gesture will cause us to snap to the next screen
*/
@@ -75,6 +75,11 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
* CellInfo for the cell that is currently being dragged
*/
private CellLayout.CellInfo mDragInfo;
+
+ /**
+ * Target drop area calculated during last acceptDrop call.
+ */
+ private int[] mTargetCell = null;
private float mLastMotionX;
private float mLastMotionY;
@@ -88,8 +93,14 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
private Launcher mLauncher;
private DragController mDragger;
-
+
+ /**
+ * Cache of vacant cells, used during drag events and invalidated as needed.
+ */
+ private CellLayout.CellInfo mVacantCache = null;
+
private int[] mTempCell = new int[2];
+ private int[] mTempEstimate = new int[2];
private boolean mAllowLongPress;
private boolean mLocked;
@@ -363,7 +374,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
CellLayout.CellInfo findAllVacantCells(boolean[] occupied) {
CellLayout group = (CellLayout) getChildAt(mCurrentScreen);
if (group != null) {
- return group.findAllVacantCells(occupied);
+ return group.findAllVacantCells(occupied, null);
}
return null;
}
@@ -890,7 +901,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
}
public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
- final CellLayout cellLayout = (CellLayout) getChildAt(mCurrentScreen);
+ final CellLayout cellLayout = getCurrentDropLayout();
if (source != this) {
onDropExternal(x - xOffset, y - yOffset, dragInfo, cellLayout);
} else {
@@ -902,7 +913,9 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
originalCellLayout.removeView(cell);
cellLayout.addView(cell);
}
- cellLayout.onDropChild(cell, x - xOffset, y - yOffset);
+ mTargetCell = estimateDropCell(source, x - xOffset, y - yOffset,
+ mDragInfo.spanX, mDragInfo.spanY, cell, cellLayout, mTargetCell);
+ cellLayout.onDropChild(cell, mTargetCell);
final ItemInfo info = (ItemInfo)cell.getTag();
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
@@ -914,6 +927,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
Object dragInfo) {
+ mVacantCache = null;
}
public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
@@ -922,6 +936,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
Object dragInfo) {
+ mVacantCache = null;
}
private void onDropExternal(int x, int y, Object dragInfo, CellLayout cellLayout) {
@@ -955,7 +970,8 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
cellLayout.addView(view, insertAtFirst ? 0 : -1);
view.setOnLongClickListener(mLongClickListener);
- cellLayout.onDropChild(view, x, y);
+ mTargetCell = estimateDropCell(null, x, y, 1, 1, view, cellLayout, mTargetCell);
+ cellLayout.onDropChild(view, mTargetCell);
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
final LauncherModel model = Launcher.getModel();
@@ -963,18 +979,73 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
LauncherModel.addOrMoveItemInDatabase(mLauncher, info,
LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY);
}
+
+ /**
+ * Return the current {@link CellLayout}, correctly picking the destination
+ * screen while a scroll is in progress.
+ */
+ private CellLayout getCurrentDropLayout() {
+ int index = mScroller.isFinished() ? mCurrentScreen : mNextScreen;
+ return (CellLayout) getChildAt(index);
+ }
- public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
- Object dragInfo) {
-
+ /**
+ * {@inheritDoc}
+ */
+ public boolean acceptDrop(DragSource source, int x, int y,
+ int xOffset, int yOffset, Object dragInfo) {
+ // Workspaces accept everything
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Rect estimateDropLocation(DragSource source, int x, int y,
+ int xOffset, int yOffset, Object dragInfo, Rect recycle) {
+ final CellLayout layout = getCurrentDropLayout();
+
final CellLayout.CellInfo cellInfo = mDragInfo;
- int cellHSpan = cellInfo == null ? 1 : cellInfo.spanX;
- int cellVSpan = cellInfo == null ? 1 : cellInfo.spanY;
-
- return ((CellLayout) getChildAt(mCurrentScreen)).acceptChildDrop(x - xOffset, y - yOffset,
- cellHSpan, cellVSpan, cellInfo == null ? null : cellInfo.cell);
+ final int spanX = cellInfo == null ? 1 : cellInfo.spanX;
+ final int spanY = cellInfo == null ? 1 : cellInfo.spanY;
+ final View ignoreView = cellInfo == null ? null : cellInfo.cell;
+
+ final Rect location = recycle != null ? recycle : new Rect();
+
+ // Find drop cell and convert into rectangle
+ int[] dropCell = estimateDropCell(source, x - xOffset, y - yOffset,
+ spanX, spanY, ignoreView, layout, mTempCell);
+
+ if (dropCell == null) {
+ return null;
+ }
+
+ layout.cellToPoint(dropCell[0], dropCell[1], mTempEstimate);
+ location.left = mTempEstimate[0];
+ location.top = mTempEstimate[1];
+
+ layout.cellToPoint(dropCell[0] + spanX, dropCell[1] + spanY, mTempEstimate);
+ location.right = mTempEstimate[0];
+ location.bottom = mTempEstimate[1];
+
+ return location;
}
+ /**
+ * Calculate the nearest cell where the given object would be dropped.
+ */
+ private int[] estimateDropCell(DragSource source, int pixelX, int pixelY,
+ int spanX, int spanY, View ignoreView, CellLayout layout, int[] recycle) {
+ // Create vacant cell cache if none exists
+ if (mVacantCache == null) {
+ mVacantCache = layout.findAllVacantCells(null, ignoreView);
+ }
+
+ // Find the best target drop location
+ return layout.findNearestVacantArea(pixelX, pixelY,
+ spanX, spanY, mVacantCache, recycle);
+ }
+
void setLauncher(Launcher launcher) {
mLauncher = launcher;
}
@@ -1002,12 +1073,14 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
}
public void scrollLeft() {
+ mVacantCache = null;
if (mNextScreen == INVALID_SCREEN && mCurrentScreen > 0 && mScroller.isFinished()) {
snapToScreen(mCurrentScreen - 1);
}
}
public void scrollRight() {
+ mVacantCache = null;
if (mNextScreen == INVALID_SCREEN && mCurrentScreen < getChildCount() -1 &&
mScroller.isFinished()) {
snapToScreen(mCurrentScreen + 1);