Loading src/com/android/launcher3/CellLayout.java +7 −79 Original line number Diff line number Diff line Loading @@ -89,8 +89,6 @@ 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 { Loading Loading @@ -1811,7 +1809,7 @@ public class CellLayout extends ViewGroup { return bestXY; } private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop, public boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop, int[] direction, ItemConfiguration currentState) { CellAndSpan c = currentState.map.get(v); boolean success = false; Loading @@ -1830,7 +1828,7 @@ public class CellLayout extends ViewGroup { return success; } private boolean pushViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, public boolean pushViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, int[] direction, View dragView, ItemConfiguration currentState) { ViewCluster cluster = new ViewCluster(this, views, currentState); Loading Loading @@ -1928,7 +1926,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. private boolean attemptPushInDirection(ArrayList<View> intersectingViews, Rect occupied, public boolean attemptPushInDirection(ArrayList<View> 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 Loading Loading @@ -2089,7 +2087,7 @@ public class CellLayout extends ViewGroup { } } private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, public boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, int[] direction, View dragView, ItemConfiguration currentState) { if (views.size() == 0) return true; Loading Loading @@ -2140,71 +2138,6 @@ 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<View> 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); } Loading @@ -2216,18 +2149,13 @@ public class CellLayout extends ViewGroup { spanX, spanY, direction, dragView, decX, solution); } public void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) { public void copyCurrentStateToSolution(ItemConfiguration solution) { int childCount = mShortcutsAndWidgets.getChildCount(); for (int i = 0; i < childCount; i++) { View child = mShortcutsAndWidgets.getChildAt(i); CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams(); 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); solution.add(child, new CellAndSpan(lp.getCellX(), lp.getCellY(), lp.cellHSpan, lp.cellVSpan)); } } Loading src/com/android/launcher3/MultipageCellLayout.java +1 −1 Original line number Diff line number Diff line Loading @@ -120,7 +120,7 @@ public class MultipageCellLayout extends CellLayout { } @Override public void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) { public void copyCurrentStateToSolution(ItemConfiguration solution) { int childCount = mShortcutsAndWidgets.getChildCount(); for (int i = 0; i < childCount; i++) { View child = mShortcutsAndWidgets.getChildAt(i); Loading src/com/android/launcher3/celllayout/ReorderAlgorithm.java +75 −4 Original line number Diff line number Diff line Loading @@ -19,7 +19,11 @@ 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; /** Loading Loading @@ -71,7 +75,7 @@ public class ReorderAlgorithm { int minSpanX, 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, false); mCellLayout.copyCurrentStateToSolution(solution); // 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); Loading @@ -84,7 +88,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 = mCellLayout.rearrangementExists(result[0], result[1], spanX, spanY, direction, success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView, solution); if (!success) { Loading @@ -108,6 +112,73 @@ 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<View> 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<View> 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. * Loading @@ -123,7 +194,7 @@ public class ReorderAlgorithm { int[] result = mCellLayout.findNearestAreaIgnoreOccupied(pixelX, pixelY, spanX, spanY, new int[2]); ItemConfiguration solution = new ItemConfiguration(); mCellLayout.copyCurrentStateToSolution(solution, false); mCellLayout.copyCurrentStateToSolution(solution); solution.isSolution = !isConfigurationRegionOccupied( new Rect(result[0], result[1], result[0] + spanX, result[1] + spanY), Loading Loading @@ -169,7 +240,7 @@ public class ReorderAlgorithm { mCellLayout.findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, result, resultSpan); if (result[0] >= 0 && result[1] >= 0) { mCellLayout.copyCurrentStateToSolution(solution, false); mCellLayout.copyCurrentStateToSolution(solution); solution.cellX = result[0]; solution.cellY = result[1]; solution.spanX = resultSpan[0]; Loading Loading
src/com/android/launcher3/CellLayout.java +7 −79 Original line number Diff line number Diff line Loading @@ -89,8 +89,6 @@ 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 { Loading Loading @@ -1811,7 +1809,7 @@ public class CellLayout extends ViewGroup { return bestXY; } private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop, public boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop, int[] direction, ItemConfiguration currentState) { CellAndSpan c = currentState.map.get(v); boolean success = false; Loading @@ -1830,7 +1828,7 @@ public class CellLayout extends ViewGroup { return success; } private boolean pushViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, public boolean pushViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, int[] direction, View dragView, ItemConfiguration currentState) { ViewCluster cluster = new ViewCluster(this, views, currentState); Loading Loading @@ -1928,7 +1926,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. private boolean attemptPushInDirection(ArrayList<View> intersectingViews, Rect occupied, public boolean attemptPushInDirection(ArrayList<View> 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 Loading Loading @@ -2089,7 +2087,7 @@ public class CellLayout extends ViewGroup { } } private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, public boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, int[] direction, View dragView, ItemConfiguration currentState) { if (views.size() == 0) return true; Loading Loading @@ -2140,71 +2138,6 @@ 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<View> 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); } Loading @@ -2216,18 +2149,13 @@ public class CellLayout extends ViewGroup { spanX, spanY, direction, dragView, decX, solution); } public void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) { public void copyCurrentStateToSolution(ItemConfiguration solution) { int childCount = mShortcutsAndWidgets.getChildCount(); for (int i = 0; i < childCount; i++) { View child = mShortcutsAndWidgets.getChildAt(i); CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams(); 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); solution.add(child, new CellAndSpan(lp.getCellX(), lp.getCellY(), lp.cellHSpan, lp.cellVSpan)); } } Loading
src/com/android/launcher3/MultipageCellLayout.java +1 −1 Original line number Diff line number Diff line Loading @@ -120,7 +120,7 @@ public class MultipageCellLayout extends CellLayout { } @Override public void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) { public void copyCurrentStateToSolution(ItemConfiguration solution) { int childCount = mShortcutsAndWidgets.getChildCount(); for (int i = 0; i < childCount; i++) { View child = mShortcutsAndWidgets.getChildAt(i); Loading
src/com/android/launcher3/celllayout/ReorderAlgorithm.java +75 −4 Original line number Diff line number Diff line Loading @@ -19,7 +19,11 @@ 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; /** Loading Loading @@ -71,7 +75,7 @@ public class ReorderAlgorithm { int minSpanX, 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, false); mCellLayout.copyCurrentStateToSolution(solution); // 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); Loading @@ -84,7 +88,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 = mCellLayout.rearrangementExists(result[0], result[1], spanX, spanY, direction, success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView, solution); if (!success) { Loading @@ -108,6 +112,73 @@ 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<View> 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<View> 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. * Loading @@ -123,7 +194,7 @@ public class ReorderAlgorithm { int[] result = mCellLayout.findNearestAreaIgnoreOccupied(pixelX, pixelY, spanX, spanY, new int[2]); ItemConfiguration solution = new ItemConfiguration(); mCellLayout.copyCurrentStateToSolution(solution, false); mCellLayout.copyCurrentStateToSolution(solution); solution.isSolution = !isConfigurationRegionOccupied( new Rect(result[0], result[1], result[0] + spanX, result[1] + spanY), Loading Loading @@ -169,7 +240,7 @@ public class ReorderAlgorithm { mCellLayout.findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, result, resultSpan); if (result[0] >= 0 && result[1] >= 0) { mCellLayout.copyCurrentStateToSolution(solution, false); mCellLayout.copyCurrentStateToSolution(solution); solution.cellX = result[0]; solution.cellY = result[1]; solution.spanX = resultSpan[0]; Loading