diff options
author | Jean-Baptiste Queru <jbq@google.com> | 2009-04-22 17:12:38 -0700 |
---|---|---|
committer | Jean-Baptiste Queru <jbq@google.com> | 2009-04-22 17:12:38 -0700 |
commit | 93998d1525a9983271972fb5c86709ec3d46acf7 (patch) | |
tree | 033d1e52ed2a2c57fb2af4786ce5f1b4d7ecf635 | |
parent | 24c106a36f330435f9ccc6871e4de0f4106fa2ea (diff) | |
parent | 7c693528b3bf83f78c7bcd4ecaffdd23529418cd (diff) | |
download | android_packages_apps_Trebuchet-93998d1525a9983271972fb5c86709ec3d46acf7.tar.gz android_packages_apps_Trebuchet-93998d1525a9983271972fb5c86709ec3d46acf7.tar.bz2 android_packages_apps_Trebuchet-93998d1525a9983271972fb5c86709ec3d46acf7.zip |
Merge donut into master
-rw-r--r-- | res/values/colors.xml | 1 | ||||
-rw-r--r-- | src/com/android/launcher/CellLayout.java | 108 | ||||
-rw-r--r-- | src/com/android/launcher/DeleteZone.java | 5 | ||||
-rw-r--r-- | src/com/android/launcher/DragLayer.java | 84 | ||||
-rw-r--r-- | src/com/android/launcher/DropTarget.java | 38 | ||||
-rw-r--r-- | src/com/android/launcher/FolderIcon.java | 5 | ||||
-rw-r--r-- | src/com/android/launcher/UserFolder.java | 5 | ||||
-rw-r--r-- | src/com/android/launcher/Workspace.java | 101 |
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); |