summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher/CellLayout.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher/CellLayout.java')
-rw-r--r--src/com/android/launcher/CellLayout.java1010
1 files changed, 0 insertions, 1010 deletions
diff --git a/src/com/android/launcher/CellLayout.java b/src/com/android/launcher/CellLayout.java
deleted file mode 100644
index ff8bff420..000000000
--- a/src/com/android/launcher/CellLayout.java
+++ /dev/null
@@ -1,1010 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.util.AttributeSet;
-import android.view.ContextMenu;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewDebug;
-import android.view.ViewGroup;
-
-import java.util.ArrayList;
-
-public class CellLayout extends ViewGroup {
- private boolean mPortrait;
-
- private int mCellWidth;
- private int mCellHeight;
-
- private int mLongAxisStartPadding;
- private int mLongAxisEndPadding;
-
- private int mShortAxisStartPadding;
- private int mShortAxisEndPadding;
-
- private int mShortAxisCells;
- private int mLongAxisCells;
-
- private int mWidthGap;
- private int mHeightGap;
-
- private final Rect mRect = new Rect();
- private final CellInfo mCellInfo = new CellInfo();
-
- int[] mCellXY = new int[2];
-
- boolean[][] mOccupied;
-
- private RectF mDragRect = new RectF();
-
- private boolean mDirtyTag;
-
- public CellLayout(Context context) {
- this(context, null);
- }
-
- public CellLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public CellLayout(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
-
- mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10);
- mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10);
-
- mLongAxisStartPadding =
- a.getDimensionPixelSize(R.styleable.CellLayout_longAxisStartPadding, 10);
- mLongAxisEndPadding =
- a.getDimensionPixelSize(R.styleable.CellLayout_longAxisEndPadding, 10);
- mShortAxisStartPadding =
- a.getDimensionPixelSize(R.styleable.CellLayout_shortAxisStartPadding, 10);
- mShortAxisEndPadding =
- a.getDimensionPixelSize(R.styleable.CellLayout_shortAxisEndPadding, 10);
-
- mShortAxisCells = a.getInt(R.styleable.CellLayout_shortAxisCells, 4);
- mLongAxisCells = a.getInt(R.styleable.CellLayout_longAxisCells, 4);
-
- a.recycle();
-
- setAlwaysDrawnWithCacheEnabled(false);
-
- if (mOccupied == null) {
- if (mPortrait) {
- mOccupied = new boolean[mShortAxisCells][mLongAxisCells];
- } else {
- mOccupied = new boolean[mLongAxisCells][mShortAxisCells];
- }
- }
- }
-
- int getCountX() {
- return mPortrait ? mShortAxisCells : mLongAxisCells;
- }
-
- int getCountY() {
- return mPortrait ? mLongAxisCells : mShortAxisCells;
- }
-
- @Override
- public void addView(View child, int index, ViewGroup.LayoutParams params) {
- // Generate an id for each view, this assumes we have at most 256x256 cells
- // per workspace screen
- final LayoutParams cellParams = (LayoutParams) params;
- child.setId(((getId() & 0xFF) << 16) |
- (cellParams.cellX & 0xFF) << 8 | (cellParams.cellY & 0xFF));
-
- super.addView(child, index, params);
- }
-
- @Override
- public void requestChildFocus(View child, View focused) {
- super.requestChildFocus(child, focused);
- if (child != null) {
- Rect r = new Rect();
- child.getDrawingRect(r);
- requestRectangleOnScreen(r);
- }
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this);
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- final int action = ev.getAction();
- final CellInfo cellInfo = mCellInfo;
-
- if (action == MotionEvent.ACTION_DOWN) {
- final Rect frame = mRect;
- final int x = (int) ev.getX() + mScrollX;
- final int y = (int) ev.getY() + mScrollY;
- final int count = getChildCount();
-
- boolean found = false;
- for (int i = count - 1; i >= 0; i--) {
- final View child = getChildAt(i);
-
- if ((child.getVisibility()) == VISIBLE || child.getAnimation() != null) {
- child.getHitRect(frame);
- if (frame.contains(x, y)) {
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
- cellInfo.cell = child;
- cellInfo.cellX = lp.cellX;
- cellInfo.cellY = lp.cellY;
- cellInfo.spanX = lp.cellHSpan;
- cellInfo.spanY = lp.cellVSpan;
- cellInfo.valid = true;
- found = true;
- mDirtyTag = false;
- break;
- }
- }
- }
-
- if (!found) {
- int cellXY[] = mCellXY;
- pointToCellExact(x, y, cellXY);
-
- final boolean portrait = mPortrait;
- final int xCount = portrait ? mShortAxisCells : mLongAxisCells;
- final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
-
- final boolean[][] occupied = mOccupied;
- findOccupiedCells(xCount, yCount, occupied);
-
- cellInfo.cell = null;
- cellInfo.cellX = cellXY[0];
- cellInfo.cellY = cellXY[1];
- cellInfo.spanX = 1;
- cellInfo.spanY = 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;
- }
- setTag(cellInfo);
- } else if (action == MotionEvent.ACTION_UP) {
- cellInfo.cell = null;
- cellInfo.cellX = -1;
- cellInfo.cellY = -1;
- cellInfo.spanX = 0;
- cellInfo.spanY = 0;
- cellInfo.valid = false;
- mDirtyTag = false;
- setTag(cellInfo);
- }
-
- return false;
- }
-
- @Override
- public CellInfo getTag() {
- final CellInfo info = (CellInfo) super.getTag();
- if (mDirtyTag && info.valid) {
- final boolean portrait = mPortrait;
- final int xCount = portrait ? mShortAxisCells : mLongAxisCells;
- final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
-
- final boolean[][] occupied = mOccupied;
- findOccupiedCells(xCount, yCount, occupied);
-
- findIntersectingVacantCells(info, info.cellX, info.cellY, xCount, yCount, occupied);
-
- mDirtyTag = false;
- }
- return info;
- }
-
- private static void findIntersectingVacantCells(CellInfo cellInfo, int x, int y,
- int xCount, int yCount, boolean[][] occupied) {
-
- cellInfo.maxVacantSpanX = Integer.MIN_VALUE;
- cellInfo.maxVacantSpanXSpanY = Integer.MIN_VALUE;
- cellInfo.maxVacantSpanY = Integer.MIN_VALUE;
- cellInfo.maxVacantSpanYSpanX = Integer.MIN_VALUE;
- cellInfo.clearVacantCells();
-
- if (occupied[x][y]) {
- return;
- }
-
- cellInfo.current.set(x, y, x, y);
-
- findVacantCell(cellInfo.current, xCount, yCount, occupied, cellInfo);
- }
-
- private static void findVacantCell(Rect current, int xCount, int yCount, boolean[][] occupied,
- CellInfo cellInfo) {
-
- addVacantCell(current, cellInfo);
-
- if (current.left > 0) {
- if (isColumnEmpty(current.left - 1, current.top, current.bottom, occupied)) {
- current.left--;
- findVacantCell(current, xCount, yCount, occupied, cellInfo);
- current.left++;
- }
- }
-
- if (current.right < xCount - 1) {
- if (isColumnEmpty(current.right + 1, current.top, current.bottom, occupied)) {
- current.right++;
- findVacantCell(current, xCount, yCount, occupied, cellInfo);
- current.right--;
- }
- }
-
- if (current.top > 0) {
- if (isRowEmpty(current.top - 1, current.left, current.right, occupied)) {
- current.top--;
- findVacantCell(current, xCount, yCount, occupied, cellInfo);
- current.top++;
- }
- }
-
- if (current.bottom < yCount - 1) {
- if (isRowEmpty(current.bottom + 1, current.left, current.right, occupied)) {
- current.bottom++;
- findVacantCell(current, xCount, yCount, occupied, cellInfo);
- current.bottom--;
- }
- }
- }
-
- private static void addVacantCell(Rect current, CellInfo cellInfo) {
- CellInfo.VacantCell cell = CellInfo.VacantCell.acquire();
- cell.cellX = current.left;
- cell.cellY = current.top;
- cell.spanX = current.right - current.left + 1;
- cell.spanY = current.bottom - current.top + 1;
- if (cell.spanX > cellInfo.maxVacantSpanX) {
- cellInfo.maxVacantSpanX = cell.spanX;
- cellInfo.maxVacantSpanXSpanY = cell.spanY;
- }
- if (cell.spanY > cellInfo.maxVacantSpanY) {
- cellInfo.maxVacantSpanY = cell.spanY;
- cellInfo.maxVacantSpanYSpanX = cell.spanX;
- }
- cellInfo.vacantCells.add(cell);
- }
-
- 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;
- }
-
- private static boolean isRowEmpty(int y, int left, int right, boolean[][] occupied) {
- for (int x = left; x <= right; x++) {
- if (occupied[x][y]) {
- return false;
- }
- }
- return true;
- }
-
- CellInfo findAllVacantCells(boolean[] occupiedCells) {
- final boolean portrait = mPortrait;
- final int xCount = portrait ? mShortAxisCells : mLongAxisCells;
- final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
-
- 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);
- }
-
- CellInfo cellInfo = new CellInfo();
-
- cellInfo.cellX = -1;
- cellInfo.cellY = -1;
- cellInfo.spanY = 0;
- cellInfo.spanX = 0;
- cellInfo.maxVacantSpanX = Integer.MIN_VALUE;
- cellInfo.maxVacantSpanXSpanY = Integer.MIN_VALUE;
- cellInfo.maxVacantSpanY = Integer.MIN_VALUE;
- cellInfo.maxVacantSpanYSpanX = Integer.MIN_VALUE;
- cellInfo.screen = mCellInfo.screen;
-
- Rect current = cellInfo.current;
-
- for (int x = 0; x < xCount; x++) {
- for (int y = 0; y < yCount; y++) {
- if (!occupied[x][y]) {
- current.set(x, y, x, y);
- findVacantCell(current, xCount, yCount, occupied, cellInfo);
- occupied[x][y] = true;
- }
- }
- }
-
- cellInfo.valid = cellInfo.vacantCells.size() > 0;
-
- // 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
- * @param y Y coordinate of the point
- * @param result Array of 2 ints to hold the x and y coordinate of the cell
- */
- void pointToCellExact(int x, int y, int[] result) {
- final boolean portrait = mPortrait;
-
- final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding;
- final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding;
-
- result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap);
- result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap);
-
- final int xAxis = portrait ? mShortAxisCells : mLongAxisCells;
- final int yAxis = portrait ? mLongAxisCells : mShortAxisCells;
-
- if (result[0] < 0) result[0] = 0;
- if (result[0] >= xAxis) result[0] = xAxis - 1;
- if (result[1] < 0) result[1] = 0;
- if (result[1] >= yAxis) result[1] = yAxis - 1;
- }
-
- /**
- * Given a point, return the cell that most closely encloses that point
- * @param x X coordinate of the point
- * @param y Y coordinate of the point
- * @param result Array of 2 ints to hold the x and y coordinate of the cell
- */
- void pointToCellRounded(int x, int y, int[] result) {
- pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result);
- }
-
- /**
- * Given a cell coordinate, return the point that represents the upper left corner of that cell
- *
- * @param cellX X coordinate of the cell
- * @param cellY Y coordinate of the cell
- *
- * @param result Array of 2 ints to hold the x and y coordinate of the point
- */
- void cellToPoint(int cellX, int cellY, int[] result) {
- final boolean portrait = mPortrait;
-
- final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding;
- final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding;
-
-
- result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap);
- result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- // TODO: currently ignoring padding
-
- int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
- int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
-
- int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
- int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
-
- if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
- throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
- }
-
- final int shortAxisCells = mShortAxisCells;
- final int longAxisCells = mLongAxisCells;
- final int longAxisStartPadding = mLongAxisStartPadding;
- final int longAxisEndPadding = mLongAxisEndPadding;
- final int shortAxisStartPadding = mShortAxisStartPadding;
- final int shortAxisEndPadding = mShortAxisEndPadding;
- final int cellWidth = mCellWidth;
- final int cellHeight = mCellHeight;
-
- mPortrait = heightSpecSize > widthSpecSize;
-
- int numShortGaps = shortAxisCells - 1;
- int numLongGaps = longAxisCells - 1;
-
- if (mPortrait) {
- int vSpaceLeft = heightSpecSize - longAxisStartPadding - longAxisEndPadding
- - (cellHeight * longAxisCells);
- mHeightGap = vSpaceLeft / numLongGaps;
-
- int hSpaceLeft = widthSpecSize - shortAxisStartPadding - shortAxisEndPadding
- - (cellWidth * shortAxisCells);
- if (numShortGaps > 0) {
- mWidthGap = hSpaceLeft / numShortGaps;
- } else {
- mWidthGap = 0;
- }
- } else {
- int hSpaceLeft = widthSpecSize - longAxisStartPadding - longAxisEndPadding
- - (cellWidth * longAxisCells);
- mWidthGap = hSpaceLeft / numLongGaps;
-
- int vSpaceLeft = heightSpecSize - shortAxisStartPadding - shortAxisEndPadding
- - (cellHeight * shortAxisCells);
- if (numShortGaps > 0) {
- mHeightGap = vSpaceLeft / numShortGaps;
- } else {
- mHeightGap = 0;
- }
- }
-
- int count = getChildCount();
-
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
- if (mPortrait) {
- lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, shortAxisStartPadding,
- longAxisStartPadding);
- } else {
- lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, longAxisStartPadding,
- shortAxisStartPadding);
- }
-
- int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
- int childheightMeasureSpec =
- MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
- child.measure(childWidthMeasureSpec, childheightMeasureSpec);
- }
-
- setMeasuredDimension(widthSpecSize, heightSpecSize);
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- int count = getChildCount();
-
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- if (child.getVisibility() != GONE) {
-
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
-
- int childLeft = lp.x;
- int childTop = lp.y;
- child.layout(childLeft, childTop, childLeft + lp.width, childTop + lp.height);
- }
- }
- }
-
- @Override
- protected void setChildrenDrawingCacheEnabled(boolean enabled) {
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- final View view = getChildAt(i);
- view.setDrawingCacheEnabled(enabled);
- // Update the drawing caches
- view.buildDrawingCache();
- }
- }
-
- @Override
- protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
- 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.
- */
- 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;
- }
-
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- final View view = getChildAt(i);
- if (view == ignoreCell) {
- 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;
- }
- }
-
- 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
- */
- void onDropChild(View child, int cellX, int cellY) {
- int[] cellXY = mCellXY;
- pointToCellRounded(cellX, cellY, cellXY);
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
- lp.cellX = cellXY[0];
- lp.cellY = cellXY[1];
- lp.isDragging = false;
- mDragRect.setEmpty();
- child.requestLayout();
- invalidate();
- }
-
- void onDropAborted(View child) {
- if (child != null) {
- ((LayoutParams) child.getLayoutParams()).isDragging = false;
- invalidate();
- }
- mDragRect.setEmpty();
- }
-
- /**
- * Start dragging the specified child
- *
- * @param child The child that is being dragged
- */
- void onDragChild(View child) {
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
- lp.isDragging = true;
- 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
- *
- * @param cellX X coordinate of upper left corner expressed as a cell position
- * @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
- */
- public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, RectF dragRect) {
- final boolean portrait = mPortrait;
- final int cellWidth = mCellWidth;
- final int cellHeight = mCellHeight;
- final int widthGap = mWidthGap;
- final int heightGap = mHeightGap;
-
- final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding;
- final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding;
-
- int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap);
- int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap);
-
- int x = hStartPadding + cellX * (cellWidth + widthGap);
- int y = vStartPadding + cellY * (cellHeight + heightGap);
-
- dragRect.set(x, y, x + width, y + height);
- }
-
- /**
- * Computes the required horizontal and vertical cell spans to always
- * fit the given rectangle.
- *
- * @param width Width in pixels
- * @param height Height in pixels
- * @param Horizontal and vertical spans required
- */
- public int[] rectToCell(int width, int height) {
- // Always assume we're working with the smallest span to make sure we
- // reserve enough space in both orientations.
- int actualWidth = mCellWidth + mWidthGap;
- int actualHeight = mCellHeight + mHeightGap;
- int smallerSize = Math.min(actualWidth, actualHeight);
-
- // Always round up to next largest cell
- int spanX = (width + smallerSize) / smallerSize;
- int spanY = (height + smallerSize) / smallerSize;
- return new int[] { spanX, spanY };
- }
-
- /**
- * Find the first vacant cell, if there is one.
- *
- * @param vacant Holds the x and y coordinate of the vacant cell
- * @param spanX Horizontal cell span.
- * @param spanY Vertical cell span.
- *
- * @return True if a vacant cell was found
- */
- public boolean getVacantCell(int[] vacant, int spanX, int spanY) {
- final boolean portrait = mPortrait;
- final int xCount = portrait ? mShortAxisCells : mLongAxisCells;
- final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
- final boolean[][] occupied = mOccupied;
-
- findOccupiedCells(xCount, yCount, occupied);
-
- return findVacantCell(vacant, spanX, spanY, xCount, yCount, occupied);
- }
-
- static boolean findVacantCell(int[] vacant, int spanX, int spanY,
- int xCount, int yCount, boolean[][] occupied) {
-
- for (int x = 0; x < xCount; x++) {
- for (int y = 0; y < yCount; y++) {
- boolean available = !occupied[x][y];
-out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
- for (int j = y; j < y + spanY - 1 && y < yCount; j++) {
- available = available && !occupied[i][j];
- if (!available) break out;
- }
- }
-
- if (available) {
- vacant[0] = x;
- vacant[1] = y;
- return true;
- }
- }
- }
-
- return false;
- }
-
- boolean[] getOccupiedCells() {
- final boolean portrait = mPortrait;
- final int xCount = portrait ? mShortAxisCells : mLongAxisCells;
- final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
- final boolean[][] occupied = mOccupied;
-
- findOccupiedCells(xCount, yCount, occupied);
-
- final boolean[] flat = new boolean[xCount * yCount];
- for (int y = 0; y < yCount; y++) {
- for (int x = 0; x < xCount; x++) {
- flat[y * xCount + x] = occupied[x][y];
- }
- }
-
- return flat;
- }
-
- private void findOccupiedCells(int xCount, int yCount, boolean[][] occupied) {
- for (int x = 0; x < xCount; x++) {
- for (int y = 0; y < yCount; y++) {
- occupied[x][y] = false;
- }
- }
-
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- if (child instanceof Folder) {
- continue;
- }
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
- 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;
- }
- }
- }
- }
-
- @Override
- public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
- return new CellLayout.LayoutParams(getContext(), attrs);
- }
-
- @Override
- protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
- return p instanceof CellLayout.LayoutParams;
- }
-
- @Override
- protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
- return new CellLayout.LayoutParams(p);
- }
-
- public static class LayoutParams extends ViewGroup.MarginLayoutParams {
- /**
- * Horizontal location of the item in the grid.
- */
- @ViewDebug.ExportedProperty
- public int cellX;
-
- /**
- * Vertical location of the item in the grid.
- */
- @ViewDebug.ExportedProperty
- public int cellY;
-
- /**
- * Number of cells spanned horizontally by the item.
- */
- @ViewDebug.ExportedProperty
- public int cellHSpan;
-
- /**
- * Number of cells spanned vertically by the item.
- */
- @ViewDebug.ExportedProperty
- public int cellVSpan;
-
- /**
- * Is this item currently being dragged
- */
- public boolean isDragging;
-
- // X coordinate of the view in the layout.
- @ViewDebug.ExportedProperty
- int x;
- // Y coordinate of the view in the layout.
- @ViewDebug.ExportedProperty
- int y;
-
- public LayoutParams(Context c, AttributeSet attrs) {
- super(c, attrs);
- cellHSpan = 1;
- cellVSpan = 1;
- }
-
- public LayoutParams(ViewGroup.LayoutParams source) {
- super(source);
- cellHSpan = 1;
- cellVSpan = 1;
- }
-
- public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
- super(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
- this.cellX = cellX;
- this.cellY = cellY;
- this.cellHSpan = cellHSpan;
- this.cellVSpan = cellVSpan;
- }
-
- public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap,
- int hStartPadding, int vStartPadding) {
-
- final int myCellHSpan = cellHSpan;
- final int myCellVSpan = cellVSpan;
- final int myCellX = cellX;
- final int myCellY = cellY;
-
- width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
- leftMargin - rightMargin;
- height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
- topMargin - bottomMargin;
-
- x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
- y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
- }
- }
-
- static final class CellInfo implements ContextMenu.ContextMenuInfo {
- /**
- * See View.AttachInfo.InvalidateInfo for futher explanations about
- * the recycling mechanism. In this case, we recycle the vacant cells
- * instances because up to several hundreds can be instanciated when
- * the user long presses an empty cell.
- */
- static final class VacantCell {
- int cellX;
- int cellY;
- int spanX;
- int spanY;
-
- // We can create up to 523 vacant cells on a 4x4 grid, 100 seems
- // like a reasonable compromise given the size of a VacantCell and
- // the fact that the user is not likely to touch an empty 4x4 grid
- // very often
- private static final int POOL_LIMIT = 100;
- private static final Object sLock = new Object();
-
- private static int sAcquiredCount = 0;
- private static VacantCell sRoot;
-
- private VacantCell next;
-
- static VacantCell acquire() {
- synchronized (sLock) {
- if (sRoot == null) {
- return new VacantCell();
- }
-
- VacantCell info = sRoot;
- sRoot = info.next;
- sAcquiredCount--;
-
- return info;
- }
- }
-
- void release() {
- synchronized (sLock) {
- if (sAcquiredCount < POOL_LIMIT) {
- sAcquiredCount++;
- next = sRoot;
- sRoot = this;
- }
- }
- }
-
- @Override
- public String toString() {
- return "VacantCell[x=" + cellX + ", y=" + cellY + ", spanX=" + spanX +
- ", spanY=" + spanY + "]";
- }
- }
-
- View cell;
- int cellX;
- int cellY;
- int spanX;
- int spanY;
- int screen;
- boolean valid;
-
- final ArrayList<VacantCell> vacantCells = new ArrayList<VacantCell>(VacantCell.POOL_LIMIT);
- int maxVacantSpanX;
- int maxVacantSpanXSpanY;
- int maxVacantSpanY;
- int maxVacantSpanYSpanX;
- final Rect current = new Rect();
-
- private void clearVacantCells() {
- final ArrayList<VacantCell> list = vacantCells;
- final int count = list.size();
-
- for (int i = 0; i < count; i++) list.get(i).release();
-
- list.clear();
- }
-
- void findVacantCellsFromOccupied(boolean[] occupied, int xCount, int yCount) {
- if (cellX < 0 || cellY < 0) {
- maxVacantSpanX = maxVacantSpanXSpanY = Integer.MIN_VALUE;
- maxVacantSpanY = maxVacantSpanYSpanX = Integer.MIN_VALUE;
- clearVacantCells();
- return;
- }
-
- final boolean[][] unflattened = new boolean[xCount][yCount];
- for (int y = 0; y < yCount; y++) {
- for (int x = 0; x < xCount; x++) {
- unflattened[x][y] = occupied[y * xCount + x];
- }
- }
- CellLayout.findIntersectingVacantCells(this, cellX, cellY, xCount, yCount, unflattened);
- }
-
- /**
- * This method can be called only once! Calling #findVacantCellsFromOccupied will
- * restore the ability to call this method.
- *
- * Finds the upper-left coordinate of the first rectangle in the grid that can
- * hold a cell of the specified dimensions.
- *
- * @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) {
- final ArrayList<VacantCell> list = vacantCells;
- final int count = list.size();
-
- boolean found = false;
-
- if (this.spanX >= spanX && this.spanY >= spanY) {
- cellXY[0] = cellX;
- cellXY[1] = cellY;
- found = true;
- }
-
- // Look for an exact match first
- for (int i = 0; i < count; i++) {
- VacantCell cell = list.get(i);
- if (cell.spanX == spanX && cell.spanY == spanY) {
- cellXY[0] = cell.cellX;
- cellXY[1] = cell.cellY;
- found = true;
- break;
- }
- }
-
- // Look for the first cell large enough
- for (int i = 0; i < count; i++) {
- VacantCell cell = list.get(i);
- if (cell.spanX >= spanX && cell.spanY >= spanY) {
- cellXY[0] = cell.cellX;
- cellXY[1] = cell.cellY;
- found = true;
- break;
- }
- }
-
- clearVacantCells();
-
- return found;
- }
-
- @Override
- public String toString() {
- return "Cell[view=" + (cell == null ? "null" : cell.getClass()) + ", x=" + cellX +
- ", y=" + cellY + "]";
- }
- }
-}
-
-