Fix bug with drag visualization and UserFolders.

When dragging an app shortcut, it was possible that we'd show a red rectangle
around a cell occupied by a UserFolder. This shouldn't be possible -- as soon
as that cell becomes the target drop cell, the folder should start handling
the drag and drop events.

Change-Id: I1b7a8b1aa9aeb7e2f1bd51ce8d947c06455e988f
This commit is contained in:
Patrick Dubroy 2010-07-13 17:50:32 -07:00
parent 6569f2c80e
commit 440c360bc3
7 changed files with 107 additions and 3 deletions

View File

@ -677,6 +677,20 @@ public class CellLayout extends ViewGroup {
return true;
}
public View getChildAt(int x, int y) {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
if ((lp.cellX <= x) && (x < lp.cellX + lp.cellHSpan) &&
(lp.cellY <= y) && (y < lp.cellY + lp.cellHSpan)) {
return child;
}
}
return null;
}
/**
* Estimate where the top left cell of the dragged item will land if it is dropped.
*
@ -690,7 +704,7 @@ public class CellLayout extends ViewGroup {
final int countX = getCountX();
final int countY = getCountY();
pointToCellRounded(originX, originY, result);
pointToCellRounded(originX + (mCellWidth / 2), originY + (mCellHeight / 2), result);
// If the item isn't fully on this screen, snap to the edges
int rightOverhang = result[0] + spanX - countX;

View File

@ -254,4 +254,10 @@ public class DeleteZone extends ImageView implements DropTarget, DragController.
return false;
}
}
@Override
public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
return null;
}
}

View File

@ -394,6 +394,12 @@ public class DragController {
// Drop on someone?
final int[] coordinates = mCoordinatesTemp;
DropTarget dropTarget = findDropTarget(screenX, screenY, coordinates);
DropTarget delegate = dropTarget.getDropTargetDelegate(
mDragSource, coordinates[0], coordinates[1],
(int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
if (delegate != null) {
dropTarget = delegate;
}
if (dropTarget != null) {
if (mLastDropTarget == dropTarget) {
dropTarget.onDragOver(mDragSource, coordinates[0], coordinates[1],
@ -482,13 +488,25 @@ public class DragController {
final ArrayList<DropTarget> dropTargets = mDropTargets;
final int count = dropTargets.size();
for (int i=count-1; i>=0; i--) {
final DropTarget target = dropTargets.get(i);
DropTarget target = dropTargets.get(i);
target.getHitRect(r);
// Convert the hit rect to screen coordinates
target.getLocationOnScreen(dropCoordinates);
r.offset(dropCoordinates[0] - target.getLeft(), dropCoordinates[1] - target.getTop());
if (r.contains(x, y)) {
DropTarget delegate = target.getDropTargetDelegate(mDragSource,
x, y, (int)mTouchOffsetX, (int)mTouchOffsetY, mDragView, mDragInfo);
if (delegate != null) {
target = delegate;
target.getLocationOnScreen(dropCoordinates);
}
// Make dropCoordinates relative to the DropTarget
dropCoordinates[0] = x - dropCoordinates[0];
dropCoordinates[1] = y - dropCoordinates[1];
return target;
}
}

View File

@ -50,6 +50,26 @@ public interface DropTarget {
void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo);
/**
* Allows a DropTarget to delegate drag and drop events to another object.
*
* Most subclasses will should just return null from this method.
*
* @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 dragView The DragView that's being dragged around on screen.
* @param dragInfo Data associated with the object being dragged
*
* @return The DropTarget to delegate to, or null to not delegate to another object.
*/
DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo);
/**
* 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

View File

@ -102,4 +102,10 @@ public class FolderIcon extends BubbleTextView implements DropTarget {
DragView dragView, Object dragInfo) {
setCompoundDrawablesWithIntrinsicBounds(null, mCloseIcon, null, null);
}
@Override
public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
return null;
}
}

View File

@ -89,4 +89,10 @@ public class UserFolder extends Folder implements DropTarget {
super.onOpen();
requestFocus();
}
@Override
public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
return null;
}
}

View File

@ -1219,11 +1219,45 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
clearVacantCache();
}
public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
// 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)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 = x - xOffset;
dragPointY = y - yOffset;
} else {
// Otherwise, use the exact drag coordinates
dragPointX = x;
dragPointY = y;
}
// 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(source, x, y, xOffset, yOffset, dragView, dragInfo)) {
return target;
}
}
return null;
}
public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
ItemInfo item = (ItemInfo)dragInfo;
CellLayout currentLayout = getCurrentDropLayout();
if (dragInfo instanceof LauncherAppWidgetInfo) {