summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Cohen <adamcohen@google.com>2016-02-24 19:19:06 -0800
committerAdam Cohen <adamcohen@google.com>2016-03-03 09:24:45 -0800
commitefca0279eb927faebffc38c8382818df67fcd159 (patch)
tree15ede9a36767c9d04a47e355edc5550b25dfb36c
parent992a5f566e7f1b1fc8bd766f1fd00bee7ea2a634 (diff)
downloadandroid_packages_apps_Trebuchet-efca0279eb927faebffc38c8382818df67fcd159.tar.gz
android_packages_apps_Trebuchet-efca0279eb927faebffc38c8382818df67fcd159.tar.bz2
android_packages_apps_Trebuchet-efca0279eb927faebffc38c8382818df67fcd159.zip
Switch all folder preview rendering to be programmatic (ie. no assets)
-> Refactored the preview background rendering to be much more self-contained. This cleans up a lot of code in the CellLayout, and keeps the logic in the right place. -> We switch to software rendering for performance and compatibility reasons. -> Removed all assets. -> FolderIcon accept animation includes animation of the clipped region. -> 1:1 hand-off of drawing of the FolderIcon background between the FolderIcon and the CellLayout. Unfortunately, CellLayout rendering is still required to work around clipping issues (due to use of software layer). We also need this to support folder creation feedback. Change-Id: Ib8f7fa6359dfedff8145f38dd50ba03849ca0d51
-rw-r--r--res/drawable-hdpi/portal_ring_inner.pngbin2340 -> 0 bytes
-rw-r--r--res/drawable-hdpi/portal_ring_inner_nolip.pngbin2231 -> 0 bytes
-rw-r--r--res/drawable-hdpi/portal_ring_outer.pngbin5918 -> 0 bytes
-rw-r--r--res/drawable-hdpi/portal_ring_rest.pngbin1512 -> 0 bytes
-rw-r--r--res/drawable-mdpi/portal_ring_inner.pngbin1431 -> 0 bytes
-rw-r--r--res/drawable-mdpi/portal_ring_inner_nolip.pngbin1382 -> 0 bytes
-rw-r--r--res/drawable-mdpi/portal_ring_outer.pngbin3217 -> 0 bytes
-rw-r--r--res/drawable-mdpi/portal_ring_rest.pngbin871 -> 0 bytes
-rw-r--r--res/drawable-xhdpi/portal_ring_inner.pngbin3275 -> 0 bytes
-rw-r--r--res/drawable-xhdpi/portal_ring_inner_nolip.pngbin3054 -> 0 bytes
-rw-r--r--res/drawable-xhdpi/portal_ring_outer.pngbin8338 -> 0 bytes
-rw-r--r--res/drawable-xhdpi/portal_ring_rest.pngbin2056 -> 0 bytes
-rw-r--r--res/drawable-xxhdpi/portal_ring_inner.pngbin5663 -> 0 bytes
-rw-r--r--res/drawable-xxhdpi/portal_ring_inner_nolip.pngbin5418 -> 0 bytes
-rw-r--r--res/drawable-xxhdpi/portal_ring_outer.pngbin16598 -> 0 bytes
-rw-r--r--res/drawable-xxhdpi/portal_ring_rest.pngbin3622 -> 0 bytes
-rw-r--r--res/drawable-xxxhdpi/portal_ring_inner.pngbin7927 -> 0 bytes
-rw-r--r--res/drawable-xxxhdpi/portal_ring_inner_nolip.pngbin7432 -> 0 bytes
-rw-r--r--res/drawable-xxxhdpi/portal_ring_outer.pngbin20634 -> 0 bytes
-rw-r--r--res/drawable-xxxhdpi/portal_ring_rest.pngbin4993 -> 0 bytes
-rw-r--r--res/layout/folder_icon.xml7
-rw-r--r--src/com/android/launcher3/CellLayout.java117
-rw-r--r--src/com/android/launcher3/DeviceProfile.java2
-rw-r--r--src/com/android/launcher3/Launcher.java6
-rw-r--r--src/com/android/launcher3/Workspace.java28
-rw-r--r--src/com/android/launcher3/config/FeatureFlags.java2
-rw-r--r--src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java16
-rw-r--r--src/com/android/launcher3/folder/FolderIcon.java500
-rw-r--r--src/com/android/launcher3/folder/StackFolderIconLayoutRule.java4
29 files changed, 379 insertions, 303 deletions
diff --git a/res/drawable-hdpi/portal_ring_inner.png b/res/drawable-hdpi/portal_ring_inner.png
deleted file mode 100644
index 65f5af2e7..000000000
--- a/res/drawable-hdpi/portal_ring_inner.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/portal_ring_inner_nolip.png b/res/drawable-hdpi/portal_ring_inner_nolip.png
deleted file mode 100644
index 5be25fc8f..000000000
--- a/res/drawable-hdpi/portal_ring_inner_nolip.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/portal_ring_outer.png b/res/drawable-hdpi/portal_ring_outer.png
deleted file mode 100644
index 712eeb20c..000000000
--- a/res/drawable-hdpi/portal_ring_outer.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/portal_ring_rest.png b/res/drawable-hdpi/portal_ring_rest.png
deleted file mode 100644
index 33cec3218..000000000
--- a/res/drawable-hdpi/portal_ring_rest.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/portal_ring_inner.png b/res/drawable-mdpi/portal_ring_inner.png
deleted file mode 100644
index 7c5e2b744..000000000
--- a/res/drawable-mdpi/portal_ring_inner.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/portal_ring_inner_nolip.png b/res/drawable-mdpi/portal_ring_inner_nolip.png
deleted file mode 100644
index 6ccdebbee..000000000
--- a/res/drawable-mdpi/portal_ring_inner_nolip.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/portal_ring_outer.png b/res/drawable-mdpi/portal_ring_outer.png
deleted file mode 100644
index 40a73abf7..000000000
--- a/res/drawable-mdpi/portal_ring_outer.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/portal_ring_rest.png b/res/drawable-mdpi/portal_ring_rest.png
deleted file mode 100644
index b2c733bdd..000000000
--- a/res/drawable-mdpi/portal_ring_rest.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/portal_ring_inner.png b/res/drawable-xhdpi/portal_ring_inner.png
deleted file mode 100644
index b088042e7..000000000
--- a/res/drawable-xhdpi/portal_ring_inner.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/portal_ring_inner_nolip.png b/res/drawable-xhdpi/portal_ring_inner_nolip.png
deleted file mode 100644
index decf76698..000000000
--- a/res/drawable-xhdpi/portal_ring_inner_nolip.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/portal_ring_outer.png b/res/drawable-xhdpi/portal_ring_outer.png
deleted file mode 100644
index 5ab9a21cf..000000000
--- a/res/drawable-xhdpi/portal_ring_outer.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/portal_ring_rest.png b/res/drawable-xhdpi/portal_ring_rest.png
deleted file mode 100644
index 7d1c84236..000000000
--- a/res/drawable-xhdpi/portal_ring_rest.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/portal_ring_inner.png b/res/drawable-xxhdpi/portal_ring_inner.png
deleted file mode 100644
index cd23cf7ac..000000000
--- a/res/drawable-xxhdpi/portal_ring_inner.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/portal_ring_inner_nolip.png b/res/drawable-xxhdpi/portal_ring_inner_nolip.png
deleted file mode 100644
index d82b910e9..000000000
--- a/res/drawable-xxhdpi/portal_ring_inner_nolip.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/portal_ring_outer.png b/res/drawable-xxhdpi/portal_ring_outer.png
deleted file mode 100644
index e5d33b252..000000000
--- a/res/drawable-xxhdpi/portal_ring_outer.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/portal_ring_rest.png b/res/drawable-xxhdpi/portal_ring_rest.png
deleted file mode 100644
index d52825c21..000000000
--- a/res/drawable-xxhdpi/portal_ring_rest.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/portal_ring_inner.png b/res/drawable-xxxhdpi/portal_ring_inner.png
deleted file mode 100644
index 59e811daa..000000000
--- a/res/drawable-xxxhdpi/portal_ring_inner.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/portal_ring_inner_nolip.png b/res/drawable-xxxhdpi/portal_ring_inner_nolip.png
deleted file mode 100644
index c1e75857e..000000000
--- a/res/drawable-xxxhdpi/portal_ring_inner_nolip.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/portal_ring_outer.png b/res/drawable-xxxhdpi/portal_ring_outer.png
deleted file mode 100644
index f2f818b3b..000000000
--- a/res/drawable-xxxhdpi/portal_ring_outer.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/portal_ring_rest.png b/res/drawable-xxxhdpi/portal_ring_rest.png
deleted file mode 100644
index 2af67b8ee..000000000
--- a/res/drawable-xxxhdpi/portal_ring_rest.png
+++ /dev/null
Binary files differ
diff --git a/res/layout/folder_icon.xml b/res/layout/folder_icon.xml
index b8d5c608b..9eb8c9a67 100644
--- a/res/layout/folder_icon.xml
+++ b/res/layout/folder_icon.xml
@@ -20,13 +20,6 @@
android:layout_height="match_parent"
android:orientation="vertical"
android:focusable="true" >
- <ImageView
- android:id="@+id/preview_background"
- android:layout_gravity="center_horizontal"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:antialias="true"
- android:src="@drawable/portal_ring_inner"/>
<com.android.launcher3.BubbleTextView
style="@style/Icon"
android:id="@+id/folder_icon_name"
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 5832b9f0d..af3703314 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -55,7 +55,6 @@ import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.config.ProviderConfig;
import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.folder.FolderIcon.FolderRingAnimator;
import com.android.launcher3.util.ParcelableSparseArray;
import com.android.launcher3.util.Thunk;
@@ -108,8 +107,9 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler {
private OnTouchListener mInterceptTouchListener;
private StylusEventHelper mStylusEventHelper;
- private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>();
- private int[] mFolderLeaveBehindCell = {-1, -1};
+ private ArrayList<FolderIcon.PreviewBackground> mFolderBackgrounds = new ArrayList<FolderIcon.PreviewBackground>();
+ FolderIcon.PreviewBackground mFolderLeaveBehind = new FolderIcon.PreviewBackground();
+ Paint mFolderBgPaint = new Paint();
private float mBackgroundAlpha;
@@ -209,6 +209,9 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler {
mPreviousReorderDirection[0] = INVALID_DIRECTION;
mPreviousReorderDirection[1] = INVALID_DIRECTION;
+ mFolderLeaveBehind.delegateCellX = -1;
+ mFolderLeaveBehind.delegateCellY = -1;
+
setAlwaysDrawnWithCacheEnabled(false);
final Resources res = getResources();
mHotseatScale = (float) grid.hotseatIconSizePx / grid.iconSizePx;
@@ -501,88 +504,62 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler {
}
}
- int previewOffset = FolderRingAnimator.sPreviewSize;
-
- // The folder outer / inner ring image(s)
- DeviceProfile grid = mLauncher.getDeviceProfile();
- for (int i = 0; i < mFolderOuterRings.size(); i++) {
- FolderRingAnimator fra = mFolderOuterRings.get(i);
-
- Drawable d;
- int width, height;
- cellToPoint(fra.mCellX, fra.mCellY, mTempLocation);
- View child = getChildAt(fra.mCellX, fra.mCellY);
-
- if (child != null) {
- int centerX = mTempLocation[0] + mCellWidth / 2;
- int centerY = mTempLocation[1] + previewOffset / 2 +
- child.getPaddingTop() + grid.folderBackgroundOffset;
-
- // Draw outer ring, if it exists
- if (FolderIcon.HAS_OUTER_RING) {
- d = FolderRingAnimator.sSharedOuterRingDrawable;
- width = (int) (fra.getOuterRingSize() * getChildrenScale());
- height = width;
- canvas.save();
- canvas.translate(centerX - width / 2, centerY - height / 2);
- d.setBounds(0, 0, width, height);
- d.draw(canvas);
- canvas.restore();
- }
-
- // Draw inner ring
- d = FolderRingAnimator.sSharedInnerRingDrawable;
- width = (int) (fra.getInnerRingSize() * getChildrenScale());
- height = width;
- canvas.save();
- canvas.translate(centerX - width / 2, centerY - width / 2);
- d.setBounds(0, 0, width, height);
- d.draw(canvas);
- canvas.restore();
- }
+ for (int i = 0; i < mFolderBackgrounds.size(); i++) {
+ FolderIcon.PreviewBackground bg = mFolderBackgrounds.get(i);
+ cellToPoint(bg.delegateCellX, bg.delegateCellY, mTempLocation);
+ canvas.save();
+ canvas.translate(mTempLocation[0], mTempLocation[1]);
+ bg.drawBackground(canvas, mFolderBgPaint);
+ canvas.restore();
}
- if (mFolderLeaveBehindCell[0] >= 0 && mFolderLeaveBehindCell[1] >= 0) {
- Drawable d = FolderIcon.sSharedFolderLeaveBehind;
- int width = d.getIntrinsicWidth();
- int height = d.getIntrinsicHeight();
+ if (mFolderLeaveBehind.delegateCellX >= 0 && mFolderLeaveBehind.delegateCellY >= 0) {
+ cellToPoint(mFolderLeaveBehind.delegateCellX,
+ mFolderLeaveBehind.delegateCellY, mTempLocation);
+ canvas.save();
+ canvas.translate(mTempLocation[0], mTempLocation[1]);
+ mFolderLeaveBehind.drawLeaveBehind(canvas, mFolderBgPaint);
+ canvas.restore();
+ }
+ }
- cellToPoint(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1], mTempLocation);
- View child = getChildAt(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1]);
- if (child != null) {
- int centerX = mTempLocation[0] + mCellWidth / 2;
- int centerY = mTempLocation[1] + previewOffset / 2 +
- child.getPaddingTop() + grid.folderBackgroundOffset;
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ super.dispatchDraw(canvas);
- canvas.save();
- canvas.translate(centerX - width / 2, centerY - width / 2);
- d.setBounds(0, 0, width, height);
- d.draw(canvas);
- canvas.restore();
- }
+ for (int i = 0; i < mFolderBackgrounds.size(); i++) {
+ FolderIcon.PreviewBackground bg = mFolderBackgrounds.get(i);
+ cellToPoint(bg.delegateCellX, bg.delegateCellY, mTempLocation);
+ canvas.save();
+ canvas.translate(mTempLocation[0], mTempLocation[1]);
+ bg.drawBackgroundStroke(canvas, mFolderBgPaint);
+ canvas.restore();
}
}
- public void showFolderAccept(FolderRingAnimator fra) {
- mFolderOuterRings.add(fra);
+ public void addFolderBackground(FolderIcon.PreviewBackground bg) {
+ mFolderBackgrounds.add(bg);
}
-
- public void hideFolderAccept(FolderRingAnimator fra) {
- if (mFolderOuterRings.contains(fra)) {
- mFolderOuterRings.remove(fra);
- }
- invalidate();
+ public void removeFolderBackground(FolderIcon.PreviewBackground bg) {
+ mFolderBackgrounds.remove(bg);
}
public void setFolderLeaveBehindCell(int x, int y) {
- mFolderLeaveBehindCell[0] = x;
- mFolderLeaveBehindCell[1] = y;
+
+ DeviceProfile grid = mLauncher.getDeviceProfile();
+ View child = getChildAt(x, y);
+
+ mFolderLeaveBehind.setup(getResources().getDisplayMetrics(), grid, null,
+ child.getMeasuredWidth(), child.getPaddingTop());
+
+ mFolderLeaveBehind.delegateCellX = x;
+ mFolderLeaveBehind.delegateCellY = y;
invalidate();
}
public void clearFolderLeaveBehind() {
- mFolderLeaveBehindCell[0] = -1;
- mFolderLeaveBehindCell[1] = -1;
+ mFolderLeaveBehind.delegateCellX = -1;
+ mFolderLeaveBehind.delegateCellY = -1;
invalidate();
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index b67e07b33..5bfa716ee 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -85,6 +85,7 @@ public class DeviceProfile {
// Folder
public int folderBackgroundOffset;
public int folderIconSizePx;
+ public int folderIconPreviewPadding;
public int folderCellWidthPx;
public int folderCellHeightPx;
@@ -262,6 +263,7 @@ public class DeviceProfile {
folderCellHeightPx = cellHeightPx + edgeMarginPx;
folderBackgroundOffset = -edgeMarginPx;
folderIconSizePx = iconSizePx + 2 * -folderBackgroundOffset;
+ folderIconPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding);
}
/**
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 70d982081..2d52341a7 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -3029,13 +3029,17 @@ public class Launcher extends Activity
// We remove and re-draw the FolderIcon in-case it has changed
mDragLayer.removeView(mFolderIconImageView);
copyFolderIconToImage(fi);
+
+ if (cl != null) {
+ cl.clearFolderLeaveBehind();
+ }
+
ObjectAnimator oa = LauncherAnimUtils.ofViewAlphaAndScale(mFolderIconImageView, 1, 1, 1);
oa.setDuration(getResources().getInteger(R.integer.config_folderExpandDuration));
oa.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (cl != null) {
- cl.clearFolderLeaveBehind();
// Remove the ImageView copy of the FolderIcon and make the original visible.
mDragLayer.removeView(mFolderIconImageView);
fi.setVisibility(View.VISIBLE);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 7bfb7d58f..0f8d834da 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -59,7 +59,6 @@ import android.widget.TextView;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.folder.FolderIcon.FolderRingAnimator;
import com.android.launcher3.Launcher.CustomContentCallbacks;
import com.android.launcher3.Launcher.LauncherOverlay;
import com.android.launcher3.UninstallDropTarget.UninstallSource;
@@ -224,7 +223,7 @@ public class Workspace extends PagedView
public static final int REORDER_TIMEOUT = 350;
private final Alarm mFolderCreationAlarm = new Alarm();
private final Alarm mReorderAlarm = new Alarm();
- @Thunk FolderRingAnimator mDragFolderRingAnimator = null;
+ private FolderIcon.PreviewBackground mFolderCreateBg = new FolderIcon.PreviewBackground();
private FolderIcon mDragOverFolderIcon = null;
private boolean mCreateUserFolderOnDrop = false;
private boolean mAddToExistingFolderOnDrop = false;
@@ -2493,6 +2492,10 @@ public class Workspace extends PagedView
// If the dragView is null, we can't animate
boolean animate = dragView != null;
if (animate) {
+ // In order to keep everything continuous, we hand off the currently rendered
+ // folder background to the newly created icon. This preserves animation state.
+ fi.setFolderBackground(mFolderCreateBg);
+ mFolderCreateBg = new FolderIcon.PreviewBackground();
fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation, scale,
postAnimationRunnable);
} else {
@@ -2855,10 +2858,7 @@ public class Workspace extends PagedView
}
private void cleanupFolderCreation() {
- if (mDragFolderRingAnimator != null) {
- mDragFolderRingAnimator.animateToNaturalState();
- mDragFolderRingAnimator = null;
- }
+ mFolderCreateBg.animateToRest();
mFolderCreationAlarm.setOnAlarmListener(null);
mFolderCreationAlarm.cancelAlarm();
}
@@ -3166,18 +3166,16 @@ public class Workspace extends PagedView
this.layout = layout;
this.cellX = cellX;
this.cellY = cellY;
+
+ DeviceProfile grid = mLauncher.getDeviceProfile();
+ BubbleTextView cell = (BubbleTextView) layout.getChildAt(cellX, cellY);
+
+ mFolderCreateBg.setup(getResources().getDisplayMetrics(), grid, null,
+ cell.getMeasuredWidth(), cell.getPaddingTop());
}
public void onAlarm(Alarm alarm) {
- if (mDragFolderRingAnimator != null) {
- // This shouldn't happen ever, but just in case, make sure we clean up the mess.
- mDragFolderRingAnimator.animateToNaturalState();
- }
- mDragFolderRingAnimator = new FolderRingAnimator(mLauncher, null);
- mDragFolderRingAnimator.setCell(cellX, cellY);
- mDragFolderRingAnimator.setCellLayout(layout);
- mDragFolderRingAnimator.animateToAcceptState();
- layout.showFolderAccept(mDragFolderRingAnimator);
+ mFolderCreateBg.animateToAccept(layout, cellX, cellY);
layout.clearDragOutlines();
setDragMode(DRAG_MODE_CREATE_FOLDER);
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 285f2c1df..2b3727a8a 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -34,7 +34,7 @@ public final class FeatureFlags {
// As opposed to the new spring-loaded workspace.
public static boolean LAUNCHER3_LEGACY_WORKSPACE_DND = false;
public static boolean LAUNCHER3_ICON_NORMALIZATION = true;
- public static boolean LAUNCHER3_CLIPPED_FOLDER_ICON = false;
+ public static boolean LAUNCHER3_LEGACY_FOLDER_ICON = false;
public static boolean LAUNCHER3_LEGACY_LOGGING = false;
public static boolean LAUNCHER3_USE_SYSTEM_DRAG_DRIVER = false;
}
diff --git a/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java b/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
index 48988d7f2..68b756b24 100644
--- a/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
+++ b/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
@@ -15,6 +15,7 @@ public class ClippedFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule
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 float[] mTmpPoint = new float[2];
@@ -22,27 +23,19 @@ public class ClippedFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule
private float mRadius;
private float mIconSize;
private boolean mIsRtl;
- private Path mClipPath = new Path();
@Override
public void init(int availableSpace, int intrinsicIconSize, boolean rtl) {
mAvailableSpace = availableSpace;
- mRadius = 0.66f * availableSpace;
+ mRadius = ITEM_RADIUS_SCALE_FACTOR * availableSpace / 2f;
mIconSize = intrinsicIconSize;
mIsRtl = rtl;
-
- // We make the clip radius just slightly smaller than the background drawable
- // TODO(adamcohen): this is hacky, needs cleanup (likely through programmatic drawing).
- int clipRadius = (int) mAvailableSpace / 2 - 1;
-
- mClipPath.addCircle(mAvailableSpace / 2, mAvailableSpace / 2, clipRadius, Path.Direction.CW);
}
@Override
public FolderIcon.PreviewItemDrawingParams computePreviewItemDrawingParams(int index,
int curNumItems, FolderIcon.PreviewItemDrawingParams params) {
-
float totalScale = scaleForNumItems(curNumItems);
float transX;
float transY;
@@ -55,7 +48,6 @@ public class ClippedFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule
getPosition(index, curNumItems, mTmpPoint);
transX = mTmpPoint[0];
transY = mTmpPoint[1];
- totalScale = scaleForNumItems(curNumItems);
}
if (params == null) {
@@ -126,8 +118,8 @@ public class ClippedFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule
}
@Override
- public Path getClipPath() {
- return mClipPath;
+ public boolean clipToBackground() {
+ return true;
}
}
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 7b71a36d1..62007f072 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -21,16 +21,17 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
-import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.Rect;
+import android.graphics.Region;
import android.graphics.drawable.Drawable;
-import android.os.Looper;
import android.os.Parcelable;
import android.util.AttributeSet;
+import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -39,7 +40,6 @@ import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
-import android.widget.ImageView;
import android.widget.TextView;
import com.android.launcher3.Alarm;
@@ -77,15 +77,14 @@ import java.util.ArrayList;
* An icon that can appear on in the workspace representing an {@link Folder}.
*/
public class FolderIcon extends FrameLayout implements FolderListener {
- @Thunk
- Launcher mLauncher;
+ @Thunk Launcher mLauncher;
@Thunk Folder mFolder;
private FolderInfo mInfo;
@Thunk static boolean sStaticValuesDirty = true;
- public static final int NUM_ITEMS_IN_PREVIEW = FeatureFlags.LAUNCHER3_CLIPPED_FOLDER_ICON ?
- ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW :
- StackFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
+ public static final int NUM_ITEMS_IN_PREVIEW = FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON ?
+ StackFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW :
+ ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
private CheckLongPressHelper mLongPressHelper;
private StylusEventHelper mStylusEventHelper;
@@ -96,36 +95,19 @@ public class FolderIcon extends FrameLayout implements FolderListener {
private static final int INITIAL_ITEM_ANIMATION_DURATION = 350;
private static final int FINAL_ITEM_ANIMATION_DURATION = 200;
- // The degree to which the inner ring grows when accepting drop
- private static final float INNER_RING_GROWTH_FACTOR = 0.15f;
-
- // The degree to which the outer ring is scaled in its natural state
- private static final float OUTER_RING_GROWTH_FACTOR = 0.3f;
-
- // Flag as to whether or not to draw an outer ring. Currently none is designed.
- public static final boolean HAS_OUTER_RING = true;
-
// Flag whether the folder should open itself when an item is dragged over is enabled.
public static final boolean SPRING_LOADING_ENABLED = true;
// Delay when drag enters until the folder opens, in miliseconds.
private static final int ON_OPEN_DELAY = 800;
- public static Drawable sSharedFolderLeaveBehind = null;
-
- @Thunk ImageView mPreviewBackground;
- @Thunk
- BubbleTextView mFolderName;
-
- FolderRingAnimator mFolderRingAnimator = null;
+ @Thunk BubbleTextView mFolderName;
// These variables are all associated with the drawing of the preview; they are stored
// as member variables for shared usage and to avoid computation on each frame
private int mIntrinsicIconSize;
- private int mAvailableSpaceInPreview;
- private int mPreviewOffsetX;
- private int mPreviewOffsetY;
private int mTotalWidth;
+ PreviewBackground mBackground = new PreviewBackground();
private PreviewLayoutRule mPreviewLayoutRule;
@@ -138,6 +120,8 @@ public class FolderIcon extends FrameLayout implements FolderListener {
private ArrayList<PreviewItemDrawingParams> mDrawingParams = new ArrayList<PreviewItemDrawingParams>();
private Drawable mReferenceDrawable = null;
+ Paint mBgPaint = new Paint();
+
private Alarm mOpenAlarm = new Alarm();
@Thunk
ItemInfo mDragInfo;
@@ -155,17 +139,11 @@ public class FolderIcon extends FrameLayout implements FolderListener {
private void init() {
mLongPressHelper = new CheckLongPressHelper(this);
mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
- mPreviewLayoutRule = FeatureFlags.LAUNCHER3_CLIPPED_FOLDER_ICON ?
- new ClippedFolderIconLayoutRule() :
- new StackFolderIconLayoutRule();
- setAccessibilityDelegate(LauncherAppState.getInstance().getAccessibilityDelegate());
- }
+ mPreviewLayoutRule = FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON ?
+ new StackFolderIconLayoutRule() :
+ new ClippedFolderIconLayoutRule();
- public boolean isDropEnabled() {
- final ViewGroup cellLayoutChildren = (ViewGroup) getParent();
- final ViewGroup cellLayout = (ViewGroup) cellLayoutChildren.getParent();
- final Workspace workspace = (Workspace) cellLayout.getParent();
- return !workspace.workspaceInModalState();
+ setAccessibilityDelegate(LauncherAppState.getInstance().getAccessibilityDelegate());
}
public static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
@@ -179,8 +157,13 @@ public class FolderIcon extends FrameLayout implements FolderListener {
}
DeviceProfile grid = launcher.getDeviceProfile();
-
FolderIcon icon = (FolderIcon) LayoutInflater.from(launcher).inflate(resId, group, false);
+
+ // For performance and compatibility reasons we render the preview using a software layer.
+ // In particular, hardware path clipping has spotty ecosystem support and bad performance.
+ // Software rendering also allows us to use shadow layers.
+ icon.setLayerType(LAYER_TYPE_SOFTWARE, new Paint(Paint.FILTER_BITMAP_FLAG));
+
icon.setClipToPadding(false);
icon.mFolderName = (BubbleTextView) icon.findViewById(R.id.folder_icon_name);
icon.mFolderName.setText(folderInfo.title);
@@ -188,13 +171,6 @@ public class FolderIcon extends FrameLayout implements FolderListener {
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) icon.mFolderName.getLayoutParams();
lp.topMargin = grid.iconSizePx + grid.iconDrawablePaddingPx;
- // Offset the preview background to center this view accordingly
- icon.mPreviewBackground = (ImageView) icon.findViewById(R.id.preview_background);
- lp = (FrameLayout.LayoutParams) icon.mPreviewBackground.getLayoutParams();
- lp.topMargin = grid.folderBackgroundOffset;
- lp.width = grid.folderIconSizePx;
- lp.height = grid.folderIconSizePx;
-
icon.setTag(folderInfo);
icon.setOnClickListener(launcher);
icon.mInfo = folderInfo;
@@ -206,7 +182,6 @@ public class FolderIcon extends FrameLayout implements FolderListener {
folder.bind(folderInfo);
icon.setFolder(folder);
- icon.mFolderRingAnimator = new FolderRingAnimator(launcher, icon);
folderInfo.addListener(icon);
icon.setOnFocusChangeListener(launcher.mFocusHandler);
@@ -219,129 +194,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
return super.onSaveInstanceState();
}
- public static class FolderRingAnimator {
- public int mCellX;
- public int mCellY;
- @Thunk
- CellLayout mCellLayout;
- public float mOuterRingSize;
- public float mInnerRingSize;
- public FolderIcon mFolderIcon = null;
- public static Drawable sSharedOuterRingDrawable = null;
- public static Drawable sSharedInnerRingDrawable = null;
- public static int sPreviewSize = -1;
- public static int sPreviewPadding = -1;
-
- private ValueAnimator mAcceptAnimator;
- private ValueAnimator mNeutralAnimator;
-
- public FolderRingAnimator(Launcher launcher, FolderIcon folderIcon) {
- mFolderIcon = folderIcon;
- Resources res = launcher.getResources();
-
- // We need to reload the static values when configuration changes in case they are
- // different in another configuration
- if (sStaticValuesDirty) {
- if (Looper.myLooper() != Looper.getMainLooper()) {
- throw new RuntimeException("FolderRingAnimator loading drawables on non-UI thread "
- + Thread.currentThread());
- }
-
- DeviceProfile grid = launcher.getDeviceProfile();
- sPreviewSize = grid.folderIconSizePx;
- sPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding);
- sSharedOuterRingDrawable = res.getDrawable(R.drawable.portal_ring_outer);
- sSharedInnerRingDrawable = res.getDrawable(R.drawable.portal_ring_inner_nolip);
- sSharedFolderLeaveBehind = res.getDrawable(R.drawable.portal_ring_rest);
- sStaticValuesDirty = false;
- }
- }
-
- public void animateToAcceptState() {
- if (mNeutralAnimator != null) {
- mNeutralAnimator.cancel();
- }
- mAcceptAnimator = LauncherAnimUtils.ofFloat(mCellLayout, 0f, 1f);
- mAcceptAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
-
- final int previewSize = sPreviewSize;
- mAcceptAnimator.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- final float percent = animation.getAnimatedFraction();
- mOuterRingSize = (1 + percent * OUTER_RING_GROWTH_FACTOR) * previewSize;
- mInnerRingSize = (1 + percent * INNER_RING_GROWTH_FACTOR) * previewSize;
- if (mCellLayout != null) {
- mCellLayout.invalidate();
- }
- }
- });
- mAcceptAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- if (mFolderIcon != null) {
- mFolderIcon.mPreviewBackground.setVisibility(INVISIBLE);
- }
- }
- });
- mAcceptAnimator.start();
- }
-
- public void animateToNaturalState() {
- if (mAcceptAnimator != null) {
- mAcceptAnimator.cancel();
- }
- mNeutralAnimator = LauncherAnimUtils.ofFloat(mCellLayout, 0f, 1f);
- mNeutralAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
-
- final int previewSize = sPreviewSize;
- mNeutralAnimator.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- final float percent = (Float) animation.getAnimatedValue();
- mOuterRingSize = (1 + (1 - percent) * OUTER_RING_GROWTH_FACTOR) * previewSize;
- mInnerRingSize = (1 + (1 - percent) * INNER_RING_GROWTH_FACTOR) * previewSize;
- if (mCellLayout != null) {
- mCellLayout.invalidate();
- }
- }
- });
- mNeutralAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mCellLayout != null) {
- mCellLayout.hideFolderAccept(FolderRingAnimator.this);
- }
- if (mFolderIcon != null) {
- mFolderIcon.mPreviewBackground.setVisibility(VISIBLE);
- }
- }
- });
- mNeutralAnimator.start();
- }
-
- // Location is expressed in window coordinates
- public void getCell(int[] loc) {
- loc[0] = mCellX;
- loc[1] = mCellY;
- }
-
- // Location is expressed in window coordinates
- public void setCell(int x, int y) {
- mCellX = x;
- mCellY = y;
- }
- public void setCellLayout(CellLayout layout) {
- mCellLayout = layout;
- }
-
- public float getOuterRingSize() {
- return mOuterRingSize;
- }
-
- public float getInnerRingSize() {
- return mInnerRingSize;
- }
- }
public Folder getFolder() {
return mFolder;
@@ -375,11 +228,9 @@ public class FolderIcon extends FrameLayout implements FolderListener {
public void onDragEnter(ItemInfo dragInfo) {
if (mFolder.isDestroyed() || !willAcceptItem(dragInfo)) return;
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
- CellLayout layout = (CellLayout) getParent().getParent();
- mFolderRingAnimator.setCell(lp.cellX, lp.cellY);
- mFolderRingAnimator.setCellLayout(layout);
- mFolderRingAnimator.animateToAcceptState();
- layout.showFolderAccept(mFolderRingAnimator);
+ CellLayout cl = (CellLayout) getParent().getParent();
+
+ mBackground.animateToAccept(cl, lp.cellX, lp.cellY);
mOpenAlarm.setOnAlarmListener(mOnOpenListener);
if (SPRING_LOADING_ENABLED &&
((dragInfo instanceof AppInfo) || (dragInfo instanceof ShortcutInfo))) {
@@ -445,7 +296,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
}
public void onDragExit() {
- mFolderRingAnimator.animateToNaturalState();
+ mBackground.animateToRest();
mOpenAlarm.cancelAlarm();
}
@@ -531,16 +382,11 @@ public class FolderIcon extends FrameLayout implements FolderListener {
mIntrinsicIconSize = drawableSize;
mTotalWidth = totalSize;
- final int previewSize = FolderRingAnimator.sPreviewSize;
- final int previewPadding = FolderRingAnimator.sPreviewPadding;
-
- mAvailableSpaceInPreview = (previewSize - 2 * previewPadding);
-
- mPreviewOffsetX = (mTotalWidth - mAvailableSpaceInPreview) / 2;
- mPreviewOffsetY = previewPadding + grid.folderBackgroundOffset + getPaddingTop();
-
- mPreviewLayoutRule.init(mAvailableSpaceInPreview, mIntrinsicIconSize,
+ mBackground.setup(getResources().getDisplayMetrics(), grid, this, mTotalWidth,
+ getPaddingTop());
+ mPreviewLayoutRule.init(mBackground.previewSize, mIntrinsicIconSize,
Utilities.isRtl(getResources()));
+
updateItemDrawingParams(false);
}
}
@@ -586,8 +432,8 @@ public class FolderIcon extends FrameLayout implements FolderListener {
mTmpParams = computePreviewItemDrawingParams(Math.min(mPreviewLayoutRule.numItems(), index),
curNumItems, mTmpParams);
- mTmpParams.transX += mPreviewOffsetX;
- mTmpParams.transY += mPreviewOffsetY;
+ mTmpParams.transX += mBackground.basePreviewOffsetX;
+ mTmpParams.transY += mBackground.basePreviewOffsetY;
float offsetX = mTmpParams.transX + (mTmpParams.scale * mIntrinsicIconSize) / 2;
float offsetY = mTmpParams.transY + (mTmpParams.scale * mIntrinsicIconSize) / 2;
@@ -610,7 +456,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
float iconSize = mLauncher.getDeviceProfile().iconSizePx;
final float scale = iconSize / mReferenceDrawable.getIntrinsicWidth();
- final float trans = (mAvailableSpaceInPreview - iconSize) / 2;
+ final float trans = (mBackground.previewSize - iconSize) / 2;
params.update(trans, trans, scale);
return params;
@@ -642,24 +488,284 @@ public class FolderIcon extends FrameLayout implements FolderListener {
canvas.restore();
}
+ public static class PreviewBackground {
+ private float mScale = 1f;
+ private float mColorMultiplier = 1f;
+ private Path mClipPath = new Path();
+ private int mStrokeWidth;
+ private View mInvalidateDeligate;
+
+ public int previewSize;
+ private int basePreviewOffsetX;
+ private int basePreviewOffsetY;
+
+ private CellLayout mDrawingDelegate;
+ public int delegateCellX;
+ public int delegateCellY;
+
+ // Drawing / animation configurations
+ private static final float ACCEPT_SCALE_FACTOR = 1.25f;
+ private static final float ACCEPT_COLOR_MULTIPLIER = 1.5f;
+
+ // Expressed on a scale from 0 to 255.
+ private static final int BG_OPACITY = 160;
+ private static final int MAX_BG_OPACITY = 225;
+ private static final int BG_INTENSITY = 245;
+ private static final int SHADOW_OPACITY = 80;
+
+ ValueAnimator mScaleAnimator;
+
+ public void setup(DisplayMetrics dm, DeviceProfile grid, View invalidateDeligate,
+ int availableSpace, int topPadding) {
+ mInvalidateDeligate = invalidateDeligate;
+
+ final int previewSize = grid.folderIconSizePx;
+ final int previewPadding = grid.folderIconPreviewPadding;
+
+ this.previewSize = (previewSize - 2 * previewPadding);
+
+ basePreviewOffsetX = (availableSpace - this.previewSize) / 2;
+ basePreviewOffsetY = previewPadding + grid.folderBackgroundOffset + topPadding;
+
+ mStrokeWidth = Utilities.pxFromDp(1, dm);
+
+ invalidate();
+ }
+
+ int getRadius() {
+ return previewSize / 2;
+ }
+
+ int getScaledRadius() {
+ return (int) (mScale * getRadius());
+ }
+
+ int getOffsetX() {
+ return basePreviewOffsetX - (getScaledRadius() - getRadius());
+ }
+
+ int getOffsetY() {
+ return basePreviewOffsetY - (getScaledRadius() - getRadius());
+ }
+
+ void invalidate() {
+ int radius = getScaledRadius();
+ mClipPath.reset();
+ mClipPath.addCircle(radius, radius, radius, Path.Direction.CW);
+
+ if (mInvalidateDeligate != null) {
+ mInvalidateDeligate.invalidate();
+ }
+
+ if (mDrawingDelegate != null) {
+ mDrawingDelegate.invalidate();
+ }
+ }
+
+ void setInvalidateDeligate(View invalidateDeligate) {
+ mInvalidateDeligate = invalidateDeligate;
+ invalidate();
+ }
+
+ public void drawBackground(Canvas canvas, Paint paint) {
+ canvas.save();
+ canvas.translate(getOffsetX(), getOffsetY());
+
+ paint.reset();
+ paint.setStyle(Paint.Style.FILL);
+ paint.setXfermode(null);
+ paint.setAntiAlias(true);
+
+ int alpha = (int) Math.min(MAX_BG_OPACITY, BG_OPACITY * mColorMultiplier);
+ paint.setColor(Color.argb(alpha, BG_INTENSITY, BG_INTENSITY, BG_INTENSITY));
+
+ float radius = getScaledRadius();
+
+ canvas.drawCircle(radius, radius, radius, paint);
+ canvas.clipPath(mClipPath, Region.Op.DIFFERENCE);
+
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setColor(Color.TRANSPARENT);
+ paint.setShadowLayer(mStrokeWidth, 0, mStrokeWidth, Color.argb(SHADOW_OPACITY, 0, 0, 0));
+ canvas.drawCircle(radius, radius, radius, paint);
+
+ canvas.restore();
+ }
+
+ public void drawBackgroundStroke(Canvas canvas, Paint paint) {
+ canvas.save();
+ canvas.translate(getOffsetX(), getOffsetY());
+
+ paint.reset();
+ paint.setAntiAlias(true);
+ paint.setColor(Color.argb(255, BG_INTENSITY, BG_INTENSITY, BG_INTENSITY));
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeWidth(mStrokeWidth);
+
+ float radius = getScaledRadius();
+ canvas.drawCircle(radius, radius, radius - 1, paint);
+
+ canvas.restore();
+ }
+
+ public void drawLeaveBehind(Canvas canvas, Paint paint) {
+ float originalScale = mScale;
+ mScale = 0.5f;
+
+ canvas.save();
+ canvas.translate(getOffsetX(), getOffsetY());
+
+ paint.reset();
+ paint.setAntiAlias(true);
+ paint.setColor(Color.argb(160, 245, 245, 245));
+
+ float radius = getScaledRadius();
+ canvas.drawCircle(radius, radius, radius, paint);
+
+ canvas.restore();
+ mScale = originalScale;
+ }
+
+ // It is the callers responsibility to save and restore the canvas.
+ private void clipCanvas(Canvas canvas) {
+ canvas.translate(getOffsetX(), getOffsetY());
+ canvas.clipPath(mClipPath);
+ canvas.translate(-getOffsetX(), -getOffsetY());
+ }
+
+ private void delegateDrawing(CellLayout delegate, int cellX, int cellY) {
+ if (mDrawingDelegate != delegate) {
+ delegate.addFolderBackground(this);
+ }
+
+ mDrawingDelegate = delegate;
+ delegateCellX = cellX;
+ delegateCellY = cellY;
+
+ invalidate();
+ }
+
+ private void clearDrawingDelegate() {
+ if (mDrawingDelegate != null) {
+ mDrawingDelegate.removeFolderBackground(this);
+ }
+
+ mDrawingDelegate = null;
+ invalidate();
+ }
+
+ private boolean drawingDelegated() {
+ return mDrawingDelegate != null;
+ }
+
+ private void animateScale(float finalScale, float finalMultiplier,
+ final Runnable onStart, final Runnable onEnd) {
+ final float scale0 = mScale;
+ final float scale1 = finalScale;
+
+ final float bgMultiplier0 = mColorMultiplier;
+ final float bgMultiplier1 = finalMultiplier;
+
+ if (mScaleAnimator != null) {
+ mScaleAnimator.cancel();
+ }
+
+ mScaleAnimator = LauncherAnimUtils.ofFloat(null, 0f, 1.0f);
+
+ mScaleAnimator.addUpdateListener(new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float prog = animation.getAnimatedFraction();
+ mScale = prog * scale1 + (1 - prog) * scale0;
+ mColorMultiplier = prog * bgMultiplier1 + (1 - prog) * bgMultiplier0;
+ invalidate();
+ }
+ });
+ mScaleAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ if (onStart != null) {
+ onStart.run();
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (onEnd != null) {
+ onEnd.run();
+ }
+ mScaleAnimator = null;
+ }
+ });
+
+ mScaleAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
+ mScaleAnimator.start();
+ }
+
+ public void animateToAccept(final CellLayout cl, final int cellX, final int cellY) {
+ Runnable onStart = new Runnable() {
+ @Override
+ public void run() {
+ delegateDrawing(cl, cellX, cellY);
+ }
+ };
+ animateScale(ACCEPT_SCALE_FACTOR, ACCEPT_COLOR_MULTIPLIER, onStart, null);
+ }
+
+ public void animateToRest() {
+ // This can be called multiple times -- we need to make sure the drawing delegate
+ // is saved and restored at the beginning of the animation, since cancelling the
+ // existing animation can clear the delgate.
+ final CellLayout cl = mDrawingDelegate;
+ final int cellX = delegateCellX;
+ final int cellY = delegateCellY;
+
+ Runnable onStart = new Runnable() {
+ @Override
+ public void run() {
+ delegateDrawing(cl, cellX, cellY);
+ }
+ };
+ Runnable onEnd = new Runnable() {
+ @Override
+ public void run() {
+ clearDrawingDelegate();
+ }
+ };
+ animateScale(1f, 1f, onStart, onEnd);
+ }
+ }
+
+ public void setFolderBackground(PreviewBackground bg) {
+ mBackground = bg;
+ mBackground.setInvalidateDeligate(this);
+ }
+
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
- if (mFolder == null) return;
- if (mFolder.getItemCount() == 0 && !mAnimating) return;
-
if (mReferenceDrawable != null) {
computePreviewDrawingParams(mReferenceDrawable);
}
+ if (!mBackground.drawingDelegated()) {
+ mBackground.drawBackground(canvas, mBgPaint);
+ }
+
+ if (mFolder == null) return;
+ if (mFolder.getItemCount() == 0 && !mAnimating) return;
+
canvas.save();
- canvas.translate(mPreviewOffsetX, mPreviewOffsetY);
- Path clipPath = mPreviewLayoutRule.getClipPath();
- if (clipPath != null) {
- canvas.clipPath(clipPath);
+
+
+ if (mPreviewLayoutRule.clipToBackground()) {
+ mBackground.clipCanvas(canvas);
}
+ // The items are drawn in coordinates relative to the preview offset
+ canvas.translate(mBackground.basePreviewOffsetX, mBackground.basePreviewOffsetY);
+
// The first item should be drawn last (ie. on top of later items)
for (int i = mDrawingParams.size() - 1; i >= 0; i--) {
PreviewItemDrawingParams p = mDrawingParams.get(i);
@@ -668,6 +774,10 @@ public class FolderIcon extends FrameLayout implements FolderListener {
}
}
canvas.restore();
+
+ if (mPreviewLayoutRule.clipToBackground() && !mBackground.drawingDelegated()) {
+ mBackground.drawBackgroundStroke(canvas, mBgPaint);
+ }
}
private Drawable getTopDrawable(TextView v) {
@@ -793,7 +903,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
PreviewItemDrawingParams p = mDrawingParams.get(i);
p.drawable = getTopDrawable((TextView) items.get(i));
- if (!animate || !FeatureFlags.LAUNCHER3_CLIPPED_FOLDER_ICON) {
+ if (!animate || FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON) {
computePreviewItemDrawingParams(i, nItemsInPreview, p);
if (mReferenceDrawable == null) {
mReferenceDrawable = p.drawable;
@@ -884,6 +994,6 @@ public class FolderIcon extends FrameLayout implements FolderListener {
public void init(int availableSpace, int intrinsicIconSize, boolean rtl);
public int numItems();
- public Path getClipPath();
+ public boolean clipToBackground();
}
}
diff --git a/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java b/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java
index 005307209..7fb02e313 100644
--- a/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java
+++ b/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java
@@ -85,7 +85,7 @@ public class StackFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule {
}
@Override
- public Path getClipPath() {
- return null;
+ public boolean clipToBackground() {
+ return false;
}
}