diff options
Diffstat (limited to 'src/com/android/launcher2/CellLayout.java')
-rw-r--r-- | src/com/android/launcher2/CellLayout.java | 473 |
1 files changed, 229 insertions, 244 deletions
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java index 4d1c29961..19b58529b 100644 --- a/src/com/android/launcher2/CellLayout.java +++ b/src/com/android/launcher2/CellLayout.java @@ -40,8 +40,6 @@ import java.util.Arrays; public class CellLayout extends ViewGroup { static final String TAG = "CellLayout"; - private boolean mPortrait; - private int mCellWidth; private int mCellHeight; @@ -90,9 +88,6 @@ public class CellLayout extends ViewGroup { // 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; - private final WallpaperManager mWallpaperManager; public CellLayout(Context context) { @@ -135,6 +130,7 @@ public class CellLayout extends ViewGroup { mCountX = LauncherModel.getCellCountX(); mCountY = LauncherModel.getCellCountY(); + mOccupied = new boolean[mCountX][mCountY]; a.recycle(); @@ -214,15 +210,60 @@ public class CellLayout extends ViewGroup { // We might be in the middle or end of shrinking/fading to a dimmed view // Make sure this view's alpha is set the same as all the rest of the views child.setAlpha(getAlpha()); - addView(child, index, lp); + markCellsAsOccupiedForView(child); + return true; } return false; } @Override + public void removeAllViews() { + clearOccupiedCells(); + } + + @Override + public void removeAllViewsInLayout() { + clearOccupiedCells(); + } + + @Override + public void removeView(View view) { + markCellsAsUnoccupiedForView(view); + super.removeView(view); + } + + @Override + public void removeViewAt(int index) { + markCellsAsUnoccupiedForView(getChildAt(index)); + super.removeViewAt(index); + } + + @Override + public void removeViewInLayout(View view) { + markCellsAsUnoccupiedForView(view); + super.removeViewInLayout(view); + } + + @Override + public void removeViews(int start, int count) { + for (int i = start; i < start + count; i++) { + markCellsAsUnoccupiedForView(getChildAt(i)); + } + super.removeViews(start, count); + } + + @Override + public void removeViewsInLayout(int start, int count) { + for (int i = start; i < start + count; i++) { + markCellsAsUnoccupiedForView(getChildAt(i)); + } + super.removeViewsInLayout(start, count); + } + + @Override public void requestChildFocus(View child, View focused) { super.requestChildFocus(child, focused); if (child != null) { @@ -258,45 +299,24 @@ public class CellLayout extends ViewGroup { cellInfo.cellY = lp.cellY; cellInfo.spanX = lp.cellHSpan; cellInfo.spanY = lp.cellVSpan; - cellInfo.intersectX = lp.cellX; - cellInfo.intersectY = lp.cellY; cellInfo.valid = true; found = true; - mDirtyTag = false; break; } } } - mLastDownOnOccupiedCell = found; - if (!found) { final int cellXY[] = mTmpCellXY; pointToCellExact(x, y, cellXY); - final boolean portrait = mPortrait; - final int xCount = mCountX; - final int yCount = mCountY; - - final boolean[][] occupied = mOccupied; - findOccupiedCells(xCount, yCount, occupied, null, true); - cellInfo.cell = null; cellInfo.cellX = cellXY[0]; cellInfo.cellY = cellXY[1]; cellInfo.spanX = 1; cellInfo.spanY = 1; - cellInfo.intersectX = cellXY[0]; - cellInfo.intersectY = cellXY[1]; - cellInfo.valid = cellXY[0] >= 0 && cellXY[1] >= 0 && cellXY[0] < xCount && - cellXY[1] < yCount && !occupied[cellXY[0]][cellXY[1]]; - - // Instead of finding the interesting vacant cells here, wait until a - // caller invokes getTag() to retrieve the result. Finding the vacant - // cells is a bit expensive and can generate many new objects, it's - // therefore better to defer it until we know we actually need it. - - mDirtyTag = true; + cellInfo.valid = cellXY[0] >= 0 && cellXY[1] >= 0 && cellXY[0] < mCountX && + cellXY[1] < mCountY && !mOccupied[cellXY[0]][cellXY[1]]; } setTag(cellInfo); } @@ -319,7 +339,6 @@ public class CellLayout extends ViewGroup { cellInfo.spanX = 0; cellInfo.spanY = 0; cellInfo.valid = false; - mDirtyTag = false; setTag(cellInfo); } @@ -328,31 +347,7 @@ public class CellLayout extends ViewGroup { @Override public CellInfo getTag() { - final CellInfo info = (CellInfo) super.getTag(); - if (mDirtyTag && info.valid) { - final int xCount = mCountX; - final int yCount = mCountY; - - final boolean[][] occupied = mOccupied; - findOccupiedCells(xCount, yCount, occupied, null, true); - - info.updateOccupiedCells(occupied, mCountX, mCountY); - - mDirtyTag = false; - } - return info; - } - - /** - * 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]) { - return false; - } - } - return true; + return (CellInfo) super.getTag(); } /** @@ -367,42 +362,6 @@ public class CellLayout extends ViewGroup { return true; } - CellInfo updateOccupiedCells(boolean[] occupiedCells, View ignoreView) { - final int xCount = mCountX; - final int yCount = mCountY; - - boolean[][] occupied = mOccupied; - - if (occupiedCells != null) { - for (int y = 0; y < yCount; y++) { - for (int x = 0; x < xCount; x++) { - occupied[x][y] = occupiedCells[y * xCount + x]; - } - } - } else { - findOccupiedCells(xCount, yCount, occupied, ignoreView, true); - } - - CellInfo cellInfo = new CellInfo(); - - cellInfo.cellX = -1; - cellInfo.cellY = -1; - cellInfo.intersectX = -1; - cellInfo.intersectY = -1; - cellInfo.spanY = 0; - cellInfo.spanX = 0; - cellInfo.screen = mCellInfo.screen; - - cellInfo.updateOccupiedCells(occupied, mCountX, mCountY); - - cellInfo.valid = cellInfo.existsEmptyCell(); - - // Assume the caller will perform their own cell searching, otherwise we - // risk causing an unnecessary rebuild after findCellForSpan() - - return cellInfo; - } - /** * Given a point, return the cell that strictly encloses that point * @param x X coordinate of the point @@ -492,19 +451,13 @@ public class CellLayout extends ViewGroup { final int cellWidth = mCellWidth; final int cellHeight = mCellHeight; - if (mOccupied == null) { - mOccupied = new boolean[mCountX][mCountY]; - } - int numWidthGaps = mCountX - 1; int numHeightGaps = mCountY - 1; - int vSpaceLeft = heightSpecSize - mTopPadding - - mBottomPadding - (cellHeight * mCountY); + int vSpaceLeft = heightSpecSize - mTopPadding - mBottomPadding - (cellHeight * mCountY); mHeightGap = vSpaceLeft / numHeightGaps; - int hSpaceLeft = widthSpecSize - mLeftPadding - - mRightPadding - (cellWidth * mCountX); + int hSpaceLeft = widthSpecSize - mLeftPadding - mRightPadding - (cellWidth * mCountX); mWidthGap = hSpaceLeft / numWidthGaps; // center it around the min gaps @@ -519,8 +472,7 @@ public class CellLayout extends ViewGroup { lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, mLeftPadding, mTopPadding); - int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, - MeasureSpec.EXACTLY); + int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY); int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); @@ -538,7 +490,7 @@ public class CellLayout extends ViewGroup { } @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { + public void onLayout(boolean changed, int l, int t, int r, int b) { int count = getChildCount(); for (int i = 0; i < count; i++) { @@ -621,15 +573,29 @@ public class CellLayout extends ViewGroup { } } - private boolean isVacant(int originX, int originY, int spanX, int spanY) { + private boolean isVacantIgnoring( + int originX, int originY, int spanX, int spanY, View ignoreView) { + if (ignoreView != null) { + markCellsAsUnoccupiedForView(ignoreView); + } for (int i = 0; i < spanY; i++) { if (!isRowEmpty(originY + i, originX, originX + spanX - 1, mOccupied)) { + if (ignoreView != null) { + markCellsAsOccupiedForView(ignoreView); + } return false; } } + if (ignoreView != null) { + markCellsAsOccupiedForView(ignoreView); + } return true; } + private boolean isVacant(int originX, int originY, int spanX, int spanY) { + return isVacantIgnoring(originX, originY, spanX, spanY, null); + } + public View getChildAt(int x, int y) { final int count = getChildCount(); for (int i = 0; i < count; i++) { @@ -687,7 +653,8 @@ public class CellLayout extends ViewGroup { result[1] = Math.max(0, result[1]); // Snap to top } - void visualizeDropLocation(View view, int originX, int originY, int spanX, int spanY) { + void visualizeDropLocation( + View view, int originX, int originY, int spanX, int spanY, View draggedItem) { final int[] originCell = mDragCell; final int[] cellXY = mTmpCellXY; estimateDropCell(originX, originY, spanX, spanY, cellXY); @@ -709,12 +676,8 @@ public class CellLayout extends ViewGroup { bottomRight[0] += mCellWidth; bottomRight[1] += mCellHeight; - final int countX = mCountX; - final int countY = mCountY; - // 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); + boolean vacant = + isVacantIgnoring(originCell[0], originCell[1], spanX, spanY, draggedItem); mDragRectDrawable = vacant ? mVacantDrawable : mOccupiedDrawable; // mDragRect will be rendered in onDraw() @@ -736,8 +699,7 @@ public class CellLayout extends ViewGroup { * @return The X, Y cell of a vacant area that can contain this object, * nearest the requested location. */ - int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, - CellInfo vacantCells, int[] recycle) { + int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, int[] recycle) { // Keep track of best-scoring drop area final int[] bestXY = recycle != null ? recycle : new int[2]; @@ -777,10 +739,130 @@ public class CellLayout extends ViewGroup { } } + boolean existsEmptyCell() { + return findCellForSpan(null, 1, 1); + } + + /** + * Finds the upper-left coordinate of the first rectangle in the grid that can + * hold a cell of the specified dimensions. If intersectX and intersectY are not -1, + * then this method will only return coordinates for rectangles that contain the cell + * (intersectX, intersectY) + * + * @param cellXY The array that will contain the position of a vacant cell if such a cell + * can be found. + * @param spanX The horizontal span of the cell we want to find. + * @param spanY The vertical span of the cell we want to find. + * + * @return True if a vacant cell of the specified dimension was found, false otherwise. + */ + boolean findCellForSpan(int[] cellXY, int spanX, int spanY) { + return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null); + } + + /** + * Like above, but ignores any cells occupied by the item "ignoreView" + * + * @param cellXY The array that will contain the position of a vacant cell if such a cell + * can be found. + * @param spanX The horizontal span of the cell we want to find. + * @param spanY The vertical span of the cell we want to find. + * @param ignoreView The home screen item we should treat as not occupying any space + * @return + */ + boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) { + return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, ignoreView); + } + + /** + * Like above, but if intersectX and intersectY are not -1, then this method will try to + * return coordinates for rectangles that contain the cell [intersectX, intersectY] + * + * @param spanX The horizontal span of the cell we want to find. + * @param spanY The vertical span of the cell we want to find. + * @param ignoreView The home screen item we should treat as not occupying any space + * @param intersectX The X coordinate of the cell that we should try to overlap + * @param intersectX The Y coordinate of the cell that we should try to overlap + * + * @return True if a vacant cell of the specified dimension was found, false otherwise. + */ + boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY, + int intersectX, int intersectY) { + return findCellForSpanThatIntersectsIgnoring( + cellXY, spanX, spanY, intersectX, intersectY, null); + } + + /** + * The superset of the above two methods + */ + boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY, + int intersectX, int intersectY, View ignoreView) { + if (ignoreView != null) { + markCellsAsUnoccupiedForView(ignoreView); + } + + while (true) { + int startX = 0; + if (intersectX >= 0) { + startX = Math.max(startX, intersectX - (spanX - 1)); + } + int endX = mCountX - (spanX - 1); + if (intersectX >= 0) { + endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0)); + } + int startY = 0; + if (intersectY >= 0) { + startY = Math.max(startY, intersectY - (spanY - 1)); + } + int endY = mCountY - (spanY - 1); + if (intersectY >= 0) { + endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0)); + } + + for (int x = startX; x < endX; x++) { + inner: + for (int y = startY; y < endY; y++) { + for (int i = 0; i < spanX; i++) { + for (int j = 0; j < spanY; j++) { + if (mOccupied[x + i][y + j]) { + // small optimization: we can skip to below the row we just found + // an occupied cell + y += j; + continue inner; + } + } + } + if (cellXY != null) { + cellXY[0] = x; + cellXY[1] = y; + } + if (ignoreView != null) { + markCellsAsOccupiedForView(ignoreView); + } + return true; + } + } + if (intersectX == -1 && intersectY == -1) { + break; + } else { + // if we failed to find anything, try again but without any requirements of + // intersecting + intersectX = -1; + intersectY = -1; + continue; + } + } + + if (ignoreView != null) { + markCellsAsOccupiedForView(ignoreView); + } + return false; + } + /** - * Called when a drag and drop operation has finished (successfully or not). + * Called when drag has left this CellLayout or has been completed (successfully or not) */ - void onDragComplete() { + void onDragExit() { // Invalidate the drag data mDragCell[0] = -1; mDragCell[1] = -1; @@ -803,14 +885,14 @@ public class CellLayout extends ViewGroup { mDragRect.setEmpty(); child.requestLayout(); } - onDragComplete(); + onDragExit(); } void onDropAborted(View child) { if (child != null) { ((LayoutParams) child.getLayoutParams()).isDragging = false; } - onDragComplete(); + onDragExit(); } /** @@ -889,13 +971,8 @@ public class CellLayout extends ViewGroup { * @return True if a vacant cell was found */ public boolean getVacantCell(int[] vacant, int spanX, int spanY) { - final int xCount = mCountX; - final int yCount = mCountY; - final boolean[][] occupied = mOccupied; - - findOccupiedCells(xCount, yCount, occupied, null, true); - return findVacantCell(vacant, spanX, spanY, xCount, yCount, occupied); + return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied); } static boolean findVacantCell(int[] vacant, int spanX, int spanY, @@ -930,8 +1007,6 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { final int yCount = mCountY; final boolean[][] occupied = mOccupied; - findOccupiedCells(xCount, yCount, occupied, null, true); - final boolean[] flat = new boolean[xCount * yCount]; for (int y = 0; y < yCount; y++) { for (int x = 0; x < xCount; x++) { @@ -942,32 +1017,34 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { return flat; } - /** - * 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; + private void clearOccupiedCells() { + for (int x = 0; x < mCountX; x++) { + for (int y = 0; y < mCountY; y++) { + mOccupied[x][y] = false; } } + } - int count = getChildCount(); - for (int i = 0; i < count; i++) { - View child = getChildAt(i); - if ((ignoreFolders && child instanceof Folder) || child.equals(ignoreView)) { - continue; - } - LayoutParams lp = (LayoutParams) child.getLayoutParams(); + public void onMove(View view, int newCellX, int newCellY) { + LayoutParams lp = (LayoutParams) view.getLayoutParams(); + markCellsAsUnoccupiedForView(view); + markCellsForView(newCellX, newCellY, lp.cellHSpan, lp.cellVSpan, true); + } - for (int x = lp.cellX; x < lp.cellX + lp.cellHSpan && x < xCount; x++) { - for (int y = lp.cellY; y < lp.cellY + lp.cellVSpan && y < yCount; y++) { - occupied[x][y] = true; - } + private void markCellsAsOccupiedForView(View view) { + LayoutParams lp = (LayoutParams) view.getLayoutParams(); + markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, true); + } + + private void markCellsAsUnoccupiedForView(View view) { + LayoutParams lp = (LayoutParams) view.getLayoutParams(); + markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, false); + } + + private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean value) { + for (int x = cellX; x < cellX + spanX && x < mCountX; x++) { + for (int y = cellY; y < cellY + spanY && y < mCountY; y++) { + mOccupied[x][y] = value; } } } @@ -1087,117 +1164,25 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { } } + // This class stores info for two purposes: + // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY, + // its spanX, spanY, and the screen it is on + // 2. When long clicking on an empty cell in a CellLayout, we save information about the + // cellX and cellY coordinates and which page was clicked. We then set this as a tag on + // the CellLayout that was long clicked static final class CellInfo implements ContextMenu.ContextMenuInfo { - private boolean[][] mOccupied; - private int mCountX; - private int mCountY; View cell; int cellX = -1; int cellY = -1; - // intersectX and intersectY constrain the results of findCellForSpan; any empty space - // it results must include this point (unless intersectX and intersectY are -1) - int intersectX = -1; - int intersectY = -1; int spanX; int spanY; int screen; boolean valid; - void updateOccupiedCells(boolean[][] occupied, int xCount, int yCount) { - mOccupied = occupied.clone(); - mCountX = xCount; - mCountY = yCount; - } - - void updateOccupiedCells(boolean[] occupied, int xCount, int yCount) { - if (mOccupied == null || mCountX != xCount || mCountY != yCount) { - mOccupied = new boolean[xCount][yCount]; - } - mCountX = xCount; - mCountY = yCount; - for (int y = 0; y < yCount; y++) { - for (int x = 0; x < xCount; x++) { - mOccupied[x][y] = occupied[y * xCount + x]; - } - } - } - - boolean existsEmptyCell() { - return findCellForSpan(null, 1, 1); - } - /** - * Finds the upper-left coordinate of the first rectangle in the grid that can - * hold a cell of the specified dimensions. If intersectX and intersectY are not -1, - * then this method will only return coordinates for rectangles that contain the cell - * (intersectX, intersectY) - * - * @param cellXY The array that will contain the position of a vacant cell if such a cell - * can be found. - * @param spanX The horizontal span of the cell we want to find. - * @param spanY The vertical span of the cell we want to find. - * - * @return True if a vacant cell of the specified dimension was found, false otherwise. - */ - boolean findCellForSpan(int[] cellXY, int spanX, int spanY) { - // return the span represented by the CellInfo only there is no view there - // (this.cell == null) and there is enough space - - if (this.cell == null && this.spanX >= spanX && this.spanY >= spanY) { - if (cellXY != null) { - cellXY[0] = cellX; - cellXY[1] = cellY; - } - return true; - } - - int startX = 0; - if (intersectX >= 0) { - startX = Math.max(startX, intersectX - (spanX - 1)); - } - int endX = mCountX - (spanX - 1); - if (intersectX >= 0) { - endX = Math.min(endX, intersectX + (spanX - 1)); - } - int startY = 0; - if (intersectY >= 0) { - startY = Math.max(startY, intersectY - (spanY - 1)); - } - int endY = mCountY - (spanY - 1); - if (intersectY >= 0) { - endY = Math.min(endY, intersectY + (spanY - 1)); - } - - for (int x = startX; x < endX; x++) { - inner: - for (int y = startY; y < endY; y++) { - for (int i = 0; i < spanX; i++) { - for (int j = 0; j < spanY; j++) { - if (mOccupied[x + i][y + j]) { - // small optimization: we can skip to below the row we just found - // an occupied cell - y += j; - continue inner; - } - } - } - if (cellXY != null) { - cellXY[0] = x; - cellXY[1] = y; - } - return true; - } - } - return false; - } - @Override public String toString() { return "Cell[view=" + (cell == null ? "null" : cell.getClass()) + ", x=" + cellX + ", y=" + cellY + "]"; } } - - public boolean lastDownOnOccupiedCell() { - return mLastDownOnOccupiedCell; - } } |