Removing separate Cancel and End callbacks and using AnimationListener instead
This removes the additional step of invoking these callbacks separately
Change-Id: I0b60047a44f179ba725f15b1e791e336884869c9
diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java
index d9cf7f1..803f8d2 100644
--- a/src/com/android/launcher3/LauncherAnimUtils.java
+++ b/src/com/android/launcher3/LauncherAnimUtils.java
@@ -16,6 +16,9 @@
package com.android.launcher3;
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
import android.graphics.drawable.Drawable;
import android.util.FloatProperty;
import android.util.IntProperty;
@@ -29,8 +32,8 @@
*/
public static final int SPRING_LOADED_EXIT_DELAY = 500;
- // The progress of an animation to all apps must be at least this far along to snap to all apps.
- public static final float MIN_PROGRESS_TO_ALL_APPS = 0.5f;
+ // Progress after which the transition is assumed to be a success
+ public static final float SUCCESS_TRANSITION_PROGRESS = 0.5f;
public static final IntProperty<Drawable> DRAWABLE_ALPHA =
new IntProperty<Drawable>("drawableAlpha") {
@@ -131,4 +134,23 @@
return view.getAlpha();
}
};
+
+ /**
+ * Utility method to create an {@link AnimatorListener} which executes a callback on animation
+ * cancel.
+ */
+ public static AnimatorListener newCancelListener(Runnable callback) {
+ return new AnimatorListenerAdapter() {
+
+ boolean mDispatched = false;
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ if (!mDispatched) {
+ mDispatched = true;
+ callback.run();
+ }
+ }
+ };
+ }
}
diff --git a/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java b/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java
index 08d573f..01d01ea 100644
--- a/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.allapps;
+import android.annotation.TargetApi;
import android.graphics.Insets;
import android.os.Build;
import android.util.Log;
@@ -26,9 +27,8 @@
import android.view.animation.LinearInterpolator;
import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
-import androidx.core.os.BuildCompat;
+import com.android.launcher3.Utilities;
import com.android.launcher3.util.UiThreadHelper;
/**
@@ -68,7 +68,7 @@
}
public void hide() {
- if (!BuildCompat.isAtLeastR()) return;
+ if (!Utilities.ATLEAST_R) return;
WindowInsets insets = mApps.getRootWindowInsets();
if (insets == null) return;
@@ -89,9 +89,9 @@
*
* @param progress value between 0..1
*/
- @RequiresApi(api = Build.VERSION_CODES.R)
+ @TargetApi(Build.VERSION_CODES.R)
public void onDragStart(float progress) {
- if (!BuildCompat.isAtLeastR()) return;
+ if (!Utilities.ATLEAST_R) return;
// Until getRootWindowInsets().isVisible(...) method returns correct value,
// only support InsetController based IME transition during swipe up and
@@ -164,7 +164,7 @@
* If IME bounds after touch sequence finishes, call finish.
*/
private boolean handleFinishOnFling(WindowInsetsAnimationController controller) {
- if (!BuildCompat.isAtLeastR()) return false;
+ if (!Utilities.ATLEAST_R) return false;
if (mState == State.FLING_END_TOP) {
controller.finish(true);
@@ -181,9 +181,9 @@
*
* @param progress value between 0..1
*/
- @RequiresApi(api = 30)
+ @TargetApi(Build.VERSION_CODES.R)
public void setProgress(float progress) {
- if (!BuildCompat.isAtLeastR()) return;
+ if (!Utilities.ATLEAST_R) return;
// progress that equals to 0 or 1 is error prone. Do not use them.
// Instead use onDragStart and onAnimationEnd
if (mAnimationController == null || progress <= 0f || progress >= 1f) return;
@@ -218,7 +218,7 @@
*
* @param progress value between 0..1
*/
- @RequiresApi(api = 30)
+ @TargetApi(Build.VERSION_CODES.R)
public void onAnimationEnd(float progress) {
if (DEBUG) {
Log.d(TAG, "onAnimationEnd progress=" + progress
diff --git a/src/com/android/launcher3/anim/AnimatorPlaybackController.java b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
index dcdfb6e..edaf51d 100644
--- a/src/com/android/launcher3/anim/AnimatorPlaybackController.java
+++ b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
@@ -29,8 +29,6 @@
import android.animation.ValueAnimator;
import android.content.Context;
-import androidx.annotation.Nullable;
-
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -72,7 +70,6 @@
private Runnable mEndAction;
protected boolean mTargetCancelled = false;
- protected Runnable mOnCancelRunnable;
/** package private */
AnimatorPlaybackController(AnimatorSet anim, long duration, ArrayList<Holder> childAnims) {
@@ -88,16 +85,11 @@
@Override
public void onAnimationCancel(Animator animation) {
mTargetCancelled = true;
- if (mOnCancelRunnable != null) {
- mOnCancelRunnable.run();
- mOnCancelRunnable = null;
- }
}
@Override
public void onAnimationEnd(Animator animation) {
mTargetCancelled = false;
- mOnCancelRunnable = null;
}
@Override
@@ -269,33 +261,6 @@
}
}
- /** @see #dispatchOnCancelWithoutCancelRunnable(Runnable) */
- public void dispatchOnCancelWithoutCancelRunnable() {
- dispatchOnCancelWithoutCancelRunnable(null);
- }
-
- /**
- * Sets mOnCancelRunnable = null before dispatching the cancel and restoring the runnable. This
- * is intended to be used only if you need to cancel but want to defer cleaning up yourself.
- * @param callback An optional callback to run after dispatching the cancel but before resetting
- * the onCancelRunnable.
- */
- public void dispatchOnCancelWithoutCancelRunnable(@Nullable Runnable callback) {
- Runnable onCancel = mOnCancelRunnable;
- setOnCancelRunnable(null);
- dispatchOnCancel();
- if (callback != null) {
- callback.run();
- }
- setOnCancelRunnable(onCancel);
- }
-
-
- public AnimatorPlaybackController setOnCancelRunnable(Runnable runnable) {
- mOnCancelRunnable = runnable;
- return this;
- }
-
public void dispatchOnStart() {
callListenerCommandRecursively(mAnim, AnimatorListener::onAnimationStart);
}
diff --git a/src/com/android/launcher3/anim/PendingAnimation.java b/src/com/android/launcher3/anim/PendingAnimation.java
index 6dd316e..4e90c9e 100644
--- a/src/com/android/launcher3/anim/PendingAnimation.java
+++ b/src/com/android/launcher3/anim/PendingAnimation.java
@@ -15,10 +15,12 @@
*/
package com.android.launcher3.anim;
+import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
import static com.android.launcher3.anim.AnimatorPlaybackController.addAnimationHoldersRecur;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
@@ -43,8 +45,6 @@
*/
public class PendingAnimation implements PropertySetter {
- private final ArrayList<Consumer<EndState>> mEndListeners = new ArrayList<>();
-
private final ArrayList<Holder> mAnimHolders = new ArrayList<>();
private final AnimatorSet mAnim;
private final long mDuration;
@@ -73,13 +73,6 @@
addAnimationHoldersRecur(a, mDuration, springProperty, mAnimHolders);
}
- public void finish(boolean isSuccess) {
- for (Consumer<EndState> listeners : mEndListeners) {
- listeners.accept(new EndState(isSuccess));
- }
- mEndListeners.clear();
- }
-
@Override
public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
if (view == null || view.getAlpha() == alpha) {
@@ -163,19 +156,38 @@
}
/**
- * Add a listener of receiving the end state.
- * Note that the listeners are called as a result of calling {@link #finish(boolean)}
- * and not automatically
+ * Add a listener of receiving the success/failure callback in the end.
*/
- public void addEndListener(Consumer<EndState> listener) {
- mEndListeners.add(listener);
+ public void addEndListener(Consumer<Boolean> listener) {
+ if (mProgressAnimator == null) {
+ mProgressAnimator = ValueAnimator.ofFloat(0, 1);
+ }
+ mProgressAnimator.addListener(new EndStateCallbackWrapper(listener));
}
- public static class EndState {
- public boolean isSuccess;
+ private static class EndStateCallbackWrapper extends AnimatorListenerAdapter {
- public EndState(boolean isSuccess) {
- this.isSuccess = isSuccess;
+ private final Consumer<Boolean> mListener;
+ private boolean mCalled = false;
+
+ EndStateCallbackWrapper(Consumer<Boolean> listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ if (!mCalled) {
+ mCalled = true;
+ mListener.accept(false);
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!mCalled) {
+ ValueAnimator anim = (ValueAnimator) animation;
+ mListener.accept(anim.getAnimatedFraction() > SUCCESS_TRANSITION_PROGRESS);
+ }
}
}
}
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 57c0ad9..a9d0e61 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -15,7 +15,8 @@
*/
package com.android.launcher3.touch;
-import static com.android.launcher3.LauncherAnimUtils.MIN_PROGRESS_TO_ALL_APPS;
+import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
+import static com.android.launcher3.LauncherAnimUtils.newCancelListener;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
@@ -32,6 +33,7 @@
import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
@@ -48,7 +50,6 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.StatsLogManager;
@@ -64,9 +65,6 @@
public abstract class AbstractStateChangeTouchController
implements TouchController, SingleAxisSwipeDetector.Listener {
- // Progress after which the transition is assumed to be a success in case user does not fling
- public static final float SUCCESS_TRANSITION_PROGRESS = 0.5f;
-
/**
* Play an atomic recents animation when the progress from NORMAL to OVERVIEW reaches this.
*/
@@ -77,6 +75,9 @@
protected final SingleAxisSwipeDetector mDetector;
protected final SingleAxisSwipeDetector.Direction mSwipeDirection;
+ protected final AnimatorListener mClearStateOnCancelListener =
+ newCancelListener(this::clearState);
+
private boolean mNoIntercept;
private boolean mIsLogContainerSet;
protected int mStartContainerType;
@@ -85,7 +86,7 @@
protected LauncherState mFromState;
protected LauncherState mToState;
protected AnimatorPlaybackController mCurrentAnimation;
- protected PendingAnimation mPendingAnimation;
+ protected boolean mGoingBetweenStates = true;
private float mStartProgress;
// Ratio of transition process [0, 1] to drag displacement (px)
@@ -209,7 +210,7 @@
mStartProgress = 0;
mPassedOverviewAtomicThreshold = false;
if (mCurrentAnimation != null) {
- mCurrentAnimation.setOnCancelRunnable(null);
+ mCurrentAnimation.getTarget().removeListener(mClearStateOnCancelListener);
}
int animComponents = goingBetweenNormalAndOverview(mFromState, mToState)
? PLAY_NON_ATOMIC : ANIM_ALL_COMPONENTS;
@@ -237,7 +238,7 @@
LauncherState toState) {
return (fromState == NORMAL || fromState == OVERVIEW)
&& (toState == NORMAL || toState == OVERVIEW)
- && mPendingAnimation == null;
+ && mGoingBetweenStates;
}
@Override
@@ -412,9 +413,8 @@
? mToState : mFromState;
// snap to top or bottom using the release velocity
} else {
- float successProgress = mToState == ALL_APPS
- ? MIN_PROGRESS_TO_ALL_APPS : SUCCESS_TRANSITION_PROGRESS;
- targetState = (interpolatedProgress > successProgress) ? mToState : mFromState;
+ targetState =
+ (interpolatedProgress > SUCCESS_TRANSITION_PROGRESS) ? mToState : mFromState;
}
final float endProgress;
@@ -438,7 +438,8 @@
} else {
// Let the state manager know that the animation didn't go to the target state,
// but don't cancel ourselves (we already clean up when the animation completes).
- mCurrentAnimation.dispatchOnCancelWithoutCancelRunnable();
+ mCurrentAnimation.getTarget().removeListener(mClearStateOnCancelListener);
+ mCurrentAnimation.dispatchOnCancel();
endProgress = 0;
if (progress <= 0) {
@@ -522,13 +523,7 @@
mAtomicComponentsController = null;
}
clearState();
- boolean shouldGoToTargetState = true;
- if (mPendingAnimation != null) {
- boolean reachedTarget = mToState == targetState;
- mPendingAnimation.finish(reachedTarget);
- mPendingAnimation = null;
- shouldGoToTargetState = !reachedTarget;
- }
+ boolean shouldGoToTargetState = mGoingBetweenStates || (mToState != targetState);
if (shouldGoToTargetState) {
goToTargetState(targetState);
}
@@ -568,6 +563,7 @@
mAtomicAnim.cancel();
mAtomicAnim = null;
}
+ mGoingBetweenStates = true;
mScheduleResumeAtomicComponent = false;
mDetector.finishedScrolling();
mDetector.setDetectableScrollConditions(0, false);