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
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 11b263d..7d15f7b 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -1741,140 +1741,6 @@
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 5c5d71c..0ec9034 100644
--- a/src/com/android/launcher3/MultipageCellLayout.java
+++ b/src/com/android/launcher3/MultipageCellLayout.java
@@ -56,17 +56,6 @@
}
@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 6682f32..7385c0a 100644
--- a/src/com/android/launcher3/celllayout/ReorderAlgorithm.java
+++ b/src/com/android/launcher3/celllayout/ReorderAlgorithm.java
@@ -187,8 +187,8 @@
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 @@
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 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 @@
}
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;
+ }
}