Allow app pairs in folders

This CL substantially refactors folders to be able to take contents of type AppPairInfo. App pairs can now be moved in and out of folders, and launch from folders.

This CL contains only logic and model changes; animation and style changes (for dropping items into folders, color changes to app pair surfaces, etc.) will be in a following CL. Another CL (hopefully) will contain tests. I'm planning to submit them together, but this patch should also be able to stand alone with no issues (except janky transitions).

Bug: 315731527
Flag: ACONFIG com.android.wm.shell.enable_app_pairs TRUNKFOOD
Test: Manual, more to follow in another CL.
Change-Id: I73732fcaefbdc61bf6e02a5be365962b8bbc3e41
This commit is contained in:
Jeremy Sim
2024-04-02 01:21:31 -07:00
parent da4ba9336e
commit a596f589c4
28 changed files with 454 additions and 233 deletions
@@ -43,6 +43,7 @@ import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PropertyResetListener;
import com.android.launcher3.apppairs.AppPairIcon;
import com.android.launcher3.celllayout.CellLayoutLayoutParams;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.BaseDragLayer;
@@ -127,7 +128,7 @@ public class FolderAnimationManager {
(BaseDragLayer.LayoutParams) mFolder.getLayoutParams();
mFolderIcon.getPreviewItemManager().recomputePreviewDrawingParams();
ClippedFolderIconLayoutRule rule = mFolderIcon.getLayoutRule();
final List<BubbleTextView> itemsInPreview = getPreviewIconsOnPage(0);
final List<View> itemsInPreview = getPreviewIconsOnPage(0);
// Match position of the FolderIcon
final Rect folderIconPos = new Rect();
@@ -139,8 +140,8 @@ public class FolderAnimationManager {
// Match size/scale of icons in the preview
float previewScale = rule.scaleForItem(itemsInPreview.size());
float previewSize = rule.getIconSize() * previewScale;
float initialScale = previewSize / itemsInPreview.get(0).getIconSize()
* scaleRelativeToDragLayer;
float baseIconSize = getBubbleTextView(itemsInPreview.get(0)).getIconSize();
float initialScale = previewSize / baseIconSize * scaleRelativeToDragLayer;
final float finalScale = 1f;
float scale = mIsOpening ? initialScale : finalScale;
mFolder.setPivotX(0);
@@ -198,11 +199,12 @@ public class FolderAnimationManager {
// Initialize the Folder items' text.
PropertyResetListener colorResetListener =
new PropertyResetListener<>(TEXT_ALPHA_PROPERTY, 1f);
for (BubbleTextView icon : mFolder.getItemsOnPage(mFolder.mContent.getCurrentPage())) {
for (View icon : mFolder.getItemsOnPage(mFolder.mContent.getCurrentPage())) {
BubbleTextView titleText = getBubbleTextView(icon);
if (mIsOpening) {
icon.setTextVisibility(false);
titleText.setTextVisibility(false);
}
ObjectAnimator anim = icon.createTextAlphaAnimator(mIsOpening);
ObjectAnimator anim = titleText.createTextAlphaAnimator(mIsOpening);
anim.addListener(colorResetListener);
play(a, anim);
}
@@ -339,7 +341,7 @@ public class FolderAnimationManager {
/**
* Returns the list of "preview items" on {@param page}.
*/
private List<BubbleTextView> getPreviewIconsOnPage(int page) {
private List<View> getPreviewIconsOnPage(int page) {
return mPreviewVerifier.setFolderInfo(mFolder.mInfo)
.previewItemsForPage(page, mFolder.getIconsInReadingOrder());
}
@@ -351,7 +353,7 @@ public class FolderAnimationManager {
int previewItemOffsetX, int previewItemOffsetY) {
ClippedFolderIconLayoutRule rule = mFolderIcon.getLayoutRule();
boolean isOnFirstPage = mFolder.mContent.getCurrentPage() == 0;
final List<BubbleTextView> itemsInPreview = getPreviewIconsOnPage(
final List<View> itemsInPreview = getPreviewIconsOnPage(
isOnFirstPage ? 0 : mFolder.mContent.getCurrentPage());
final int numItemsInPreview = itemsInPreview.size();
final int numItemsInFirstPagePreview = isOnFirstPage
@@ -361,48 +363,49 @@ public class FolderAnimationManager {
ShortcutAndWidgetContainer cwc = mContent.getPageAt(0).getShortcutsAndWidgets();
for (int i = 0; i < numItemsInPreview; ++i) {
final BubbleTextView btv = itemsInPreview.get(i);
CellLayoutLayoutParams btvLp = (CellLayoutLayoutParams) btv.getLayoutParams();
final View v = itemsInPreview.get(i);
CellLayoutLayoutParams vLp = (CellLayoutLayoutParams) v.getLayoutParams();
// Calculate the final values in the LayoutParams.
btvLp.isLockedToGrid = true;
cwc.setupLp(btv);
vLp.isLockedToGrid = true;
cwc.setupLp(v);
// Match scale of icons in the preview of the items on the first page.
float previewScale = rule.scaleForItem(numItemsInFirstPagePreview);
float previewSize = rule.getIconSize() * previewScale;
float iconScale = previewSize / itemsInPreview.get(i).getIconSize();
float baseIconSize = getBubbleTextView(v).getIconSize();
float iconScale = previewSize / baseIconSize;
final float initialScale = iconScale / folderScale;
final float finalScale = 1f;
float scale = mIsOpening ? initialScale : finalScale;
btv.setScaleX(scale);
btv.setScaleY(scale);
v.setScaleX(scale);
v.setScaleY(scale);
// Match positions of the icons in the folder with their positions in the preview
rule.computePreviewItemDrawingParams(i, numItemsInFirstPagePreview, mTmpParams);
// The PreviewLayoutRule assumes that the icon size takes up the entire width so we
// offset by the actual size.
int iconOffsetX = (int) ((btvLp.width - btv.getIconSize()) * iconScale) / 2;
int iconOffsetX = (int) ((vLp.width - baseIconSize) * iconScale) / 2;
final int previewPosX =
(int) ((mTmpParams.transX - iconOffsetX + previewItemOffsetX) / folderScale);
final float paddingTop = btv.getPaddingTop() * iconScale;
final float paddingTop = v.getPaddingTop() * iconScale;
final int previewPosY = (int) ((mTmpParams.transY + previewItemOffsetY - paddingTop)
/ folderScale);
final float xDistance = previewPosX - btvLp.x;
final float yDistance = previewPosY - btvLp.y;
final float xDistance = previewPosX - vLp.x;
final float yDistance = previewPosY - vLp.y;
Animator translationX = getAnimator(btv, View.TRANSLATION_X, xDistance, 0f);
Animator translationX = getAnimator(v, View.TRANSLATION_X, xDistance, 0f);
translationX.setInterpolator(previewItemInterpolator);
play(animatorSet, translationX);
Animator translationY = getAnimator(btv, View.TRANSLATION_Y, yDistance, 0f);
Animator translationY = getAnimator(v, View.TRANSLATION_Y, yDistance, 0f);
translationY.setInterpolator(previewItemInterpolator);
play(animatorSet, translationY);
Animator scaleAnimator = getAnimator(btv, SCALE_PROPERTY, initialScale, finalScale);
Animator scaleAnimator = getAnimator(v, SCALE_PROPERTY, initialScale, finalScale);
scaleAnimator.setInterpolator(previewItemInterpolator);
play(animatorSet, scaleAnimator);
@@ -426,20 +429,20 @@ public class FolderAnimationManager {
super.onAnimationStart(animation);
// Necessary to initialize values here because of the start delay.
if (mIsOpening) {
btv.setTranslationX(xDistance);
btv.setTranslationY(yDistance);
btv.setScaleX(initialScale);
btv.setScaleY(initialScale);
v.setTranslationX(xDistance);
v.setTranslationY(yDistance);
v.setScaleX(initialScale);
v.setScaleY(initialScale);
}
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
btv.setTranslationX(0.0f);
btv.setTranslationY(0.0f);
btv.setScaleX(1f);
btv.setScaleY(1f);
v.setTranslationX(0.0f);
v.setTranslationY(0.0f);
v.setScaleX(1f);
v.setScaleY(1f);
}
});
}
@@ -482,4 +485,15 @@ public class FolderAnimationManager {
? ObjectAnimator.ofArgb(drawable, property, v1, v2)
: ObjectAnimator.ofArgb(drawable, property, v2, v1);
}
/**
* Gets the {@link com.android.launcher3.BubbleTextView} from an icon. In some cases the
* BubbleTextView is the whole icon itself, while in others it is contained within the view and
* only serves to store the title text.
*/
private BubbleTextView getBubbleTextView(View v) {
return v instanceof AppPairIcon
? ((AppPairIcon) v).getTitleTextView()
: (BubbleTextView) v;
}
}