From 6569f2c80e179c2f8ed73dae6b01d971ec20f005 Mon Sep 17 00:00:00 2001 From: Patrick Dubroy Date: Mon, 12 Jul 2010 14:25:18 -0700 Subject: When dragging items on the home screen, visualize where they will drop. Draw a rectangle around the area where an item will land if it is dropped. If the area is vacant, the rectangle is green; otherwise, it is red. Change-Id: I859b52514566fa55f8c7a04493b8088d12baa476 --- src/com/android/launcher2/CellLayout.java | 196 +++++++++++++++++---- src/com/android/launcher2/Launcher.java | 2 +- .../android/launcher2/LauncherAppWidgetInfo.java | 28 ++- src/com/android/launcher2/WidgetChooser.java | 7 +- src/com/android/launcher2/WidgetListAdapter.java | 2 + src/com/android/launcher2/Workspace.java | 72 ++++++-- 6 files changed, 249 insertions(+), 58 deletions(-) (limited to 'src') diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java index 1d45565a0..9cc370f45 100644 --- a/src/com/android/launcher2/CellLayout.java +++ b/src/com/android/launcher2/CellLayout.java @@ -16,7 +16,7 @@ package com.android.launcher2; -import java.util.ArrayList; +import com.android.launcher.R; import android.app.WallpaperManager; import android.content.Context; @@ -25,6 +25,7 @@ import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.ContextMenu; import android.view.MotionEvent; @@ -34,7 +35,8 @@ import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.LayoutAnimationController; -import com.android.launcher.R; +import java.util.ArrayList; +import java.util.Arrays; public class CellLayout extends ViewGroup { static final String TAG = "CellLayout"; @@ -63,10 +65,25 @@ public class CellLayout extends ViewGroup { private final Rect mRect = new Rect(); private final CellInfo mCellInfo = new CellInfo(); - int[] mCellXY = new int[2]; + // This is a temporary variable to prevent having to allocate a new object just to + // return an (x, y) value from helper functions. Do NOT use it to maintain other state. + private final int[] mTmpCellXY = new int[2]; + boolean[][] mOccupied; - private RectF mDragRect = new RectF(); + private final RectF mDragRect = new RectF(); + + // When dragging, used to indicate a vacant drop location + private Drawable mVacantDrawable; + + // When dragging, used to indicate an occupied drop location + private Drawable mOccupiedDrawable; + + // Updated to point to mVacantDrawable or mOccupiedDrawable, as appropriate + private Drawable mDragRectDrawable; + + // When a drag operation is in progress, holds the nearest cell to the touch point + private final int[] mDragCell = new int[2]; private boolean mDirtyTag; private boolean mLastDownOnOccupiedCell = false; @@ -83,6 +100,13 @@ public class CellLayout extends ViewGroup { public CellLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); + + // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show + // the user where a dragged item will land when dropped. + setWillNotDraw(false); + mVacantDrawable = getResources().getDrawable(R.drawable.rounded_rect_green); + mOccupiedDrawable = getResources().getDrawable(R.drawable.rounded_rect_red); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0); mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10); @@ -112,6 +136,18 @@ public class CellLayout extends ViewGroup { super.dispatchDraw(canvas); } + @Override + protected void onDraw(Canvas canvas) { + if (!mDragRect.isEmpty()) { + mDragRectDrawable.setBounds( + (int)mDragRect.left, + (int)mDragRect.top, + (int)mDragRect.right, + (int)mDragRect.bottom); + mDragRectDrawable.draw(canvas); + } + } + @Override public void cancelLongPress() { super.cancelLongPress(); @@ -199,7 +235,7 @@ public class CellLayout extends ViewGroup { mLastDownOnOccupiedCell = found; if (!found) { - int cellXY[] = mCellXY; + final int cellXY[] = mTmpCellXY; pointToCellExact(x, y, cellXY); final boolean portrait = mPortrait; @@ -207,7 +243,7 @@ public class CellLayout extends ViewGroup { final int yCount = portrait ? mLongAxisCells : mShortAxisCells; final boolean[][] occupied = mOccupied; - findOccupiedCells(xCount, yCount, occupied, null); + findOccupiedCells(xCount, yCount, occupied, null, true); cellInfo.cell = null; cellInfo.cellX = cellXY[0]; @@ -258,7 +294,7 @@ public class CellLayout extends ViewGroup { final int yCount = portrait ? mLongAxisCells : mShortAxisCells; final boolean[][] occupied = mOccupied; - findOccupiedCells(xCount, yCount, occupied, null); + findOccupiedCells(xCount, yCount, occupied, null, true); findIntersectingVacantCells(info, info.cellX, info.cellY, xCount, yCount, occupied); @@ -340,6 +376,9 @@ public class CellLayout extends ViewGroup { cellInfo.vacantCells.add(cell); } + /** + * Check if the column 'x' is empty from rows 'top' to 'bottom', inclusive. + */ private static boolean isColumnEmpty(int x, int top, int bottom, boolean[][] occupied) { for (int y = top; y <= bottom; y++) { if (occupied[x][y]) { @@ -349,6 +388,9 @@ public class CellLayout extends ViewGroup { return true; } + /** + * Check if the row 'y' is empty from columns 'left' to 'right', inclusive. + */ private static boolean isRowEmpty(int y, int left, int right, boolean[][] occupied) { for (int x = left; x <= right; x++) { if (occupied[x][y]) { @@ -372,7 +414,7 @@ public class CellLayout extends ViewGroup { } } } else { - findOccupiedCells(xCount, yCount, occupied, ignoreView); + findOccupiedCells(xCount, yCount, occupied, ignoreView, true); } CellInfo cellInfo = new CellInfo(); @@ -600,7 +642,7 @@ public class CellLayout extends ViewGroup { if (lp.dropped) { lp.dropped = false; - final int[] cellXY = mCellXY; + final int[] cellXY = mTmpCellXY; getLocationOnScreen(cellXY); mWallpaperManager.sendWallpaperCommand(getWindowToken(), "android.home.drop", cellXY[0] + childLeft + lp.width / 2, @@ -626,6 +668,79 @@ public class CellLayout extends ViewGroup { super.setChildrenDrawnWithCacheEnabled(enabled); } + private boolean isVacant(int originX, int originY, int spanX, int spanY) { + for (int i = 0; i < spanY; i++) { + if (!isRowEmpty(originY + i, originX, originX + spanX - 1, mOccupied)) { + return false; + } + } + return true; + } + + /** + * Estimate where the top left cell of the dragged item will land if it is dropped. + * + * @param originX The X value of the top left corner of the item + * @param originY The Y value of the top left corner of the item + * @param spanX The number of horizontal cells that the item spans + * @param spanY The number of vertical cells that the item spans + * @param result The estimated drop cell X and Y. + */ + void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) { + final int countX = getCountX(); + final int countY = getCountY(); + + pointToCellRounded(originX, originY, result); + + // If the item isn't fully on this screen, snap to the edges + int rightOverhang = result[0] + spanX - countX; + if (rightOverhang > 0) { + result[0] -= rightOverhang; // Snap to right + } + result[0] = Math.max(0, result[0]); // Snap to left + int bottomOverhang = result[1] + spanY - countY; + if (bottomOverhang > 0) { + result[1] -= bottomOverhang; // Snap to bottom + } + result[1] = Math.max(0, result[1]); // Snap to top + } + + void visualizeDropLocation(View view, int originX, int originY, int spanX, int spanY) { + final int[] originCell = mDragCell; + final int[] cellXY = mTmpCellXY; + estimateDropCell(originX, originY, spanX, spanY, cellXY); + + // Only recalculate the bounding rect when necessary + if (!Arrays.equals(cellXY, originCell)) { + originCell[0] = cellXY[0]; + originCell[1] = cellXY[1]; + + // Find the top left corner of the rect the object will occupy + final int[] topLeft = mTmpCellXY; + cellToPoint(originCell[0], originCell[1], topLeft); + final int left = topLeft[0]; + final int top = topLeft[1]; + + // Now find the bottom right + final int[] bottomRight = mTmpCellXY; + cellToPoint(originCell[0] + spanX - 1, originCell[1] + spanY - 1, bottomRight); + bottomRight[0] += mCellWidth; + bottomRight[1] += mCellHeight; + + final int countX = mPortrait ? mShortAxisCells : mLongAxisCells; + final int countY = mPortrait ? mLongAxisCells : mShortAxisCells; + // TODO: It's not necessary to do this every time, but it's not especially expensive + findOccupiedCells(countX, countY, mOccupied, view, false); + + boolean vacant = isVacant(originCell[0], originCell[1], spanX, spanY); + mDragRectDrawable = vacant ? mVacantDrawable : mOccupiedDrawable; + + // mDragRect will be rendered in onDraw() + mDragRect.set(left, top, bottomRight[0], bottomRight[1]); + invalidate(); + } + } + /** * Find a vacant area that will fit the given bounds nearest the requested * cell location. Uses Euclidean distance to score multiple vacant areas. @@ -644,7 +759,6 @@ public class CellLayout extends ViewGroup { // 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 @@ -662,7 +776,8 @@ public class CellLayout extends ViewGroup { continue; } - // Score is center distance from requested pixel + // Score is distance from requested pixel to the top left of each cell + final int[] cellXY = mTmpCellXY; cellToPoint(cell.cellX, cell.cellY, cellXY); double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2) @@ -682,6 +797,18 @@ public class CellLayout extends ViewGroup { } } + /** + * Called when a drag and drop operation has finished (successfully or not). + */ + void onDragComplete() { + // Invalidate the drag data + mDragCell[0] = -1; + mDragCell[1] = -1; + + mDragRect.setEmpty(); + invalidate(); + } + /** * Mark a child as having been dropped. * @@ -694,16 +821,15 @@ public class CellLayout extends ViewGroup { lp.dropped = true; mDragRect.setEmpty(); child.requestLayout(); - invalidate(); } + onDragComplete(); } void onDropAborted(View child) { if (child != null) { ((LayoutParams) child.getLayoutParams()).isDragging = false; - invalidate(); } - mDragRect.setEmpty(); + onDragComplete(); } /** @@ -717,21 +843,6 @@ public class CellLayout extends ViewGroup { mDragRect.setEmpty(); } - /** - * Drag a child over the specified position - * - * @param child The child that is being dropped - * @param cellX The child's new x cell location - * @param cellY The child's new y cell location - */ - void onDragOverChild(View child, int cellX, int cellY) { - int[] cellXY = mCellXY; - pointToCellRounded(cellX, cellY, cellXY); - LayoutParams lp = (LayoutParams) child.getLayoutParams(); - cellToRect(cellXY[0], cellXY[1], lp.cellHSpan, lp.cellVSpan, mDragRect); - invalidate(); - } - /** * Computes a bounding rectangle for a range of cells * @@ -739,9 +850,10 @@ public class CellLayout extends ViewGroup { * @param cellY Y coordinate of upper left corner expressed as a cell position * @param cellHSpan Width in cells * @param cellVSpan Height in cells - * @param dragRect Rectnagle into which to put the results + * @param resultRect Rect into which to put the results */ - public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, RectF dragRect) { + public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, RectF resultRect) { + final boolean portrait = mPortrait; final int cellWidth = mCellWidth; final int cellHeight = mCellHeight; final int widthGap = mWidthGap; @@ -756,7 +868,7 @@ public class CellLayout extends ViewGroup { int x = hStartPadding + cellX * (cellWidth + widthGap); int y = vStartPadding + cellY * (cellHeight + heightGap); - dragRect.set(x, y, x + width, y + height); + resultRect.set(x, y, x + width, y + height); } /** @@ -796,7 +908,7 @@ public class CellLayout extends ViewGroup { final int yCount = portrait ? mLongAxisCells : mShortAxisCells; final boolean[][] occupied = mOccupied; - findOccupiedCells(xCount, yCount, occupied, null); + findOccupiedCells(xCount, yCount, occupied, null, true); return findVacantCell(vacant, spanX, spanY, xCount, yCount, occupied); } @@ -825,13 +937,16 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { return false; } - boolean[] getOccupiedCells() { + /** + * Update the array of occupied cells (mOccupied), and return a flattened copy of the array. + */ + boolean[] getOccupiedCellsFlattened() { final boolean portrait = mPortrait; final int xCount = portrait ? mShortAxisCells : mLongAxisCells; final int yCount = portrait ? mLongAxisCells : mShortAxisCells; final boolean[][] occupied = mOccupied; - findOccupiedCells(xCount, yCount, occupied, null); + findOccupiedCells(xCount, yCount, occupied, null, true); final boolean[] flat = new boolean[xCount * yCount]; for (int y = 0; y < yCount; y++) { @@ -843,7 +958,14 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { return flat; } - private void findOccupiedCells(int xCount, int yCount, boolean[][] occupied, View ignoreView) { + /** + * Update the array of occupied cells. + * @param ignoreView If non-null, the space occupied by this View is treated as vacant + * @param ignoreFolders If true, a cell occupied by a Folder is treated as vacant + */ + private void findOccupiedCells( + int xCount, int yCount, boolean[][] occupied, View ignoreView, boolean ignoreFolders) { + for (int x = 0; x < xCount; x++) { for (int y = 0; y < yCount; y++) { occupied[x][y] = false; @@ -853,7 +975,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 || child.equals(ignoreView)) { + if ((ignoreFolders && child instanceof Folder) || child.equals(ignoreView)) { continue; } LayoutParams lp = (LayoutParams) child.getLayoutParams(); diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java index 03066c169..94556be55 100644 --- a/src/com/android/launcher2/Launcher.java +++ b/src/com/android/launcher2/Launcher.java @@ -1088,7 +1088,7 @@ public final class Launcher extends Activity outState.putInt(RUNTIME_STATE_PENDING_ADD_COUNT_X, layout.getCountX()); outState.putInt(RUNTIME_STATE_PENDING_ADD_COUNT_Y, layout.getCountY()); outState.putBooleanArray(RUNTIME_STATE_PENDING_ADD_OCCUPIED_CELLS, - layout.getOccupiedCells()); + layout.getOccupiedCellsFlattened()); } if (mFolderInfo != null && mWaitingForResult) { diff --git a/src/com/android/launcher2/LauncherAppWidgetInfo.java b/src/com/android/launcher2/LauncherAppWidgetInfo.java index 3c81bac8e..32c92aabd 100644 --- a/src/com/android/launcher2/LauncherAppWidgetInfo.java +++ b/src/com/android/launcher2/LauncherAppWidgetInfo.java @@ -21,23 +21,46 @@ import android.content.ComponentName; import android.content.ContentValues; /** - * Represents a widget, which just contains an identifier. + * Represents a widget (either instantiated or about to be) in the Launcher. */ class LauncherAppWidgetInfo extends ItemInfo { + /** + * Indicates that the widget hasn't been instantiated yet. + */ + static final int NO_ID = -1; + /** * Identifier for this widget when talking with * {@link android.appwidget.AppWidgetManager} for updates. */ - int appWidgetId; + int appWidgetId = NO_ID; + ComponentName providerName; + // TODO: Are these necessary here? + int minWidth = -1; + int minHeight = -1; + /** * View that holds this widget after it's been created. This view isn't created * until Launcher knows it's needed. */ AppWidgetHostView hostView = null; + /** + * Constructor for use with AppWidgets that haven't been instantiated yet. + */ + LauncherAppWidgetInfo(ComponentName providerName) { + itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET; + this.providerName = providerName; + + // Since the widget isn't instantiated yet, we don't know these values. Set them to -1 + // to indicate that they should be calculated based on the layout and minWidth/minHeight + spanX = -1; + spanY = -1; + } + LauncherAppWidgetInfo(int appWidgetId) { itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET; this.appWidgetId = appWidgetId; @@ -54,7 +77,6 @@ class LauncherAppWidgetInfo extends ItemInfo { return "AppWidget(id=" + Integer.toString(appWidgetId) + ")"; } - @Override void unbind() { super.unbind(); diff --git a/src/com/android/launcher2/WidgetChooser.java b/src/com/android/launcher2/WidgetChooser.java index 4718c6c22..101b671df 100644 --- a/src/com/android/launcher2/WidgetChooser.java +++ b/src/com/android/launcher2/WidgetChooser.java @@ -34,8 +34,11 @@ public class WidgetChooser extends HomeCustomizationItemGallery implements DragS int screenX = mMotionDownRawX - (w / 2); int screenY = mMotionDownRawY - h; - LauncherAppWidgetInfo dragInfo = new LauncherAppWidgetInfo(-1); - dragInfo.providerName = info.provider; + AppWidgetProviderInfo appWidgetInfo = (AppWidgetProviderInfo)view.getTag(); + LauncherAppWidgetInfo dragInfo = new LauncherAppWidgetInfo(info.provider); + // TODO: Is this really the best place to do this? + dragInfo.minWidth = appWidgetInfo.minWidth; + dragInfo.minHeight = appWidgetInfo.minHeight; mDragController.startDrag(bmp, screenX, screenY, 0, 0, w, h, this, dragInfo, DragController.DRAG_ACTION_COPY); return true; diff --git a/src/com/android/launcher2/WidgetListAdapter.java b/src/com/android/launcher2/WidgetListAdapter.java index 5a569ea02..5d5d86a67 100644 --- a/src/com/android/launcher2/WidgetListAdapter.java +++ b/src/com/android/launcher2/WidgetListAdapter.java @@ -85,6 +85,8 @@ public class WidgetListAdapter extends BaseAdapter { image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight()); textView.setCompoundDrawables(null, image, null, null); textView.setText(info.label); + // Store the widget info on the associated view so we can easily fetch it later + textView.setTag(info); return textView; } diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java index 57195ad8f..67b543e87 100644 --- a/src/com/android/launcher2/Workspace.java +++ b/src/com/android/launcher2/Workspace.java @@ -28,6 +28,7 @@ import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; import android.content.res.TypedArray; import android.graphics.Canvas; +import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -43,9 +44,9 @@ import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewParent; import android.view.animation.Animation; +import android.view.animation.Animation.AnimationListener; import android.view.animation.Interpolator; import android.view.animation.RotateAnimation; -import android.view.animation.Animation.AnimationListener; import android.widget.Scroller; import android.widget.TextView; import android.widget.Toast; @@ -90,6 +91,11 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag */ private int[] mTargetCell = null; + /** + * The CellLayout that is currently being dragged over + */ + private CellLayout mDragTargetLayout = null; + private float mLastMotionX; private float mLastMotionY; @@ -136,6 +142,8 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag private static final float BASELINE_FLING_VELOCITY = 2500.f; private static final float FLING_VELOCITY_INFLUENCE = 0.4f; + private Paint mDropIndicatorPaint; + private static class WorkspaceOvershootInterpolator implements Interpolator { private static final float DEFAULT_TENSION = 1.3f; private float mTension; @@ -480,13 +488,12 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag lp.cellVSpan = spanY; } - // get the canonical child id to uniquely represent this view in this - // screen + // Get the canonical child id to uniquely represent this view in this screen int childId = LauncherModel.getCanonicalCellLayoutChildId(child.getId(), screen, x, y, spanX, spanY); if (!group.addViewToCellLayout(child, insert ? 0 : -1, childId, lp)) { // TODO: This branch occurs when the workspace is adding views // outside of the defined grid - // maybe we should be deleting these items from the LauncherMode? + // maybe we should be deleting these items from the LauncherModel? Log.w(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout"); } @@ -1212,13 +1219,45 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag clearVacantCache(); } - public void onDragOver(DragSource source, int x, int y, int xOffset, - int yOffset, DragView dragView, Object dragInfo) { + 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) { + LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo)dragInfo; + + if (widgetInfo.spanX == -1) { + // Calculate the grid spans needed to fit this widget + int[] spans = currentLayout.rectToCell(widgetInfo.minWidth, widgetInfo.minHeight); + item.spanX = spans[0]; + item.spanY = spans[1]; + } + } + if (currentLayout != mDragTargetLayout) { + if (mDragTargetLayout != null) { + mDragTargetLayout.onDragComplete(); + } + mDragTargetLayout = currentLayout; + } + + // Find the top left corner of the item + int originX = x - xOffset; + int originY = y - yOffset; + + final View child = (mDragInfo == null) ? null : mDragInfo.cell; + currentLayout.visualizeDropLocation(child, originX, originY, item.spanX, item.spanY); } public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, DragView dragView, Object dragInfo) { clearVacantCache(); + if (mDragTargetLayout != null) { + mDragTargetLayout.onDragComplete(); + mDragTargetLayout = null; + } } private void onDropExternal(int x, int y, Object dragInfo, @@ -1257,16 +1296,15 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag + info.itemType); } - // addAppWidgetFromDrop already took care of attaching the widget view to the appropriate cell - // TODO why aren't we calling addInScreen here? - if (info.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) { - mTargetCell = estimateDropCell(x, y, 1, 1, view, cellLayout, - mTargetCell); + // If the view is null, it has already been added. + if (view == null) { + cellLayout.onDragComplete(); + } else { + mTargetCell = estimateDropCell(x, y, 1, 1, view, cellLayout, mTargetCell); addInScreen(view, indexOfChild(cellLayout), mTargetCell[0], mTargetCell[1], info.spanX, info.spanY, insertAtFirst); cellLayout.onDropChild(view); - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view - .getLayoutParams(); + CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams(); LauncherModel.addOrMoveItemInDatabase(mLauncher, info, LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, @@ -1344,14 +1382,18 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag */ private int[] estimateDropCell(int pixelX, int pixelY, int spanX, int spanY, View ignoreView, CellLayout layout, int[] recycle) { + + final int[] cellXY = mTempCell; + layout.estimateDropCell(pixelX, pixelY, spanX, spanY, cellXY); + layout.cellToPoint(cellXY[0], cellXY[1], mTempEstimate); + // 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); + return layout.findNearestVacantArea(mTempEstimate[0], mTempEstimate[1], spanX, spanY, mVacantCache, recycle); } void setLauncher(Launcher launcher) { -- cgit v1.2.3