diff options
author | 2023-12-01 12:45:23 -0600 | |
---|---|---|
committer | 2023-12-01 12:50:13 -0600 | |
commit | dcf6bf2311ae9b6c7d933d1df7babb12e1a7ab9c (patch) | |
tree | 2a15fcdff0b026a4d13a2464f9135c815cab56bf | |
parent | f601447877680b391841920a203355f491c12674 (diff) |
Moving the remainder of reorder logic to ReorderAlgorithm
This is a no-op thoroughly tested by ReorderAlgorithmUnitTest.
Flag: NA
Bug: 229292911
Test: ReorderAlgorithmUnitTest
Change-Id: I7203444df289cd3b67794fc570a2cd46e64549a2
-rw-r--r-- | src/com/android/launcher3/CellLayout.java | 134 | ||||
-rw-r--r-- | src/com/android/launcher3/MultipageCellLayout.java | 11 | ||||
-rw-r--r-- | src/com/android/launcher3/celllayout/ReorderAlgorithm.java | 145 |
3 files changed, 141 insertions, 149 deletions
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 11b263decd..7d15f7b7c0 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -1741,140 +1741,6 @@ public class CellLayout extends ViewGroup { return swapSolution.isSolution; } - /** - * Find a vacant area that will fit the given bounds nearest the requested - * cell location, and will also weigh in a suggested direction vector of the - * desired location. This method computers distance based on unit grid distances, - * not pixel distances. - * - * @param cellX The X cell nearest to which you want to search for a vacant area. - * @param cellY The Y cell nearest which you want to search for a vacant area. - * @param spanX Horizontal span of the object. - * @param spanY Vertical span of the object. - * @param direction The favored direction in which the views should move from x, y - * @param occupied The array which represents which cells in the CellLayout are occupied - * @param blockOccupied The array which represents which cells in the specified block (cellX, - * cellY, spanX, spanY) are occupied. This is used when try to move a group of views. - * @param result Array in which to place the result, or null (in which case a new array will - * be allocated) - * @return The X, Y cell of a vacant area that can contain this object, - * nearest the requested location. - */ - public int[] findNearestArea(int cellX, int cellY, int spanX, int spanY, int[] direction, - boolean[][] occupied, boolean blockOccupied[][], int[] result) { - // Keep track of best-scoring drop area - final int[] bestXY = result != null ? result : new int[2]; - float bestDistance = Float.MAX_VALUE; - int bestDirectionScore = Integer.MIN_VALUE; - - final int countX = mCountX; - final int countY = mCountY; - - for (int y = 0; y < countY - (spanY - 1); y++) { - inner: - for (int x = 0; x < countX - (spanX - 1); x++) { - // First, let's see if this thing fits anywhere - for (int i = 0; i < spanX; i++) { - for (int j = 0; j < spanY; j++) { - if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) { - continue inner; - } - } - } - - float distance = (float) Math.hypot(x - cellX, y - cellY); - int[] curDirection = mTmpPoint; - computeDirectionVector(x - cellX, y - cellY, curDirection); - // The direction score is just the dot product of the two candidate direction - // and that passed in. - int curDirectionScore = direction[0] * curDirection[0] + - direction[1] * curDirection[1]; - if (Float.compare(distance, bestDistance) < 0 || - (Float.compare(distance, bestDistance) == 0 - && curDirectionScore > bestDirectionScore)) { - bestDistance = distance; - bestDirectionScore = curDirectionScore; - bestXY[0] = x; - bestXY[1] = y; - } - } - } - - // Return -1, -1 if no suitable location found - if (bestDistance == Float.MAX_VALUE) { - bestXY[0] = -1; - bestXY[1] = -1; - } - return bestXY; - } - - /* - * Returns a pair (x, y), where x,y are in {-1, 0, 1} corresponding to vector between - * the provided point and the provided cell - */ - private void computeDirectionVector(float deltaX, float deltaY, int[] result) { - double angle = Math.atan(deltaY / deltaX); - - result[0] = 0; - result[1] = 0; - if (Math.abs(Math.cos(angle)) > 0.5f) { - result[0] = (int) Math.signum(deltaX); - } - if (Math.abs(Math.sin(angle)) > 0.5f) { - result[1] = (int) Math.signum(deltaY); - } - } - - /* This seems like it should be obvious and straight-forward, but when the direction vector - needs to match with the notion of the dragView pushing other views, we have to employ - a slightly more subtle notion of the direction vector. The question is what two points is - the vector between? The center of the dragView and its desired destination? Not quite, as - this doesn't necessarily coincide with the interaction of the dragView and items occupying - those cells. Instead we use some heuristics to often lock the vector to up, down, left - or right, which helps make pushing feel right. - */ - public void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX, - int spanY, View dragView, int[] resultDirection) { - - //TODO(adamcohen) b/151776141 use the items visual center for the direction vector - int[] targetDestination = new int[2]; - - findNearestAreaIgnoreOccupied(dragViewCenterX, dragViewCenterY, spanX, spanY, - targetDestination); - Rect dragRect = new Rect(); - cellToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect); - dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY()); - - Rect region = new Rect(targetDestination[0], targetDestination[1], - targetDestination[0] + spanX, targetDestination[1] + spanY); - Rect dropRegionRect = getIntersectingRectanglesInRegion(region, dragView); - if (dropRegionRect == null) dropRegionRect = new Rect(region); - - int dropRegionSpanX = dropRegionRect.width(); - int dropRegionSpanY = dropRegionRect.height(); - - cellToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(), - dropRegionRect.height(), dropRegionRect); - - int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX; - int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY; - - if (dropRegionSpanX == mCountX || spanX == mCountX) { - deltaX = 0; - } - if (dropRegionSpanY == mCountY || spanY == mCountY) { - deltaY = 0; - } - - if (deltaX == 0 && deltaY == 0) { - // No idea what to do, give a random direction. - resultDirection[0] = 1; - resultDirection[1] = 0; - } else { - computeDirectionVector(deltaX, deltaY, resultDirection); - } - } - public ReorderAlgorithm createReorderAlgorithm() { return new ReorderAlgorithm(this); } diff --git a/src/com/android/launcher3/MultipageCellLayout.java b/src/com/android/launcher3/MultipageCellLayout.java index 5c5d71c635..0ec9034cc7 100644 --- a/src/com/android/launcher3/MultipageCellLayout.java +++ b/src/com/android/launcher3/MultipageCellLayout.java @@ -56,17 +56,6 @@ public class MultipageCellLayout extends CellLayout { } @Override - public void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX, - int spanY, View dragView, int[] resultDirection) { - createReorderAlgorithm().simulateSeam( - () -> { - super.getDirectionVectorForDrop(dragViewCenterX, dragViewCenterY, spanX, spanY, - dragView, resultDirection); - return 0; - }); - } - - @Override public boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY, View dragView, int[] result) { return createReorderAlgorithm().simulateSeam( diff --git a/src/com/android/launcher3/celllayout/ReorderAlgorithm.java b/src/com/android/launcher3/celllayout/ReorderAlgorithm.java index 6682f32873..7385c0a3cf 100644 --- a/src/com/android/launcher3/celllayout/ReorderAlgorithm.java +++ b/src/com/android/launcher3/celllayout/ReorderAlgorithm.java @@ -187,8 +187,8 @@ public class ReorderAlgorithm { mCellLayout.mTmpOccupied.markCells(c, false); mCellLayout.mTmpOccupied.markCells(rectOccupiedByPotentialDrop, true); - int[] tmpLocation = mCellLayout.findNearestArea(c.cellX, c.cellY, c.spanX, c.spanY, - direction, mCellLayout.mTmpOccupied.cells, null, new int[2]); + int[] tmpLocation = findNearestArea(c.cellX, c.cellY, c.spanX, c.spanY, direction, + mCellLayout.mTmpOccupied.cells, null, new int[2]); if (tmpLocation[0] >= 0 && tmpLocation[1] >= 0) { c.cellX = tmpLocation[0]; @@ -419,7 +419,7 @@ public class ReorderAlgorithm { mCellLayout.mTmpOccupied.markCells(rectOccupiedByPotentialDrop, true); - int[] tmpLocation = mCellLayout.findNearestArea(boundingRect.left, boundingRect.top, + int[] tmpLocation = findNearestArea(boundingRect.left, boundingRect.top, boundingRect.width(), boundingRect.height(), direction, mCellLayout.mTmpOccupied.cells, blockOccupied.cells, new int[2]); @@ -533,7 +533,7 @@ public class ReorderAlgorithm { */ public ItemConfiguration calculateReorder(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, View dragView) { - mCellLayout.getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, + getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mCellLayout.mDirectionVector); ItemConfiguration dropInPlaceSolution = dropInPlaceSolution(pixelX, pixelY, spanX, spanY, @@ -559,4 +559,141 @@ public class ReorderAlgorithm { } return null; } + + /* + * Returns a pair (x, y), where x,y are in {-1, 0, 1} corresponding to vector between + * the provided point and the provided cell + */ + private void computeDirectionVector(float deltaX, float deltaY, int[] result) { + double angle = Math.atan(deltaY / deltaX); + + result[0] = 0; + result[1] = 0; + if (Math.abs(Math.cos(angle)) > 0.5f) { + result[0] = (int) Math.signum(deltaX); + } + if (Math.abs(Math.sin(angle)) > 0.5f) { + result[1] = (int) Math.signum(deltaY); + } + } + + /** + * This seems like it should be obvious and straight-forward, but when the direction vector + * needs to match with the notion of the dragView pushing other views, we have to employ + * a slightly more subtle notion of the direction vector. The question is what two points is + * the vector between? The center of the dragView and its desired destination? Not quite, as + * this doesn't necessarily coincide with the interaction of the dragView and items occupying + * those cells. Instead we use some heuristics to often lock the vector to up, down, left + * or right, which helps make pushing feel right. + */ + private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX, + int spanY, View dragView, int[] resultDirection) { + + //TODO(adamcohen) b/151776141 use the items visual center for the direction vector + int[] targetDestination = new int[2]; + + mCellLayout.findNearestAreaIgnoreOccupied(dragViewCenterX, dragViewCenterY, spanX, spanY, + targetDestination); + Rect dragRect = new Rect(); + mCellLayout.cellToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect); + dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY()); + + Rect region = new Rect(targetDestination[0], targetDestination[1], + targetDestination[0] + spanX, targetDestination[1] + spanY); + Rect dropRegionRect = mCellLayout.getIntersectingRectanglesInRegion(region, dragView); + if (dropRegionRect == null) dropRegionRect = new Rect(region); + + int dropRegionSpanX = dropRegionRect.width(); + int dropRegionSpanY = dropRegionRect.height(); + + mCellLayout.cellToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(), + dropRegionRect.height(), dropRegionRect); + + int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX; + int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY; + + if (dropRegionSpanX == mCellLayout.getCountX() || spanX == mCellLayout.getCountX()) { + deltaX = 0; + } + if (dropRegionSpanY == mCellLayout.getCountY() || spanY == mCellLayout.getCountY()) { + deltaY = 0; + } + + if (deltaX == 0 && deltaY == 0) { + // No idea what to do, give a random direction. + resultDirection[0] = 1; + resultDirection[1] = 0; + } else { + computeDirectionVector(deltaX, deltaY, resultDirection); + } + } + + /** + * Find a vacant area that will fit the given bounds nearest the requested + * cell location, and will also weigh in a suggested direction vector of the + * desired location. This method computers distance based on unit grid distances, + * not pixel distances. + * + * @param cellX The X cell nearest to which you want to search for a vacant area. + * @param cellY The Y cell nearest which you want to search for a vacant area. + * @param spanX Horizontal span of the object. + * @param spanY Vertical span of the object. + * @param direction The favored direction in which the views should move from x, y + * @param occupied The array which represents which cells in the CellLayout are occupied + * @param blockOccupied The array which represents which cells in the specified block (cellX, + * cellY, spanX, spanY) are occupied. This is used when try to move a group + * of views. + * @param result Array in which to place the result, or null (in which case a new array + * will + * be allocated) + * @return The X, Y cell of a vacant area that can contain this object, + * nearest the requested location. + */ + public int[] findNearestArea(int cellX, int cellY, int spanX, int spanY, int[] direction, + boolean[][] occupied, boolean[][] blockOccupied, int[] result) { + // Keep track of best-scoring drop area + final int[] bestXY = result != null ? result : new int[2]; + float bestDistance = Float.MAX_VALUE; + int bestDirectionScore = Integer.MIN_VALUE; + + final int countX = mCellLayout.getCountX(); + final int countY = mCellLayout.getCountY(); + + for (int y = 0; y < countY - (spanY - 1); y++) { + inner: + for (int x = 0; x < countX - (spanX - 1); x++) { + // First, let's see if this thing fits anywhere + for (int i = 0; i < spanX; i++) { + for (int j = 0; j < spanY; j++) { + if (occupied[x + i][y + j] && (blockOccupied == null + || blockOccupied[i][j])) { + continue inner; + } + } + } + + float distance = (float) Math.hypot(x - cellX, y - cellY); + int[] curDirection = new int[2]; + computeDirectionVector(x - cellX, y - cellY, curDirection); + // The direction score is just the dot product of the two candidate direction + // and that passed in. + int curDirectionScore = + direction[0] * curDirection[0] + direction[1] * curDirection[1]; + if (Float.compare(distance, bestDistance) < 0 || (Float.compare(distance, + bestDistance) == 0 && curDirectionScore > bestDirectionScore)) { + bestDistance = distance; + bestDirectionScore = curDirectionScore; + bestXY[0] = x; + bestXY[1] = y; + } + } + } + + // Return -1, -1 if no suitable location found + if (bestDistance == Float.MAX_VALUE) { + bestXY[0] = -1; + bestXY[1] = -1; + } + return bestXY; + } } |