Fixed dragging over mini-screens
- during dragging, finding the mini-screen closest to the touch point
Change-Id: I4d967803b85de8af3208511c60c1f3bf5691718f
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 6802966..97c54c4 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -110,10 +110,14 @@
private IconCache mIconCache;
private DragController mDragController;
+ // These are temporary variables to prevent having to allocate a new object just to
+ // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
private int[] mTempCell = new int[2];
private int[] mTempEstimate = new int[2];
private float[] mTempOriginXY = new float[2];
private float[] mTempDragCoordinates = new float[2];
+ private float[] mTempTouchCoordinates = new float[2];
+ private float[] mTempCellLayoutCenterCoordinates = new float[2];
private float[] mTempDragBottomRightCoordinates = new float[2];
private Matrix mTempInverseMatrix = new Matrix();
@@ -855,7 +859,7 @@
int originX = x - xOffset;
int originY = y - yOffset;
if (mIsSmall || mIsInUnshrinkAnimation) {
- cellLayout = findMatchingPageForDragOver(dragView, originX, originY);
+ cellLayout = findMatchingPageForDragOver(dragView, originX, originY, xOffset, yOffset);
if (cellLayout == null) {
// cancel the drag if we're not over a mini-screen at time of drop
// TODO: maybe add a nice fade here?
@@ -864,7 +868,7 @@
// get originX and originY in the local coordinate system of the screen
mTempOriginXY[0] = originX;
mTempOriginXY[1] = originY;
- mapPointGlobalToLocal(cellLayout, mTempOriginXY);
+ mapPointFromSelfToChild(cellLayout, mTempOriginXY);
originX = (int)mTempOriginXY[0];
originY = (int)mTempOriginXY[1];
} else {
@@ -954,73 +958,146 @@
return null;
}
- private void mapPointGlobalToLocal(View v, float[] xy) {
- xy[0] = xy[0] + mScrollX - v.getLeft();
- xy[1] = xy[1] + mScrollY - v.getTop();
- v.getMatrix().invert(mTempInverseMatrix);
- mTempInverseMatrix.mapPoints(xy);
+ /*
+ *
+ * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's
+ * coordinate space. The argument xy is modified with the return result.
+ *
+ */
+ void mapPointFromSelfToChild(View v, float[] xy) {
+ mapPointFromSelfToChild(v, xy, null);
+ }
+
+ /*
+ *
+ * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's
+ * coordinate space. The argument xy is modified with the return result.
+ *
+ * if cachedInverseMatrix is not null, this method will just use that matrix instead of
+ * computing it itself; we use this to avoid redudant matrix inversions in
+ * findMatchingPageForDragOver
+ *
+ */
+ void mapPointFromSelfToChild(View v, float[] xy, Matrix cachedInverseMatrix) {
+ if (cachedInverseMatrix == null) {
+ v.getMatrix().invert(mTempInverseMatrix);
+ cachedInverseMatrix = mTempInverseMatrix;
+ }
+ xy[0] = xy[0] + mScrollX - v.getLeft();
+ xy[1] = xy[1] + mScrollY - v.getTop();
+ cachedInverseMatrix.mapPoints(xy);
+ }
+
+ /*
+ *
+ * Convert the 2D coordinate xy from this CellLayout's coordinate space to
+ * the parent View's coordinate space. The argument xy is modified with the return result.
+ *
+ */
+ void mapPointFromChildToSelf(View v, float[] xy) {
+ v.getMatrix().mapPoints(xy);
+ xy[0] -= (mScrollX - v.getLeft());
+ xy[1] -= (mScrollY - v.getTop());
+ }
+
+ static private float squaredDistance(float[] point1, float[] point2) {
+ float distanceX = point1[0] - point2[0];
+ float distanceY = point2[1] - point2[1];
+ return distanceX * distanceX + distanceY * distanceY;
}
- // xy = upper left corner of item being dragged
- // bottomRightXy = lower right corner of item being dragged
- // This method will see which mini-screen is most overlapped by the item being dragged, and
- // return it. It will also transform the parameters xy and bottomRightXy into the local
- // coordinate space of the returned screen
- private CellLayout findMatchingPageForDragOver(DragView dragView, int originX, int originY) {
- float x = originX + dragView.getScaledDragRegionXOffset();
- float y = originY + dragView.getScaledDragRegionYOffset();
- float right = x + dragView.getScaledDragRegionWidth();
- float bottom = y + dragView.getScaledDragRegionHeight();
+ /*
+ *
+ * Returns true if the passed CellLayout cl overlaps with dragView
+ *
+ */
+ boolean overlaps(CellLayout cl, DragView dragView,
+ int dragViewX, int dragViewY, Matrix cachedInverseMatrix) {
+ // Transform the coordinates of the item being dragged to the CellLayout's coordinates
+ final float[] draggedItemTopLeft = mTempDragCoordinates;
+ draggedItemTopLeft[0] = dragViewX + dragView.getScaledDragRegionXOffset();
+ draggedItemTopLeft[1] = dragViewY + dragView.getScaledDragRegionYOffset();
+ final float[] draggedItemBottomRight = mTempDragBottomRightCoordinates;
+ draggedItemBottomRight[0] = draggedItemTopLeft[0] + dragView.getScaledDragRegionWidth();
+ draggedItemBottomRight[1] = draggedItemTopLeft[1] + dragView.getScaledDragRegionHeight();
- // We loop through all the screens (ie CellLayouts) and see which one overlaps the most
- // with the item being dragged.
+ // Transform the dragged item's top left coordinates
+ // to the CellLayout's local coordinates
+ mapPointFromSelfToChild(cl, draggedItemTopLeft, cachedInverseMatrix);
+ float overlapRegionLeft = Math.max(0f, draggedItemTopLeft[0]);
+ float overlapRegionTop = Math.max(0f, draggedItemTopLeft[1]);
+
+ if (overlapRegionLeft <= cl.getWidth() && overlapRegionTop >= 0) {
+ // Transform the dragged item's bottom right coordinates
+ // to the CellLayout's local coordinates
+ mapPointFromSelfToChild(cl, draggedItemBottomRight, cachedInverseMatrix);
+ float overlapRegionRight = Math.min(cl.getWidth(), draggedItemBottomRight[0]);
+ float overlapRegionBottom = Math.min(cl.getHeight(), draggedItemBottomRight[1]);
+
+ if (overlapRegionRight >= 0 && overlapRegionBottom <= cl.getHeight()) {
+ float overlap = (overlapRegionRight - overlapRegionLeft) *
+ (overlapRegionBottom - overlapRegionTop);
+ if (overlap > 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /*
+ *
+ * This method returns the CellLayout that is currently being dragged to. In order to drag
+ * to a CellLayout, either the touch point must be directly over the CellLayout, or as a second
+ * strategy, we see if the dragView is overlapping any CellLayout and choose the closest one
+ *
+ * Return null if no CellLayout is currently being dragged over
+ *
+ */
+ private CellLayout findMatchingPageForDragOver(
+ DragView dragView, int originX, int originY, int offsetX, int offsetY) {
+ // We loop through all the screens (ie CellLayouts) and see which ones overlap
+ // with the item being dragged and then choose the one that's closest to the touch point
final int screenCount = getChildCount();
CellLayout bestMatchingScreen = null;
float smallestDistSoFar = Float.MAX_VALUE;
- final float[] xy = mTempDragCoordinates;
- final float[] bottomRightXy = mTempDragBottomRightCoordinates;
+
for (int i = 0; i < screenCount; i++) {
CellLayout cl = (CellLayout)getChildAt(i);
- // Transform the coordinates of the item being dragged to the CellLayout's coordinates
- float left = cl.getLeft();
- float top = cl.getTop();
- xy[0] = x + mScrollX - left;
- xy[1] = y + mScrollY - top;
- bottomRightXy[0] = right + mScrollX - left;
- bottomRightXy[1] = bottom + mScrollY - top;
+ final float[] touchXy = mTempTouchCoordinates;
+ touchXy[0] = originX + offsetX;
+ touchXy[1] = originY + offsetY;
+ // Transform the touch coordinates to the CellLayout's local coordinates
+ // If the touch point is within the bounds of the cell layout, we can return immediately
cl.getMatrix().invert(mTempInverseMatrix);
- mTempInverseMatrix.mapPoints(xy);
- mTempInverseMatrix.mapPoints(bottomRightXy);
+ mapPointFromSelfToChild(cl, touchXy, mTempInverseMatrix);
- float dragRegionX = xy[0];
- float dragRegionY = xy[1];
- float dragRegionRight = bottomRightXy[0];
- float dragRegionBottom = bottomRightXy[1];
- float dragRegionCenterX = (dragRegionX + dragRegionRight) / 2.0f;
- float dragRegionCenterY = (dragRegionY + dragRegionBottom) / 2.0f;
+ if (touchXy[0] >= 0 && touchXy[0] <= cl.getWidth() &&
+ touchXy[1] >= 0 && touchXy[1] <= cl.getHeight()) {
+ return cl;
+ }
- // Find the overlapping region
- float overlapLeft = Math.max(0f, dragRegionX);
- float overlapTop = Math.max(0f, dragRegionY);
- float overlapBottom = Math.min(cl.getHeight(), dragRegionBottom);
- float overlapRight = Math.min(cl.getWidth(), dragRegionRight);
- if (overlapRight >= 0 && overlapLeft <= cl.getWidth() &&
- (overlapTop >= 0 && overlapBottom <= cl.getHeight())) {
- // Calculate the distance between the two centers
- float distX = dragRegionCenterX - cl.getWidth()/2;
- float distY = dragRegionCenterY - cl.getHeight()/2;
- float dist = distX * distX + distY * distY;
+ if (overlaps(cl, dragView, originX, originY, mTempInverseMatrix)) {
+ // Get the center of the cell layout in screen coordinates
+ final float[] cellLayoutCenter = mTempCellLayoutCenterCoordinates;
+ cellLayoutCenter[0] = cl.getWidth()/2;
+ cellLayoutCenter[1] = cl.getHeight()/2;
+ mapPointFromChildToSelf(cl, cellLayoutCenter);
- float overlap = (overlapRight - overlapLeft) * (overlapBottom - overlapTop);
+ touchXy[0] = originX + offsetX;
+ touchXy[1] = originY + offsetY;
- // Calculate the closest overlapping region
- if (overlap > 0 && dist < smallestDistSoFar) {
+ // Calculate the distance between the center of the CellLayout
+ // and the touch point
+ float dist = squaredDistance(touchXy, cellLayoutCenter);
+
+ if (dist < smallestDistSoFar) {
smallestDistSoFar = dist;
bestMatchingScreen = cl;
}
- }
+ }
}
if (bestMatchingScreen != mDragTargetLayout) {
@@ -1039,7 +1116,8 @@
int originX = x - xOffset;
int originY = y - yOffset;
if (mIsSmall || mIsInUnshrinkAnimation) {
- currentLayout = findMatchingPageForDragOver(dragView, originX, originY);
+ currentLayout = findMatchingPageForDragOver(
+ dragView, originX, originY, xOffset, yOffset);
if (currentLayout == null) {
return;
@@ -1049,7 +1127,7 @@
// get originX and originY in the local coordinate system of the screen
mTempOriginXY[0] = originX;
mTempOriginXY[1] = originY;
- mapPointGlobalToLocal(currentLayout, mTempOriginXY);
+ mapPointFromSelfToChild(currentLayout, mTempOriginXY);
originX = (int)mTempOriginXY[0];
originY = (int)mTempOriginXY[1];
} else {
@@ -1069,7 +1147,7 @@
}
}
- if (source != this) {
+ if (source instanceof AllAppsPagedView) {
// This is a hack to fix the point used to determine which cell an icon from the all
// apps screen is over
if (item != null && item.spanX == 1 && currentLayout != null) {
@@ -1233,7 +1311,8 @@
int xOffset, int yOffset, DragView dragView, Object dragInfo) {
CellLayout layout;
if (mIsSmall || mIsInUnshrinkAnimation) {
- layout = findMatchingPageForDragOver(dragView, x - xOffset, y - yOffset);
+ layout = findMatchingPageForDragOver(
+ dragView, x - xOffset, y - yOffset, xOffset, yOffset);
if (layout == null) {
// cancel the drag if we're not over a mini-screen at time of drop
return false;