e4c0345747
ReorderAlgorithm will now handle all the logic associated with the reorder. Basically all the logic associated with a reorder in CellLayout was copy and pasted into ReorderAlgorithm.java. Test: atest TestReorderAlgorithm Bug: 229292911 Change-Id: Ie096abc346bf705414e47452a42d1dec5be0a041
205 lines
9.1 KiB
Java
205 lines
9.1 KiB
Java
/*
|
|
* Copyright (C) 2023 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package com.android.launcher3.celllayout;
|
|
|
|
import android.view.View;
|
|
|
|
import com.android.launcher3.CellLayout;
|
|
|
|
/**
|
|
* Contains the logic of a reorder.
|
|
*
|
|
* The content of this class was extracted from {@link CellLayout} and should mimic the exact
|
|
* same behaviour.
|
|
*/
|
|
public class ReorderAlgorithm {
|
|
|
|
CellLayout mCellLayout;
|
|
|
|
public ReorderAlgorithm(CellLayout cellLayout) {
|
|
mCellLayout = cellLayout;
|
|
}
|
|
|
|
/**
|
|
* This method differs from closestEmptySpaceReorder and dropInPlaceSolution because this method
|
|
* will move items around and will change the shape of the item if possible to try to find a
|
|
* solution.
|
|
*
|
|
* When changing the size of the widget this method will try first subtracting -1 in the x
|
|
* dimension and then subtracting -1 in the y dimension until finding a possible solution or
|
|
* until it no longer can reduce the span.
|
|
*
|
|
* @param pixelX X coordinate in pixels in the screen
|
|
* @param pixelY Y coordinate in pixels in the screen
|
|
* @param minSpanX minimum possible horizontal span it will try to find a solution for.
|
|
* @param minSpanY minimum possible vertical span it will try to find a solution for.
|
|
* @param spanX horizontal cell span
|
|
* @param spanY vertical cell span
|
|
* @param direction direction in which it will try to push the items intersecting the desired
|
|
* view
|
|
* @param dragView view being dragged in reorder
|
|
* @param decX whether it will decrease the horizontal or vertical span if it can't find a
|
|
* solution for the current span.
|
|
* @param solution variable to store the solution
|
|
* @return the same solution variable
|
|
*/
|
|
public CellLayout.ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX,
|
|
int minSpanY, int spanX, int spanY, int[] direction, View dragView, boolean decX,
|
|
CellLayout.ItemConfiguration solution) {
|
|
// Copy the current state into the solution. This solution will be manipulated as necessary.
|
|
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);
|
|
|
|
// We find the nearest cell into which we would place the dragged item, assuming there's
|
|
// nothing in its way.
|
|
int[] result = new int[2];
|
|
result = mCellLayout.findNearestAreaIgnoreOccupied(pixelX, pixelY, spanX, spanY, result);
|
|
|
|
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,
|
|
dragView, solution);
|
|
|
|
if (!success) {
|
|
// We try shrinking the widget down to size in an alternating pattern, shrink 1 in
|
|
// x, then 1 in y etc.
|
|
if (spanX > minSpanX && (minSpanY == spanY || decX)) {
|
|
return findReorderSolution(pixelX, pixelY, minSpanX, minSpanY, spanX - 1, spanY,
|
|
direction, dragView, false, solution);
|
|
} else if (spanY > minSpanY) {
|
|
return findReorderSolution(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY - 1,
|
|
direction, dragView, true, solution);
|
|
}
|
|
solution.isSolution = false;
|
|
} else {
|
|
solution.isSolution = true;
|
|
solution.cellX = result[0];
|
|
solution.cellY = result[1];
|
|
solution.spanX = spanX;
|
|
solution.spanY = spanY;
|
|
}
|
|
return solution;
|
|
}
|
|
|
|
/**
|
|
* Returns a "reorder" if there is empty space without rearranging anything.
|
|
*
|
|
* @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
|
|
* @param dragView view being dragged in reorder
|
|
* @return the configuration that represents the found reorder
|
|
*/
|
|
public CellLayout.ItemConfiguration dropInPlaceSolution(int pixelX, int pixelY, int spanX,
|
|
int spanY, View dragView) {
|
|
int[] result = new int[2];
|
|
if (mCellLayout.isNearestDropLocationOccupied(pixelX, pixelY, spanX, spanY, dragView,
|
|
result)) {
|
|
result[0] = result[1] = -1;
|
|
}
|
|
CellLayout.ItemConfiguration solution = new CellLayout.ItemConfiguration();
|
|
mCellLayout.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;
|
|
}
|
|
|
|
/**
|
|
* 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 CellLayout.ItemConfiguration closestEmptySpaceReorder(int pixelX, int pixelY,
|
|
int minSpanX, int minSpanY, int spanX, int spanY) {
|
|
CellLayout.ItemConfiguration solution = new CellLayout.ItemConfiguration();
|
|
int[] result = new int[2];
|
|
int[] resultSpan = new int[2];
|
|
mCellLayout.findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, result,
|
|
resultSpan);
|
|
if (result[0] >= 0 && result[1] >= 0) {
|
|
mCellLayout.copyCurrentStateToSolution(solution, false);
|
|
solution.cellX = result[0];
|
|
solution.cellY = result[1];
|
|
solution.spanX = resultSpan[0];
|
|
solution.spanY = resultSpan[1];
|
|
solution.isSolution = true;
|
|
} else {
|
|
solution.isSolution = false;
|
|
}
|
|
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 CellLayout.ItemConfiguration calculateReorder(int pixelX, int pixelY, int minSpanX,
|
|
int minSpanY, int spanX, int spanY, View dragView) {
|
|
mCellLayout.getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView,
|
|
mCellLayout.mDirectionVector);
|
|
|
|
CellLayout.ItemConfiguration dropInPlaceSolution = dropInPlaceSolution(pixelX, pixelY,
|
|
spanX, spanY,
|
|
dragView);
|
|
|
|
// Find a solution involving pushing / displacing any items in the way
|
|
CellLayout.ItemConfiguration swapSolution = findReorderSolution(pixelX, pixelY, minSpanX,
|
|
minSpanY, spanX, spanY, mCellLayout.mDirectionVector, dragView, true,
|
|
new CellLayout.ItemConfiguration());
|
|
|
|
// We attempt the approach which doesn't shuffle views at all
|
|
CellLayout.ItemConfiguration closestSpaceSolution = closestEmptySpaceReorder(
|
|
pixelX, pixelY, minSpanX, minSpanY, spanX, spanY);
|
|
|
|
// 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() >= closestSpaceSolution.area()) {
|
|
return swapSolution;
|
|
} else if (closestSpaceSolution.isSolution) {
|
|
return closestSpaceSolution;
|
|
} else if (dropInPlaceSolution.isSolution) {
|
|
return dropInPlaceSolution;
|
|
}
|
|
return null;
|
|
}
|
|
}
|