Add new motion for when Folder preview changes due to onDrop. am: 4dd024b974

Change-Id: I2890d07784fdf4e7530e840434293bf5cdb80b4e
This commit is contained in:
Jonathan Miranda
2017-07-14 21:27:07 +00:00
5 changed files with 200 additions and 26 deletions
@@ -1,15 +1,18 @@
package com.android.launcher3.folder;
public class ClippedFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule {
static final int MAX_NUM_ITEMS_IN_PREVIEW = 4;
private static final int MIN_NUM_ITEMS_IN_PREVIEW = 2;
private static final int MAX_NUM_ITEMS_PER_ROW = 2;
final float MIN_SCALE = 0.48f;
final float MAX_SCALE = 0.58f;
final float MAX_RADIUS_DILATION = 0.15f;
final float ITEM_RADIUS_SCALE_FACTOR = 1.33f;
private static final float MIN_SCALE = 0.48f;
private static final float MAX_SCALE = 0.58f;
private static final float MAX_RADIUS_DILATION = 0.15f;
private static final float ITEM_RADIUS_SCALE_FACTOR = 1.33f;
private static final int EXIT_INDEX = -2;
private static final int ENTER_INDEX = -3;
private float[] mTmpPoint = new float[2];
@@ -31,21 +34,29 @@ public class ClippedFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule
@Override
public PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
PreviewItemDrawingParams params) {
float totalScale = scaleForItem(index, curNumItems);
float transX;
float transY;
float overlayAlpha = 0;
// Items beyond those displayed in the preview are animated to the center
if (index >= MAX_NUM_ITEMS_IN_PREVIEW) {
transX = transY = mAvailableSpace / 2 - (mIconSize * totalScale) / 2;
if (index == getExitIndex()) {
// 0 1 * <-- Exit position (row 0, col 2)
// 2 3
getGridPosition(0, 2, mTmpPoint);
} else if (index == getEnterIndex()) {
// 0 1
// 2 3 * <-- Enter position (row 1, col 2)
getGridPosition(1, 2, mTmpPoint);
} else if (index >= MAX_NUM_ITEMS_IN_PREVIEW) {
// Items beyond those displayed in the preview are animated to the center
mTmpPoint[0] = mTmpPoint[1] = mAvailableSpace / 2 - (mIconSize * totalScale) / 2;
} else {
getPosition(index, curNumItems, mTmpPoint);
transX = mTmpPoint[0];
transY = mTmpPoint[1];
}
transX = mTmpPoint[0];
transY = mTmpPoint[1];
if (params == null) {
params = new PreviewItemDrawingParams(transX, transY, totalScale, overlayAlpha);
} else {
@@ -55,6 +66,27 @@ public class ClippedFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule
return params;
}
/**
* Builds a grid based on the positioning of the items when there are
* {@link #MAX_NUM_ITEMS_IN_PREVIEW} in the preview.
*
* Positions in the grid: 0 1 // 0 is row 0, col 1
* 2 3 // 3 is row 1, col 1
*/
private void getGridPosition(int row, int col, float[] result) {
// We use position 0 and 3 to calculate the x and y distances between items.
getPosition(0, 4, result);
float left = result[0];
float top = result[1];
getPosition(3, 4, result);
float dx = result[0] - left;
float dy = result[1] - top;
result[0] = left + (col * dx);
result[1] = top + (row * dy);
}
private void getPosition(int index, int curNumItems, float[] result) {
// The case of two items is homomorphic to the case of one.
curNumItems = Math.max(curNumItems, 2);
@@ -127,4 +159,19 @@ public class ClippedFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule
public boolean clipToBackground() {
return true;
}
@Override
public boolean hasEnterExitIndices() {
return true;
}
@Override
public int getExitIndex() {
return EXIT_INDEX;
}
@Override
public int getEnterIndex() {
return ENTER_INDEX;
}
}
@@ -221,7 +221,15 @@ public class FolderIcon extends FrameLayout implements FolderListener {
}
public void addItem(ShortcutInfo item) {
mInfo.add(item, true);
addItem(item, true);
}
public void addItem(ShortcutInfo item, boolean animate) {
mInfo.add(item, animate);
}
public void removeItem(ShortcutInfo item, boolean animate) {
mInfo.remove(item, animate);
}
public void onDragEnter(ItemInfo dragInfo) {
@@ -276,7 +284,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
}
private void onDrop(final ShortcutInfo item, DragView animateView, Rect finalRect,
float scaleRelativeToDragLayer, final int index, Runnable postAnimationRunnable) {
float scaleRelativeToDragLayer, int index, Runnable postAnimationRunnable) {
item.cellX = -1;
item.cellY = -1;
@@ -304,13 +312,39 @@ public class FolderIcon extends FrameLayout implements FolderListener {
workspace.resetTransitionTransform((CellLayout) getParent().getParent());
}
boolean itemAdded = false;
if (index >= mPreviewLayoutRule.maxNumItems()
&& mPreviewLayoutRule.hasEnterExitIndices()) {
List<BubbleTextView> oldPreviewItems = getPreviewItemsOnPage(0);
addItem(item, false);
List<BubbleTextView> newPreviewItems = getPreviewItemsOnPage(0);
if (!oldPreviewItems.containsAll(newPreviewItems)) {
for (int i = 0; i < newPreviewItems.size(); ++i) {
if (newPreviewItems.get(i).getTag().equals(item)) {
// If the item dropped is going to be in the preview, we update the
// index here to reflect its position in the preview.
index = i;
}
}
mPreviewItemManager.onDrop(oldPreviewItems, newPreviewItems, item);
itemAdded = true;
} else {
removeItem(item, false);
}
}
if (!itemAdded) {
addItem(item);
}
int[] center = new int[2];
float scale = getLocalCenterForIndex(index, index + 1, center);
center[0] = (int) Math.round(scaleRelativeToDragLayer * center[0]);
center[1] = (int) Math.round(scaleRelativeToDragLayer * center[1]);
to.offset(center[0] - animateView.getMeasuredWidth() / 2,
center[1] - animateView.getMeasuredHeight() / 2);
center[1] - animateView.getMeasuredHeight() / 2);
float finalAlpha = index < mPreviewLayoutRule.maxNumItems() ? 0.5f : 0f;
@@ -319,13 +353,14 @@ public class FolderIcon extends FrameLayout implements FolderListener {
1, 1, finalScale, finalScale, DROP_IN_ANIMATION_DURATION,
new DecelerateInterpolator(2), new AccelerateInterpolator(2),
postAnimationRunnable, DragLayer.ANIMATION_END_DISAPPEAR, null);
addItem(item);
mFolder.hideItem(item);
mPreviewItemManager.hidePreviewItem(index, true);
if (!itemAdded) mPreviewItemManager.hidePreviewItem(index, true);
final int finalIndex = index;
postDelayed(new Runnable() {
public void run() {
mPreviewItemManager.hidePreviewItem(index, false);
mPreviewItemManager.hidePreviewItem(finalIndex, false);
mFolder.showItem(item);
invalidate();
}
@@ -655,11 +690,16 @@ public class FolderIcon extends FrameLayout implements FolderListener {
interface PreviewLayoutRule {
PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
PreviewItemDrawingParams params);
PreviewItemDrawingParams params);
void init(int availableSpace, float intrinsicIconSize, boolean rtl);
float scaleForItem(int index, int totalNumItems);
float getIconSize();
int maxNumItems();
boolean clipToBackground();
boolean hasEnterExitIndices();
int getExitIndex();
int getEnterIndex();
}
}
@@ -40,19 +40,14 @@ public class FolderIconPreviewVerifier {
}
public void setFolderInfo(FolderInfo info) {
FolderPagedView.calculateGridSize(info.contents.size(), 0, 0, mMaxGridCountX,
int numItemsInFolder = info.contents.size();
FolderPagedView.calculateGridSize(numItemsInFolder, 0, 0, mMaxGridCountX,
mMaxGridCountY, mMaxItemsPerPage, mGridSize);
mGridCountX = mGridSize[0];
int numItemsInFolder = info.contents.size();
mDisplayingUpperLeftQuadrant = FeatureFlags.LAUNCHER3_NEW_FOLDER_ANIMATION
&& !FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON
&& numItemsInFolder > FolderIcon.NUM_ITEMS_IN_PREVIEW;
if (mDisplayingUpperLeftQuadrant) {
FolderPagedView.calculateGridSize(info.contents.size(), 0, 0, mMaxGridCountX,
mMaxGridCountY, mMaxItemsPerPage, mGridSize);
mGridCountX = mGridSize[0];
}
}
/**
@@ -27,6 +27,7 @@ import android.view.View;
import android.widget.TextView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
@@ -273,4 +274,80 @@ public class PreviewItemManager {
float getIntrinsicIconSize() {
return mIntrinsicIconSize;
}
/**
* Handles the case where items in the preview are either:
* - Moving into the preview
* - Moving into a new position
* - Moving out of the preview
*
* @param oldParams The list of items in the old preview.
* @param newParams The list of items in the new preview.
* @param dropped The item that was dropped onto the FolderIcon.
*/
public void onDrop(List<BubbleTextView> oldParams, List<BubbleTextView> newParams,
ShortcutInfo dropped) {
int numItems = newParams.size();
final ArrayList<PreviewItemDrawingParams> params = mFirstPageParams;
buildParamsForPage(0, params, false);
// New preview items for items that are moving in (except for the dropped item).
List<BubbleTextView> moveIn = new ArrayList<>();
for (BubbleTextView btv : newParams) {
if (!oldParams.contains(btv) && !btv.getTag().equals(dropped)) {
moveIn.add(btv);
}
}
for (int i = 0; i < moveIn.size(); ++i) {
int prevIndex = newParams.indexOf(moveIn.get(i));
PreviewItemDrawingParams p = params.get(prevIndex);
computePreviewItemDrawingParams(prevIndex, numItems, p);
updateTransitionParam(p, moveIn.get(i), mIcon.mPreviewLayoutRule.getEnterIndex(),
newParams.indexOf(moveIn.get(i)));
}
// Items that are moving into new positions within the preview.
for (int newIndex = 0; newIndex < newParams.size(); ++newIndex) {
int oldIndex = oldParams.indexOf(newParams.get(newIndex));
if (oldIndex >= 0 && newIndex != oldIndex) {
PreviewItemDrawingParams p = params.get(newIndex);
updateTransitionParam(p, newParams.get(newIndex), oldIndex, newIndex);
}
}
// Old preview items that need to be moved out.
List<BubbleTextView> moveOut = new ArrayList<>(oldParams);
moveOut.removeAll(newParams);
for (int i = 0; i < moveOut.size(); ++i) {
BubbleTextView item = moveOut.get(i);
int oldIndex = oldParams.indexOf(item);
PreviewItemDrawingParams p = computePreviewItemDrawingParams(oldIndex, numItems, null);
updateTransitionParam(p, item, oldIndex, mIcon.mPreviewLayoutRule.getExitIndex());
params.add(0, p); // We want these items first so that they are on drawn last.
}
for (int i = 0; i < params.size(); ++i) {
if (params.get(i).anim != null) {
params.get(i).anim.start();
}
}
}
private void updateTransitionParam(final PreviewItemDrawingParams p, BubbleTextView btv,
int prevIndex, int newIndex) {
p.drawable = btv.getCompoundDrawables()[1];
if (!mIcon.mFolder.isOpen()) {
// Set the callback to FolderIcon as it is responsible to drawing the icon. The
// callback will be released when the folder is opened.
p.drawable.setCallback(mIcon);
}
FolderPreviewItemAnim anim = new FolderPreviewItemAnim(this, p, prevIndex,
FolderIcon.NUM_ITEMS_IN_PREVIEW, newIndex, FolderIcon.NUM_ITEMS_IN_PREVIEW,
DROP_IN_ANIMATION_DURATION, null);
if (p.anim != null && !p.anim.hasEqualFinalState(anim)) {
p.anim.cancel();
}
p.anim = anim;
}
}
@@ -97,4 +97,19 @@ public class StackFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule {
public boolean clipToBackground() {
return false;
}
@Override
public boolean hasEnterExitIndices() {
return false;
}
@Override
public int getExitIndex() {
throw new RuntimeException("hasEnterExitIndices not supported");
}
@Override
public int getEnterIndex() {
throw new RuntimeException("hasEnterExitIndices not supported");
}
}