diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java index 642451d8aa..4ae54e69f1 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -559,7 +559,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo .inflate(R.layout.user_folder_icon_normalized, null); } - private void startAnimation(final AnimatorSet a) { + private void addAnimationStartListeners(AnimatorSet a) { mLauncherDelegate.forEachVisibleWorkspacePage( visiblePage -> addAnimatorListenerForPage(a, (CellLayout) visiblePage)); @@ -575,7 +575,6 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo mCurrentAnimator = null; } }); - a.start(); } private void addAnimatorListenerForPage(AnimatorSet a, CellLayout currentCellLayout) { @@ -735,10 +734,14 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo mPageIndicator.stopAllAnimations(); + // b/282158620 because setCurrentPlayTime() below will start animator, we need to register + // {@link AnimatorListener} before it so that {@link AnimatorListener#onAnimationStart} can + // be called to register mCurrentAnimator, which will be used to cancel animator + addAnimationStartListeners(anim); // Because t=0 has the folder match the folder icon, we can skip the // first frame and have the same movement one frame earlier. anim.setCurrentPlayTime(Math.min(getSingleFrameMs(getContext()), anim.getTotalDuration())); - startAnimation(anim); + anim.start(); // Make sure the folder picks up the last drag move even if the finger doesn't move. if (mDragController.isDragging()) { @@ -816,7 +819,8 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo mIsAnimatingClosed = false; } }); - startAnimation(a); + addAnimationStartListeners(a); + a.start(); } @Override diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java index 05ad57acd4..2ce6c785c2 100644 --- a/src/com/android/launcher3/folder/FolderAnimationManager.java +++ b/src/com/android/launcher3/folder/FolderAnimationManager.java @@ -265,23 +265,37 @@ public class FolderAnimationManager { Animator z = getAnimator(mFolder, View.TRANSLATION_Z, -mFolder.getElevation(), 0); play(a, z, mIsOpening ? midDuration : 0, midDuration); - // Store clip variables - CellLayout cellLayout = mContent.getCurrentCellLayout(); - boolean folderClipChildren = mFolder.getClipChildren(); - boolean folderClipToPadding = mFolder.getClipToPadding(); - boolean contentClipChildren = mContent.getClipChildren(); - boolean contentClipToPadding = mContent.getClipToPadding(); - boolean cellLayoutClipChildren = cellLayout.getClipChildren(); - boolean cellLayoutClipPadding = cellLayout.getClipToPadding(); - - mFolder.setClipChildren(false); - mFolder.setClipToPadding(false); - mContent.setClipChildren(false); - mContent.setClipToPadding(false); - cellLayout.setClipChildren(false); - cellLayout.setClipToPadding(false); - + // Store clip variables. + // Because {@link #onAnimationStart} and {@link #onAnimationEnd} callbacks are sent to + // message queue and executed on separate frame, we should save states in + // {@link #onAnimationStart} instead of before creating animator, so that cancelling + // animation A and restarting animation B allows A to reset states in + // {@link #onAnimationEnd} before B reads new UI state from {@link #onAnimationStart}. a.addListener(new AnimatorListenerAdapter() { + private CellLayout mCellLayout; + private boolean mFolderClipToPadding; + private boolean mContentClipChildren; + private boolean mContentClipToPadding; + private boolean mCellLayoutClipChildren; + private boolean mCellLayoutClipPadding; + + @Override + public void onAnimationStart(Animator animator) { + super.onAnimationStart(animator); + mCellLayout = mContent.getCurrentCellLayout(); + mFolderClipToPadding = mFolder.getClipToPadding(); + mContentClipChildren = mContent.getClipChildren(); + mContentClipToPadding = mContent.getClipToPadding(); + mCellLayoutClipChildren = mCellLayout.getClipChildren(); + mCellLayoutClipPadding = mCellLayout.getClipToPadding(); + + mFolder.setClipToPadding(false); + mContent.setClipChildren(false); + mContent.setClipToPadding(false); + mCellLayout.setClipChildren(false); + mCellLayout.setClipToPadding(false); + } + @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); @@ -295,13 +309,11 @@ public class FolderAnimationManager { mFolder.mFooter.setTranslationX(0f); mFolder.mFolderName.setAlpha(1f); - mFolder.setClipChildren(folderClipChildren); - mFolder.setClipToPadding(folderClipToPadding); - mContent.setClipChildren(contentClipChildren); - mContent.setClipToPadding(contentClipToPadding); - cellLayout.setClipChildren(cellLayoutClipChildren); - cellLayout.setClipToPadding(cellLayoutClipPadding); - + mFolder.setClipToPadding(mFolderClipToPadding); + mContent.setClipChildren(mContentClipChildren); + mContent.setClipToPadding(mContentClipToPadding); + mCellLayout.setClipChildren(mCellLayoutClipChildren); + mCellLayout.setClipToPadding(mCellLayoutClipPadding); } });