diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 17e4a5b2dd..7257d86ddc 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -89,6 +89,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; +import java.util.List; import java.util.Stack; public class CellLayout extends ViewGroup { @@ -1809,7 +1811,7 @@ public class CellLayout extends ViewGroup { return bestXY; } - public boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop, + private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop, int[] direction, ItemConfiguration currentState) { CellAndSpan c = currentState.map.get(v); boolean success = false; @@ -1828,7 +1830,7 @@ public class CellLayout extends ViewGroup { return success; } - public boolean pushViewsToTempLocation(ArrayList views, Rect rectOccupiedByPotentialDrop, + private boolean pushViewsToTempLocation(ArrayList views, Rect rectOccupiedByPotentialDrop, int[] direction, View dragView, ItemConfiguration currentState) { ViewCluster cluster = new ViewCluster(this, views, currentState); @@ -1926,7 +1928,7 @@ public class CellLayout extends ViewGroup { // This method tries to find a reordering solution which satisfies the push mechanic by trying // to push items in each of the cardinal directions, in an order based on the direction vector // passed. - public boolean attemptPushInDirection(ArrayList intersectingViews, Rect occupied, + private boolean attemptPushInDirection(ArrayList intersectingViews, Rect occupied, int[] direction, View ignoreView, ItemConfiguration solution) { if ((Math.abs(direction[0]) + Math.abs(direction[1])) > 1) { // If the direction vector has two non-zero components, we try pushing @@ -2087,7 +2089,7 @@ public class CellLayout extends ViewGroup { } } - public boolean addViewsToTempLocation(ArrayList views, Rect rectOccupiedByPotentialDrop, + private boolean addViewsToTempLocation(ArrayList views, Rect rectOccupiedByPotentialDrop, int[] direction, View dragView, ItemConfiguration currentState) { if (views.size() == 0) return true; @@ -2138,6 +2140,71 @@ public class CellLayout extends ViewGroup { return success; } + public boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction, + View ignoreView, ItemConfiguration solution) { + // Return early if get invalid cell positions + if (cellX < 0 || cellY < 0) return false; + + mIntersectingViews.clear(); + mOccupiedRect.set(cellX, cellY, cellX + spanX, cellY + spanY); + + // Mark the desired location of the view currently being dragged. + if (ignoreView != null) { + CellAndSpan c = solution.map.get(ignoreView); + if (c != null) { + c.cellX = cellX; + c.cellY = cellY; + } + } + Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY); + Rect r1 = new Rect(); + // The views need to be sorted so that the results are deterministic on the views positions + // and not by the views hash which is "random". + // The views are sorted twice, once for the X position and a second time for the Y position + // to ensure same order everytime. + Comparator comparator = Comparator.comparing(view -> + ((CellLayoutLayoutParams) ((View) view).getLayoutParams()).getCellX()) + .thenComparing(view -> + ((CellLayoutLayoutParams) ((View) view).getLayoutParams()).getCellY()); + List views = solution.map.keySet().stream().sorted(comparator).toList(); + for (View child : views) { + if (child == ignoreView) continue; + CellAndSpan c = solution.map.get(child); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams(); + r1.set(c.cellX, c.cellY, c.cellX + c.spanX, c.cellY + c.spanY); + if (Rect.intersects(r0, r1)) { + if (!lp.canReorder) { + return false; + } + mIntersectingViews.add(child); + } + } + + solution.intersectingViews = new ArrayList<>(mIntersectingViews); + + // First we try to find a solution which respects the push mechanic. That is, + // we try to find a solution such that no displaced item travels through another item + // without also displacing that item. + if (attemptPushInDirection(mIntersectingViews, mOccupiedRect, direction, ignoreView, + solution)) { + return true; + } + + // Next we try moving the views as a block, but without requiring the push mechanic. + if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, ignoreView, + solution)) { + return true; + } + + // Ok, they couldn't move as a block, let's move them individually + for (View v : mIntersectingViews) { + if (!addViewToTempLocation(v, mOccupiedRect, direction, solution)) { + return false; + } + } + return true; + } + public ReorderAlgorithm createReorderAlgorithm() { return new ReorderAlgorithm(this); } @@ -2149,13 +2216,18 @@ public class CellLayout extends ViewGroup { spanX, spanY, direction, dragView, decX, solution); } - public void copyCurrentStateToSolution(ItemConfiguration solution) { + public void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) { int childCount = mShortcutsAndWidgets.getChildCount(); for (int i = 0; i < childCount; i++) { View child = mShortcutsAndWidgets.getChildAt(i); CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams(); - solution.add(child, - new CellAndSpan(lp.getCellX(), lp.getCellY(), lp.cellHSpan, lp.cellVSpan)); + CellAndSpan c; + if (temp) { + c = new CellAndSpan(lp.getTmpCellX(), lp.getTmpCellY(), lp.cellHSpan, lp.cellVSpan); + } else { + c = new CellAndSpan(lp.getCellX(), lp.getCellY(), lp.cellHSpan, lp.cellVSpan); + } + solution.add(child, c); } } diff --git a/src/com/android/launcher3/MultipageCellLayout.java b/src/com/android/launcher3/MultipageCellLayout.java index 5c5d71c635..123e8ca1e3 100644 --- a/src/com/android/launcher3/MultipageCellLayout.java +++ b/src/com/android/launcher3/MultipageCellLayout.java @@ -120,7 +120,7 @@ public class MultipageCellLayout extends CellLayout { } @Override - public void copyCurrentStateToSolution(ItemConfiguration solution) { + public void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) { int childCount = mShortcutsAndWidgets.getChildCount(); for (int i = 0; i < childCount; i++) { View child = mShortcutsAndWidgets.getChildAt(i); diff --git a/src/com/android/launcher3/celllayout/ReorderAlgorithm.java b/src/com/android/launcher3/celllayout/ReorderAlgorithm.java index 535dfe57a6..05bd13da81 100644 --- a/src/com/android/launcher3/celllayout/ReorderAlgorithm.java +++ b/src/com/android/launcher3/celllayout/ReorderAlgorithm.java @@ -19,11 +19,7 @@ import android.graphics.Rect; import android.view.View; import com.android.launcher3.CellLayout; -import com.android.launcher3.util.CellAndSpan; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; import java.util.Map.Entry; /** @@ -67,7 +63,7 @@ public class ReorderAlgorithm { int minSpanY, int spanX, int spanY, int[] direction, View dragView, boolean decX, ItemConfiguration solution) { // Copy the current state into the solution. This solution will be manipulated as necessary. - mCellLayout.copyCurrentStateToSolution(solution); + mCellLayout.copyCurrentStateToSolution(solution, false); // Copy the current occupied array into the temporary occupied array. This array will be // manipulated as necessary to find a solution. mCellLayout.getOccupied().copyTo(mCellLayout.mTmpOccupied); @@ -80,7 +76,7 @@ public class ReorderAlgorithm { boolean success; // First we try the exact nearest position of the item being dragged, // we will then want to try to move this around to other neighbouring positions - success = rearrangementExists(result[0], result[1], spanX, spanY, direction, + success = mCellLayout.rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView, solution); if (!success) { @@ -104,73 +100,6 @@ public class ReorderAlgorithm { return solution; } - private boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction, - View ignoreView, ItemConfiguration solution) { - // Return early if get invalid cell positions - if (cellX < 0 || cellY < 0) return false; - - ArrayList intersectingViews = new ArrayList<>(); - Rect occupiedRect = new Rect(cellX, cellY, cellX + spanX, cellY + spanY); - - // Mark the desired location of the view currently being dragged. - if (ignoreView != null) { - CellAndSpan c = solution.map.get(ignoreView); - if (c != null) { - c.cellX = cellX; - c.cellY = cellY; - } - } - Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY); - Rect r1 = new Rect(); - // The views need to be sorted so that the results are deterministic on the views positions - // and not by the views hash which is "random". - // The views are sorted twice, once for the X position and a second time for the Y position - // to ensure same order everytime. - Comparator comparator = Comparator.comparing(view -> - ((CellLayoutLayoutParams) ((View) view).getLayoutParams()).getCellX()) - .thenComparing(view -> - ((CellLayoutLayoutParams) ((View) view).getLayoutParams()).getCellY()); - List views = solution.map.keySet().stream().sorted(comparator).toList(); - for (View child : views) { - if (child == ignoreView) continue; - CellAndSpan c = solution.map.get(child); - CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams(); - r1.set(c.cellX, c.cellY, c.cellX + c.spanX, c.cellY + c.spanY); - if (Rect.intersects(r0, r1)) { - if (!lp.canReorder) { - return false; - } - intersectingViews.add(child); - } - } - - solution.intersectingViews = intersectingViews; - - // First we try to find a solution which respects the push mechanic. That is, - // we try to find a solution such that no displaced item travels through another item - // without also displacing that item. - if (mCellLayout.attemptPushInDirection(intersectingViews, occupiedRect, direction, - ignoreView, - solution)) { - return true; - } - - // Next we try moving the views as a block, but without requiring the push mechanic. - if (mCellLayout.addViewsToTempLocation(intersectingViews, occupiedRect, direction, - ignoreView, - solution)) { - return true; - } - - // Ok, they couldn't move as a block, let's move them individually - for (View v : intersectingViews) { - if (!mCellLayout.addViewToTempLocation(v, occupiedRect, direction, solution)) { - return false; - } - } - return true; - } - /** * Returns a "reorder" if there is empty space without rearranging anything. * @@ -186,7 +115,7 @@ public class ReorderAlgorithm { int[] result = mCellLayout.findNearestAreaIgnoreOccupied(pixelX, pixelY, spanX, spanY, new int[2]); ItemConfiguration solution = new ItemConfiguration(); - mCellLayout.copyCurrentStateToSolution(solution); + mCellLayout.copyCurrentStateToSolution(solution, false); solution.isSolution = !isConfigurationRegionOccupied( new Rect(result[0], result[1], result[0] + spanX, result[1] + spanY), @@ -232,7 +161,7 @@ public class ReorderAlgorithm { mCellLayout.findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, result, resultSpan); if (result[0] >= 0 && result[1] >= 0) { - mCellLayout.copyCurrentStateToSolution(solution); + mCellLayout.copyCurrentStateToSolution(solution, false); solution.cellX = result[0]; solution.cellY = result[1]; solution.spanX = resultSpan[0];