mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-20 11:18:21 +00:00
Decoupling finding the solution and animation of a reorder in CellLayout
Adding new functions to CellLayout, two of them return a solution (calculateReorder, getSimpleReorder) and the other one takes a solution and animates that solution (void performReorder) and it can either submit the solution or just show it for a preview. Right now this two things are done under the same function: int[] performReorder. The need to separate this two functions is because to add this functionality b/188081026 which needs to find soluion without animation and animation solutions that can be calculated in another place. Bug: 188081026 Test: atest ReorderWidgets Change-Id: Ib519d4346f58f9b55aff5008cd3ccbcfe8443d2d
This commit is contained in:
@@ -55,7 +55,6 @@ import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.core.view.ViewCompat;
|
||||
|
||||
@@ -193,7 +192,7 @@ public class CellLayout extends ViewGroup {
|
||||
private final Rect mOccupiedRect = new Rect();
|
||||
private final int[] mDirectionVector = new int[2];
|
||||
|
||||
final int[] mPreviousReorderDirection = new int[2];
|
||||
ItemConfiguration mPreviousSolution = null;
|
||||
private static final int INVALID_DIRECTION = -100;
|
||||
|
||||
private final Rect mTempRect = new Rect();
|
||||
@@ -247,9 +246,6 @@ public class CellLayout extends ViewGroup {
|
||||
mOccupied = new GridOccupancy(mCountX, mCountY);
|
||||
mTmpOccupied = new GridOccupancy(mCountX, mCountY);
|
||||
|
||||
mPreviousReorderDirection[0] = INVALID_DIRECTION;
|
||||
mPreviousReorderDirection[1] = INVALID_DIRECTION;
|
||||
|
||||
mFolderLeaveBehind.mDelegateCellX = -1;
|
||||
mFolderLeaveBehind.mDelegateCellY = -1;
|
||||
|
||||
@@ -2471,32 +2467,92 @@ public class CellLayout extends ViewGroup {
|
||||
}
|
||||
|
||||
int[] performReorder(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
|
||||
View dragView, int[] result, int resultSpan[], int mode) {
|
||||
// First we determine if things have moved enough to cause a different layout
|
||||
result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
|
||||
|
||||
View dragView, int[] result, int[] resultSpan, int mode) {
|
||||
if (resultSpan == null) {
|
||||
resultSpan = new int[2];
|
||||
resultSpan = new int[]{-1, -1};
|
||||
}
|
||||
if (result == null) {
|
||||
result = new int[]{-1, -1};
|
||||
}
|
||||
|
||||
ItemConfiguration finalSolution;
|
||||
// When we are checking drop validity or actually dropping, we don't recompute the
|
||||
// direction vector, since we want the solution to match the preview, and it's possible
|
||||
// that the exact position of the item has changed to result in a new reordering outcome.
|
||||
if ((mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL || mode == MODE_ACCEPT_DROP)
|
||||
&& mPreviousReorderDirection[0] != INVALID_DIRECTION) {
|
||||
mDirectionVector[0] = mPreviousReorderDirection[0];
|
||||
mDirectionVector[1] = mPreviousReorderDirection[1];
|
||||
&& mPreviousSolution != null) {
|
||||
finalSolution = mPreviousSolution;
|
||||
// We reset this vector after drop
|
||||
if (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
|
||||
mPreviousReorderDirection[0] = INVALID_DIRECTION;
|
||||
mPreviousReorderDirection[1] = INVALID_DIRECTION;
|
||||
mPreviousSolution = null;
|
||||
}
|
||||
} else {
|
||||
getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector);
|
||||
mPreviousReorderDirection[0] = mDirectionVector[0];
|
||||
mPreviousReorderDirection[1] = mDirectionVector[1];
|
||||
finalSolution = calculateReorder(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY,
|
||||
dragView);
|
||||
mPreviousSolution = finalSolution;
|
||||
}
|
||||
|
||||
if (finalSolution == null || !finalSolution.isSolution) {
|
||||
result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1;
|
||||
} else {
|
||||
result[0] = finalSolution.cellX;
|
||||
result[1] = finalSolution.cellY;
|
||||
resultSpan[0] = finalSolution.spanX;
|
||||
resultSpan[1] = finalSolution.spanY;
|
||||
}
|
||||
performReorder(finalSolution, dragView, mode);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a "reorder" where we simply drop the item in the closest empty space, without moving
|
||||
* any other item in the way.
|
||||
*
|
||||
* @param pixelX X coordinate in pixels in the screen
|
||||
* @param pixelY Y coordinate in pixels in the screen
|
||||
* @param spanX horizontal cell span
|
||||
* @param spanY vertical cell span
|
||||
* @return the configuration that represents the found reorder
|
||||
*/
|
||||
public ItemConfiguration closestEmptySpaceReorder(int pixelX, int pixelY, int spanX,
|
||||
int spanY) {
|
||||
int[] result = new int[2];
|
||||
result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
|
||||
ItemConfiguration solution = new ItemConfiguration();
|
||||
copyCurrentStateToSolution(solution, false);
|
||||
solution.isSolution = result[0] != -1;
|
||||
if (!solution.isSolution) {
|
||||
return solution;
|
||||
}
|
||||
solution.cellX = result[0];
|
||||
solution.cellY = result[1];
|
||||
solution.spanX = spanX;
|
||||
solution.spanY = spanY;
|
||||
return solution;
|
||||
}
|
||||
|
||||
/**
|
||||
* When the user drags an Item in the workspace sometimes we need to move the items already in
|
||||
* the workspace to make space for the new item, this function return a solution for that
|
||||
* reorder.
|
||||
*
|
||||
* @param pixelX X coordinate in the screen of the dragView in pixels
|
||||
* @param pixelY Y coordinate in the screen of the dragView in pixels
|
||||
* @param minSpanX minimum horizontal span the item can be shrunk to
|
||||
* @param minSpanY minimum vertical span the item can be shrunk to
|
||||
* @param spanX occupied horizontal span
|
||||
* @param spanY occupied vertical span
|
||||
* @param dragView the view of the item being draged
|
||||
* @return returns a solution for the given parameters, the solution contains all the icons and
|
||||
* the locations they should be in the given solution.
|
||||
*/
|
||||
public ItemConfiguration calculateReorder(int pixelX, int pixelY, int minSpanX, int minSpanY,
|
||||
int spanX, int spanY, View dragView) {
|
||||
getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector);
|
||||
|
||||
ItemConfiguration closestSpaceSolution = closestEmptySpaceReorder(pixelX, pixelY, spanX,
|
||||
spanY);
|
||||
|
||||
// Find a solution involving pushing / displacing any items in the way
|
||||
ItemConfiguration swapSolution = findReorderSolution(pixelX, pixelY, minSpanX, minSpanY,
|
||||
spanX, spanY, mDirectionVector, dragView, true, new ItemConfiguration());
|
||||
@@ -2505,73 +2561,67 @@ public class CellLayout extends ViewGroup {
|
||||
ItemConfiguration noShuffleSolution = findConfigurationNoShuffle(pixelX, pixelY, minSpanX,
|
||||
minSpanY, spanX, spanY, dragView, new ItemConfiguration());
|
||||
|
||||
ItemConfiguration finalSolution = null;
|
||||
|
||||
// If the reorder solution requires resizing (shrinking) the item being dropped, we instead
|
||||
// favor a solution in which the item is not resized, but
|
||||
if (swapSolution.isSolution && swapSolution.area() >= noShuffleSolution.area()) {
|
||||
finalSolution = swapSolution;
|
||||
return swapSolution;
|
||||
} else if (noShuffleSolution.isSolution) {
|
||||
finalSolution = noShuffleSolution;
|
||||
return noShuffleSolution;
|
||||
} else if (closestSpaceSolution.isSolution) {
|
||||
return closestSpaceSolution;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Animates and submits in the DB the given ItemConfiguration depending of the mode.
|
||||
*
|
||||
* @param solution represents widgets on the screen which the Workspace will animate to and
|
||||
* would be submitted to the database.
|
||||
* @param dragView view which is being dragged over the workspace that trigger the reorder
|
||||
* @param mode depending on the mode different animations would be played and depending on the
|
||||
* mode the solution would be submitted or not the database.
|
||||
* The possible modes are {@link MODE_SHOW_REORDER_HINT}, {@link MODE_DRAG_OVER},
|
||||
* {@link MODE_ON_DROP}, {@link MODE_ON_DROP_EXTERNAL}, {@link MODE_ACCEPT_DROP}
|
||||
* defined in {@link CellLayout}.
|
||||
*/
|
||||
void performReorder(ItemConfiguration solution, View dragView, int mode) {
|
||||
if (mode == MODE_SHOW_REORDER_HINT) {
|
||||
if (finalSolution != null) {
|
||||
beginOrAdjustReorderPreviewAnimations(finalSolution, dragView,
|
||||
ReorderPreviewAnimation.MODE_HINT);
|
||||
result[0] = finalSolution.cellX;
|
||||
result[1] = finalSolution.cellY;
|
||||
resultSpan[0] = finalSolution.spanX;
|
||||
resultSpan[1] = finalSolution.spanY;
|
||||
beginOrAdjustReorderPreviewAnimations(solution, dragView,
|
||||
ReorderPreviewAnimation.MODE_HINT);
|
||||
return;
|
||||
}
|
||||
// If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother
|
||||
// committing anything or animating anything as we just want to determine if a solution
|
||||
// exists
|
||||
if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
|
||||
if (!DESTRUCTIVE_REORDER) {
|
||||
setUseTempCoords(true);
|
||||
}
|
||||
|
||||
if (!DESTRUCTIVE_REORDER) {
|
||||
copySolutionToTempState(solution, dragView);
|
||||
}
|
||||
setItemPlacementDirty(true);
|
||||
animateItemsToSolution(solution, dragView, mode == MODE_ON_DROP);
|
||||
|
||||
if (!DESTRUCTIVE_REORDER
|
||||
&& (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL)) {
|
||||
// Since the temp solution didn't update dragView, don't commit it either
|
||||
commitTempPlacement(dragView);
|
||||
completeAndClearReorderPreviewAnimations();
|
||||
setItemPlacementDirty(false);
|
||||
} else {
|
||||
result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1;
|
||||
beginOrAdjustReorderPreviewAnimations(solution, dragView,
|
||||
ReorderPreviewAnimation.MODE_PREVIEW);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
boolean foundSolution = true;
|
||||
if (!DESTRUCTIVE_REORDER) {
|
||||
setUseTempCoords(true);
|
||||
}
|
||||
|
||||
if (finalSolution != null) {
|
||||
result[0] = finalSolution.cellX;
|
||||
result[1] = finalSolution.cellY;
|
||||
resultSpan[0] = finalSolution.spanX;
|
||||
resultSpan[1] = finalSolution.spanY;
|
||||
|
||||
// If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother
|
||||
// committing anything or animating anything as we just want to determine if a solution
|
||||
// exists
|
||||
if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
|
||||
if (!DESTRUCTIVE_REORDER) {
|
||||
copySolutionToTempState(finalSolution, dragView);
|
||||
}
|
||||
setItemPlacementDirty(true);
|
||||
animateItemsToSolution(finalSolution, dragView, mode == MODE_ON_DROP);
|
||||
|
||||
if (!DESTRUCTIVE_REORDER &&
|
||||
(mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL)) {
|
||||
// Since the temp solution didn't update dragView, don't commit it either
|
||||
commitTempPlacement(dragView);
|
||||
completeAndClearReorderPreviewAnimations();
|
||||
setItemPlacementDirty(false);
|
||||
} else {
|
||||
beginOrAdjustReorderPreviewAnimations(finalSolution, dragView,
|
||||
ReorderPreviewAnimation.MODE_PREVIEW);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foundSolution = false;
|
||||
result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1;
|
||||
}
|
||||
|
||||
if ((mode == MODE_ON_DROP || !foundSolution) && !DESTRUCTIVE_REORDER) {
|
||||
if (mode == MODE_ON_DROP && !DESTRUCTIVE_REORDER) {
|
||||
setUseTempCoords(false);
|
||||
}
|
||||
|
||||
mShortcutsAndWidgets.requestLayout();
|
||||
return result;
|
||||
}
|
||||
|
||||
void setItemPlacementDirty(boolean dirty) {
|
||||
|
||||
Reference in New Issue
Block a user