Moving animation config so a separate class
Using PendingAnimation for animation builder.
This will allow us to easily add SpringAnimation to stateAnimation
Change-Id: I8d88489a5da6fc85747ef9be7c13858b441cd28a
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index af2cdc3..12b5fc1 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -22,7 +22,6 @@
import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
-import android.animation.Animator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
@@ -30,11 +29,12 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.animation.Interpolator;
import android.widget.LinearLayout;
import androidx.annotation.IntDef;
-import androidx.annotation.Nullable;
+import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.TouchController;
@@ -134,9 +134,8 @@
* Creates a user-controlled animation to hint that the view will be closed if completed.
* @param distanceToMove The max distance that elements should move from their starting point.
*/
- public @Nullable Animator createHintCloseAnim(float distanceToMove) {
- return null;
- }
+ public void addHintCloseAnim(
+ float distanceToMove, Interpolator interpolator, PendingAnimation target) { }
public abstract void logActionCommand(int command);
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 62b8927..df71f16 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -20,11 +20,6 @@
import static android.view.View.VISIBLE;
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
-import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
-import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
-import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_X;
-import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
-import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
@@ -32,6 +27,11 @@
import static com.android.launcher3.anim.Interpolators.clampToProgress;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.testing.TestProtocol.ALL_APPS_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.BACKGROUND_APP_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.HINT_STATE_ORDINAL;
@@ -46,9 +46,9 @@
import android.view.animation.Interpolator;
import com.android.launcher3.allapps.AllAppsContainerView;
-import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.states.HintState;
import com.android.launcher3.states.SpringLoadedState;
+import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.uioverrides.states.AllAppsState;
import com.android.launcher3.uioverrides.states.OverviewState;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -325,13 +325,13 @@
* - Setting some start values (e.g. scale) for views that are hidden but about to be shown.
*/
public void prepareForAtomicAnimation(Launcher launcher, LauncherState fromState,
- AnimatorSetBuilder builder) {
+ StateAnimationConfig config) {
if (this == NORMAL && fromState == OVERVIEW) {
- builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
- builder.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
- builder.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
- builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL);
- builder.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7);
+ config.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
+ config.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
+ config.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
+ config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL);
+ config.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7);
Workspace workspace = launcher.getWorkspace();
// Start from a higher workspace scale, but only if we're invisible so we don't jump.
@@ -363,7 +363,7 @@
}
} else if (this == NORMAL && fromState == OVERVIEW_PEEK) {
// Keep fully visible until the very end (when overview is offscreen) to make invisible.
- builder.setInterpolator(ANIM_OVERVIEW_FADE, t -> t < 1 ? 0 : 1);
+ config.setInterpolator(ANIM_OVERVIEW_FADE, t -> t < 1 ? 0 : 1);
}
}
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 04134f2..24d0c41 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -17,26 +17,23 @@
package com.android.launcher3;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.os.Handler;
import android.os.Looper;
-import androidx.annotation.IntDef;
-
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.anim.AnimatorSetBuilder;
-import com.android.launcher3.anim.PropertySetter;
-import com.android.launcher3.anim.PropertySetter.AnimatedPropertySetter;
+import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
+import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
/**
@@ -84,28 +81,7 @@
public static final String TAG = "StateManager";
- // We separate the state animations into "atomic" and "non-atomic" components. The atomic
- // components may be run atomically - that is, all at once, instead of user-controlled. However,
- // atomic components are not restricted to this purpose; they can be user-controlled alongside
- // non atomic components as well. Note that each gesture model has exactly one atomic component,
- // PLAY_ATOMIC_OVERVIEW_SCALE *or* PLAY_ATOMIC_OVERVIEW_PEEK.
- @IntDef(flag = true, value = {
- PLAY_NON_ATOMIC,
- PLAY_ATOMIC_OVERVIEW_SCALE,
- PLAY_ATOMIC_OVERVIEW_PEEK,
- SKIP_OVERVIEW,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface AnimationFlags {}
- public static final int PLAY_NON_ATOMIC = 1 << 0;
- public static final int PLAY_ATOMIC_OVERVIEW_SCALE = 1 << 1;
- public static final int PLAY_ATOMIC_OVERVIEW_PEEK = 1 << 2;
- public static final int SKIP_OVERVIEW = 1 << 3;
-
- public static final int ANIM_ALL_COMPONENTS = PLAY_NON_ATOMIC | PLAY_ATOMIC_OVERVIEW_SCALE
- | PLAY_ATOMIC_OVERVIEW_PEEK;
-
- private final AnimationConfig mConfig = new AnimationConfig();
+ private final AnimationState mConfig = new AnimationState();
private final Handler mUiHandler;
private final Launcher mLauncher;
private final ArrayList<StateListener> mListeners = new ArrayList<>();
@@ -140,7 +116,7 @@
writer.println(prefix + "\tmCurrentStableState:" + mCurrentStableState);
writer.println(prefix + "\tmState:" + mState);
writer.println(prefix + "\tmRestState:" + mRestState);
- writer.println(prefix + "\tisInTransition:" + (mConfig.mCurrentAnimation != null));
+ writer.println(prefix + "\tisInTransition:" + (mConfig.currentAnimation != null));
}
public StateHandler[] getStateHandlers() {
@@ -171,7 +147,7 @@
*/
public boolean isInStableState(LauncherState state) {
return mState == state && mCurrentStableState == state
- && (mConfig.mTargetState == null || mConfig.mTargetState == state);
+ && (mConfig.targetState == null || mConfig.targetState == state);
}
/**
@@ -218,12 +194,12 @@
}
public void reapplyState(boolean cancelCurrentAnimation) {
- boolean wasInAnimation = mConfig.mCurrentAnimation != null;
+ boolean wasInAnimation = mConfig.currentAnimation != null;
if (cancelCurrentAnimation) {
cancelAllStateElementAnimation();
cancelAnimation();
}
- if (mConfig.mCurrentAnimation == null) {
+ if (mConfig.currentAnimation == null) {
for (StateHandler handler : getStateHandlers()) {
handler.setState(mState);
}
@@ -237,16 +213,16 @@
final Runnable onCompleteRunnable) {
animated &= Utilities.areAnimationsEnabled(mLauncher);
if (mLauncher.isInState(state)) {
- if (mConfig.mCurrentAnimation == null) {
+ if (mConfig.currentAnimation == null) {
// Run any queued runnable
if (onCompleteRunnable != null) {
onCompleteRunnable.run();
}
return;
- } else if (!mConfig.userControlled && animated && mConfig.mTargetState == state) {
+ } else if (!mConfig.userControlled && animated && mConfig.targetState == state) {
// We are running the same animation as requested
if (onCompleteRunnable != null) {
- mConfig.mCurrentAnimation.addListener(
+ mConfig.currentAnimation.addListener(
AnimationSuccessListener.forRunnable(onCompleteRunnable));
}
return;
@@ -276,9 +252,9 @@
if (delay > 0) {
// Create the animation after the delay as some properties can change between preparing
// the animation and running the animation.
- int startChangeId = mConfig.mChangeId;
+ int startChangeId = mConfig.changeId;
mUiHandler.postDelayed(() -> {
- if (mConfig.mChangeId == startChangeId) {
+ if (mConfig.changeId == startChangeId) {
goToStateAnimated(state, fromState, onCompleteRunnable);
}
}, delay);
@@ -294,11 +270,11 @@
mConfig.duration = state == NORMAL
? fromState.getTransitionDuration(mLauncher)
: state.getTransitionDuration(mLauncher);
-
- AnimatorSetBuilder builder = new AnimatorSetBuilder();
- prepareForAtomicAnimation(fromState, state, builder);
- AnimatorSet animation = createAnimationToNewWorkspaceInternal(
- state, builder, onCompleteRunnable);
+ prepareForAtomicAnimation(fromState, state, mConfig);
+ AnimatorSet animation = createAnimationToNewWorkspaceInternal(state).getAnim();
+ if (onCompleteRunnable != null) {
+ animation.addListener(AnimationSuccessListener.forRunnable(onCompleteRunnable));
+ }
mUiHandler.post(new StartAnimRunnable(animation));
}
@@ -308,44 +284,22 @@
* - Setting some start values (e.g. scale) for views that are hidden but about to be shown.
*/
public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toState,
- AnimatorSetBuilder builder) {
- toState.prepareForAtomicAnimation(mLauncher, fromState, builder);
- }
-
- public AnimatorSet createAtomicAnimation(LauncherState fromState, LauncherState toState,
- AnimatorSetBuilder builder, @AnimationFlags int animFlags, long duration) {
- prepareForAtomicAnimation(fromState, toState, builder);
- AnimationConfig config = new AnimationConfig();
- config.mAnimFlags = animFlags;
- config.duration = duration;
- for (StateHandler handler : mLauncher.getStateManager().getStateHandlers()) {
- handler.setStateWithAnimation(toState, builder, config);
- }
- return builder.build();
+ StateAnimationConfig config) {
+ toState.prepareForAtomicAnimation(mLauncher, fromState, config);
}
/**
- * Creates a {@link AnimatorPlaybackController} that can be used for a controlled
- * state transition. The UI is force-set to fromState before creating the controller.
- * @param fromState the initial state for the transition.
- * @param state the final state for the transition.
- * @param duration intended duration for normal playback. Use higher duration for better
- * accuracy.
+ * Creates an animation representing atomic transitions between the provided states
*/
- public AnimatorPlaybackController createAnimationToNewWorkspace(
- LauncherState fromState, LauncherState state, long duration) {
- // Since we are creating a state animation to a different state, temporarily prevent state
- // change as part of config reset.
- LauncherState originalRestState = mRestState;
- mRestState = state;
- mConfig.reset();
- mRestState = originalRestState;
+ public AnimatorSet createAtomicAnimation(
+ LauncherState fromState, LauncherState toState, StateAnimationConfig config) {
+ PendingAnimation builder = new PendingAnimation(config.duration);
+ prepareForAtomicAnimation(fromState, toState, config);
- for (StateHandler handler : getStateHandlers()) {
- handler.setState(fromState);
+ for (StateHandler handler : mLauncher.getStateManager().getStateHandlers()) {
+ handler.setStateWithAnimation(toState, config, builder);
}
-
- return createAnimationToNewWorkspace(state, duration);
+ return builder.getAnim();
}
/**
@@ -362,32 +316,27 @@
public AnimatorPlaybackController createAnimationToNewWorkspace(
LauncherState state, long duration, @AnimationFlags int animComponents) {
- return createAnimationToNewWorkspace(state, new AnimatorSetBuilder(), duration, null,
- animComponents);
+ StateAnimationConfig config = new StateAnimationConfig();
+ config.duration = duration;
+ config.animFlags = animComponents;
+ return createAnimationToNewWorkspace(state, config);
}
public AnimatorPlaybackController createAnimationToNewWorkspace(LauncherState state,
- AnimatorSetBuilder builder, long duration, Runnable onCancelRunnable,
- @AnimationFlags int animComponents) {
+ StateAnimationConfig config) {
mConfig.reset();
- mConfig.userControlled = true;
- mConfig.mAnimFlags = animComponents;
- mConfig.duration = duration;
- mConfig.playbackController = AnimatorPlaybackController.wrap(
- createAnimationToNewWorkspaceInternal(state, builder, null), duration)
- .setOnCancelRunnable(onCancelRunnable);
+ config.copyTo(mConfig);
+ mConfig.playbackController = createAnimationToNewWorkspaceInternal(state)
+ .createPlaybackController();
return mConfig.playbackController;
}
- protected AnimatorSet createAnimationToNewWorkspaceInternal(final LauncherState state,
- AnimatorSetBuilder builder, final Runnable onCompleteRunnable) {
-
+ private PendingAnimation createAnimationToNewWorkspaceInternal(final LauncherState state) {
+ PendingAnimation builder = new PendingAnimation(mConfig.duration);
for (StateHandler handler : getStateHandlers()) {
- handler.setStateWithAnimation(state, builder, mConfig);
+ handler.setStateWithAnimation(state, mConfig, builder);
}
-
- final AnimatorSet animation = builder.build();
- animation.addListener(new AnimationSuccessListener() {
+ builder.getAnim().addListener(new AnimationSuccessListener() {
@Override
public void onAnimationStart(Animator animation) {
@@ -397,15 +346,11 @@
@Override
public void onAnimationSuccess(Animator animator) {
- // Run any queued runnables
- if (onCompleteRunnable != null) {
- onCompleteRunnable.run();
- }
onStateTransitionEnd(state);
}
});
- mConfig.setAnimation(animation, state);
- return mConfig.mCurrentAnimation;
+ mConfig.setAnimation(builder.getAnim(), state);
+ return builder;
}
private void onStateTransitionStart(LauncherState state) {
@@ -452,7 +397,7 @@
}
public void moveToRestState() {
- if (mConfig.mCurrentAnimation != null && mConfig.userControlled) {
+ if (mConfig.currentAnimation != null && mConfig.userControlled) {
// The user is doing something. Lets not mess it up
return;
}
@@ -500,12 +445,12 @@
&& mConfig.playbackController.getTarget() == childAnim) {
clearCurrentAnimation();
break;
- } else if (mConfig.mCurrentAnimation == childAnim) {
+ } else if (mConfig.currentAnimation == childAnim) {
clearCurrentAnimation();
break;
}
}
- boolean reapplyNeeded = mConfig.mCurrentAnimation != null;
+ boolean reapplyNeeded = mConfig.currentAnimation != null;
cancelAnimation();
if (reapplyNeeded) {
reapplyState();
@@ -557,9 +502,9 @@
}
private void clearCurrentAnimation() {
- if (mConfig.mCurrentAnimation != null) {
- mConfig.mCurrentAnimation.removeListener(mConfig);
- mConfig.mCurrentAnimation = null;
+ if (mConfig.currentAnimation != null) {
+ mConfig.currentAnimation.removeListener(mConfig);
+ mConfig.currentAnimation = null;
}
mConfig.playbackController = null;
}
@@ -574,54 +519,42 @@
@Override
public void run() {
- if (mConfig.mCurrentAnimation != mAnim) {
+ if (mConfig.currentAnimation != mAnim) {
return;
}
mAnim.start();
}
}
- public static class AnimationConfig extends AnimatorListenerAdapter {
- public long duration;
- public boolean userControlled;
- public AnimatorPlaybackController playbackController;
- private @AnimationFlags int mAnimFlags = ANIM_ALL_COMPONENTS;
- private PropertySetter mPropertySetter;
+ private static class AnimationState extends StateAnimationConfig implements AnimatorListener {
- private AnimatorSet mCurrentAnimation;
- private LauncherState mTargetState;
+ private static final StateAnimationConfig DEFAULT = new StateAnimationConfig();
+
+ public AnimatorPlaybackController playbackController;
+ public AnimatorSet currentAnimation;
+ public LauncherState targetState;
+
// Id to keep track of config changes, to tie an animation with the corresponding request
- private int mChangeId = 0;
+ public int changeId = 0;
/**
* Cancels the current animation and resets config variables.
*/
public void reset() {
- duration = 0;
- userControlled = false;
- mAnimFlags = ANIM_ALL_COMPONENTS;
- mPropertySetter = null;
- mTargetState = null;
+ DEFAULT.copyTo(this);
+ targetState = null;
if (playbackController != null) {
playbackController.getAnimationPlayer().cancel();
playbackController.dispatchOnCancel();
- } else if (mCurrentAnimation != null) {
- mCurrentAnimation.setDuration(0);
- mCurrentAnimation.cancel();
+ } else if (currentAnimation != null) {
+ currentAnimation.setDuration(0);
+ currentAnimation.cancel();
}
- mCurrentAnimation = null;
+ currentAnimation = null;
playbackController = null;
- mChangeId ++;
- }
-
- public PropertySetter getPropertySetter(AnimatorSetBuilder builder) {
- if (mPropertySetter == null) {
- mPropertySetter = duration == 0 ? NO_ANIM_PROPERTY_SETTER
- : new AnimatedPropertySetter(duration, builder);
- }
- return mPropertySetter;
+ changeId++;
}
@Override
@@ -629,51 +562,25 @@
if (playbackController != null && playbackController.getTarget() == animation) {
playbackController = null;
}
- if (mCurrentAnimation == animation) {
- mCurrentAnimation = null;
+ if (currentAnimation == animation) {
+ currentAnimation = null;
}
}
public void setAnimation(AnimatorSet animation, LauncherState targetState) {
- mCurrentAnimation = animation;
- mTargetState = targetState;
- mCurrentAnimation.addListener(this);
+ currentAnimation = animation;
+ this.targetState = targetState;
+ currentAnimation.addListener(this);
}
- /**
- * @return Whether Overview is scaling as part of this animation. If this is the only
- * component (i.e. NON_ATOMIC_COMPONENT isn't included), then this scaling is happening
- * atomically, rather than being part of a normal state animation. StateHandlers can use
- * this to designate part of their animation that should scale with Overview.
- */
- public boolean playAtomicOverviewScaleComponent() {
- return hasAnimationFlag(PLAY_ATOMIC_OVERVIEW_SCALE);
- }
+ @Override
+ public void onAnimationStart(Animator animator) { }
- /**
- * @return Whether this animation will play atomically at the same time as a different,
- * user-controlled state transition. StateHandlers, which contribute to both animations, can
- * use this to avoid animating the same properties in both animations, since they'd conflict
- * with one another.
- */
- public boolean onlyPlayAtomicComponent() {
- return getAnimComponents() == PLAY_ATOMIC_OVERVIEW_SCALE
- || getAnimComponents() == PLAY_ATOMIC_OVERVIEW_PEEK;
- }
+ @Override
+ public void onAnimationCancel(Animator animator) { }
- /**
- * Returns true if the config and any of the provided component flags
- */
- public boolean hasAnimationFlag(@AnimationFlags int a) {
- return (mAnimFlags & a) != 0;
- }
-
- /**
- * @return Only the flags that determine which animation components to play.
- */
- public @AnimationFlags int getAnimComponents() {
- return mAnimFlags & ANIM_ALL_COMPONENTS;
- }
+ @Override
+ public void onAnimationRepeat(Animator animator) { }
}
public interface StateHandler {
@@ -686,8 +593,8 @@
/**
* Sets the UI to {@param state} by animating any changes.
*/
- void setStateWithAnimation(LauncherState toState,
- AnimatorSetBuilder builder, AnimationConfig config);
+ void setStateWithAnimation(
+ LauncherState toState, StateAnimationConfig config, PendingAnimation animation);
}
public interface StateListener {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index fc1a074..ead6018 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -60,11 +60,10 @@
import android.widget.Toast;
import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
-import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
-import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dot.FolderDotInfo;
import com.android.launcher3.dragndrop.DragController;
@@ -83,6 +82,7 @@
import com.android.launcher3.pageindicators.WorkspacePageIndicator;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
+import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.WorkspaceTouchListener;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -1383,10 +1383,10 @@
* Sets the current workspace {@link LauncherState}, then animates the UI
*/
@Override
- public void setStateWithAnimation(LauncherState toState,
- AnimatorSetBuilder builder, AnimationConfig config) {
+ public void setStateWithAnimation(
+ LauncherState toState, StateAnimationConfig config, PendingAnimation animation) {
StateTransitionListener listener = new StateTransitionListener(toState);
- mStateTransitionAnimation.setStateWithAnimation(toState, builder, config);
+ mStateTransitionAnimation.setStateWithAnimation(toState, config, animation);
// Invalidate the pages now, so that we have the visible pages before the
// animation is started
@@ -1399,7 +1399,7 @@
stepAnimator.addUpdateListener(listener);
stepAnimator.setDuration(config.duration);
stepAnimator.addListener(listener);
- builder.play(stepAnimator);
+ animation.add(stepAnimator);
}
public WorkspaceStateTransitionAnimation getStateTransitionAnimation() {
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 6653426..c521c34 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -22,27 +22,27 @@
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
-import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_SCALE;
-import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_TRANSLATE;
-import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
-import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
-import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.ZOOM_OUT;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
import static com.android.launcher3.graphics.WorkspaceAndHotseatScrim.SCRIM_PROGRESS;
import static com.android.launcher3.graphics.WorkspaceAndHotseatScrim.SYSUI_PROGRESS;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
import android.view.View;
import android.view.animation.Interpolator;
import com.android.launcher3.LauncherState.PageAlphaProvider;
import com.android.launcher3.LauncherState.ScaleAndTranslation;
-import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.allapps.AllAppsContainerView;
-import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.graphics.WorkspaceAndHotseatScrim;
+import com.android.launcher3.states.StateAnimationConfig;
/**
* Manages the animations between each of the workspace states.
@@ -60,13 +60,15 @@
}
public void setState(LauncherState toState) {
- setWorkspaceProperty(toState, NO_ANIM_PROPERTY_SETTER, new AnimatorSetBuilder(),
- new AnimationConfig());
+ setWorkspaceProperty(toState, NO_ANIM_PROPERTY_SETTER, new StateAnimationConfig());
}
- public void setStateWithAnimation(LauncherState toState, AnimatorSetBuilder builder,
- AnimationConfig config) {
- setWorkspaceProperty(toState, config.getPropertySetter(builder), builder, config);
+ /**
+ * @see com.android.launcher3.LauncherStateManager.StateHandler#setStateWithAnimation
+ */
+ public void setStateWithAnimation(
+ LauncherState toState, StateAnimationConfig config, PendingAnimation animation) {
+ setWorkspaceProperty(toState, animation, config);
}
public float getFinalScale() {
@@ -77,7 +79,7 @@
* Starts a transition animation for the workspace.
*/
private void setWorkspaceProperty(LauncherState state, PropertySetter propertySetter,
- AnimatorSetBuilder builder, AnimationConfig config) {
+ StateAnimationConfig config) {
ScaleAndTranslation scaleAndTranslation = state.getWorkspaceScaleAndTranslation(mLauncher);
ScaleAndTranslation hotseatScaleAndTranslation = state.getHotseatScaleAndTranslation(
mLauncher);
@@ -87,11 +89,11 @@
final int childCount = mWorkspace.getChildCount();
for (int i = 0; i < childCount; i++) {
applyChildState(state, (CellLayout) mWorkspace.getChildAt(i), i, pageAlphaProvider,
- propertySetter, builder, config);
+ propertySetter, config);
}
int elements = state.getVisibleElements(mLauncher);
- Interpolator fadeInterpolator = builder.getInterpolator(ANIM_WORKSPACE_FADE,
+ Interpolator fadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE,
pageAlphaProvider.interpolator);
boolean playAtomicComponent = config.playAtomicOverviewScaleComponent();
Hotseat hotseat = mWorkspace.getHotseat();
@@ -99,7 +101,7 @@
AllAppsContainerView qsbScaleView = mLauncher.getAppsView();
View qsbView = qsbScaleView.getSearchView();
if (playAtomicComponent) {
- Interpolator scaleInterpolator = builder.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
+ Interpolator scaleInterpolator = config.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator);
if (!hotseat.getRotationMode().isTransposed) {
@@ -107,7 +109,7 @@
setPivotToScaleWithWorkspace(qsbScaleView);
}
float hotseatScale = hotseatScaleAndTranslation.scale;
- Interpolator hotseatScaleInterpolator = builder.getInterpolator(ANIM_HOTSEAT_SCALE,
+ Interpolator hotseatScaleInterpolator = config.getInterpolator(ANIM_HOTSEAT_SCALE,
scaleInterpolator);
propertySetter.setFloat(hotseat, SCALE_PROPERTY, hotseatScale,
hotseatScaleInterpolator);
@@ -127,13 +129,13 @@
Interpolator translationInterpolator = !playAtomicComponent
? LINEAR
- : builder.getInterpolator(ANIM_WORKSPACE_TRANSLATE, ZOOM_OUT);
+ : config.getInterpolator(ANIM_WORKSPACE_TRANSLATE, ZOOM_OUT);
propertySetter.setFloat(mWorkspace, VIEW_TRANSLATE_X,
scaleAndTranslation.translationX, translationInterpolator);
propertySetter.setFloat(mWorkspace, VIEW_TRANSLATE_Y,
scaleAndTranslation.translationY, translationInterpolator);
- Interpolator hotseatTranslationInterpolator = builder.getInterpolator(
+ Interpolator hotseatTranslationInterpolator = config.getInterpolator(
ANIM_HOTSEAT_TRANSLATE, translationInterpolator);
propertySetter.setFloat(hotseat, VIEW_TRANSLATE_Y,
hotseatScaleAndTranslation.translationY, hotseatTranslationInterpolator);
@@ -166,12 +168,12 @@
public void applyChildState(LauncherState state, CellLayout cl, int childIndex) {
applyChildState(state, cl, childIndex, state.getWorkspacePageAlphaProvider(mLauncher),
- NO_ANIM_PROPERTY_SETTER, new AnimatorSetBuilder(), new AnimationConfig());
+ NO_ANIM_PROPERTY_SETTER, new StateAnimationConfig());
}
private void applyChildState(LauncherState state, CellLayout cl, int childIndex,
PageAlphaProvider pageAlphaProvider, PropertySetter propertySetter,
- AnimatorSetBuilder builder, AnimationConfig config) {
+ StateAnimationConfig config) {
float pageAlpha = pageAlphaProvider.getPageAlpha(childIndex);
int drawableAlpha = Math.round(pageAlpha * (state.hasWorkspacePageBackground ? 255 : 0));
@@ -181,7 +183,7 @@
DRAWABLE_ALPHA, drawableAlpha, ZOOM_OUT);
}
if (config.playAtomicOverviewScaleComponent()) {
- Interpolator fadeInterpolator = builder.getInterpolator(ANIM_WORKSPACE_FADE,
+ Interpolator fadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE,
pageAlphaProvider.interpolator);
propertySetter.setFloat(cl.getShortcutsAndWidgets(), VIEW_ALPHA,
pageAlpha, fadeInterpolator);
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 744f4eb..7600f52 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -5,13 +5,13 @@
import static com.android.launcher3.LauncherState.APPS_VIEW_ITEM_MASK;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.VERTICAL_SWIPE_INDICATOR;
-import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE;
-import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_HEADER_FADE;
-import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
-import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_HEADER_FADE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
import static com.android.launcher3.util.SystemUiController.UI_STATE_ALL_APPS;
import android.animation.Animator;
@@ -24,12 +24,12 @@
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimationSuccessListener;
-import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ScrimView;
@@ -112,7 +112,7 @@
* @param progress value between 0 and 1, 0 shows all apps and 1 shows workspace
*
* @see #setState(LauncherState)
- * @see #setStateWithAnimation(LauncherState, AnimatorSetBuilder, AnimationConfig)
+ * @see #setStateWithAnimation(LauncherState, StateAnimationConfig, PendingAnimation)
*/
public void setProgress(float progress) {
mProgress = progress;
@@ -143,7 +143,7 @@
@Override
public void setState(LauncherState state) {
setProgress(state.getVerticalProgress(mLauncher));
- setAlphas(state, null, new AnimatorSetBuilder());
+ setAlphas(state, new StateAnimationConfig(), NO_ANIM_PROPERTY_SETTER);
onProgressAnimationEnd();
}
@@ -153,7 +153,7 @@
*/
@Override
public void setStateWithAnimation(LauncherState toState,
- AnimatorSetBuilder builder, AnimationConfig config) {
+ StateAnimationConfig config, PendingAnimation builder) {
float targetProgress = toState.getVerticalProgress(mLauncher);
if (Float.compare(mProgress, targetProgress) == 0) {
setAlphas(toState, config, builder);
@@ -168,14 +168,14 @@
}
Interpolator interpolator = config.userControlled ? LINEAR : toState == OVERVIEW
- ? builder.getInterpolator(ANIM_OVERVIEW_SCALE, FAST_OUT_SLOW_IN)
+ ? config.getInterpolator(ANIM_OVERVIEW_SCALE, FAST_OUT_SLOW_IN)
: FAST_OUT_SLOW_IN;
+
Animator anim = createSpringAnimation(mProgress, targetProgress);
anim.setDuration(config.duration);
- anim.setInterpolator(builder.getInterpolator(ANIM_VERTICAL_PROGRESS, interpolator));
+ anim.setInterpolator(config.getInterpolator(ANIM_VERTICAL_PROGRESS, interpolator));
anim.addListener(getProgressAnimatorListener());
-
- builder.play(anim);
+ builder.add(anim);
setAlphas(toState, config, builder);
}
@@ -184,21 +184,18 @@
return ObjectAnimator.ofFloat(this, ALL_APPS_PROGRESS, progressValues);
}
- private void setAlphas(LauncherState toState, AnimationConfig config,
- AnimatorSetBuilder builder) {
- setAlphas(toState.getVisibleElements(mLauncher), config, builder);
- }
-
- public void setAlphas(int visibleElements, AnimationConfig config, AnimatorSetBuilder builder) {
- PropertySetter setter = config == null ? NO_ANIM_PROPERTY_SETTER
- : config.getPropertySetter(builder);
+ /**
+ * Updates the property for the provided state
+ */
+ public void setAlphas(LauncherState state, StateAnimationConfig config, PropertySetter setter) {
+ int visibleElements = state.getVisibleElements(mLauncher);
boolean hasHeaderExtra = (visibleElements & ALL_APPS_HEADER_EXTRA) != 0;
boolean hasAllAppsContent = (visibleElements & ALL_APPS_CONTENT) != 0;
boolean hasAnyVisibleItem = (visibleElements & APPS_VIEW_ITEM_MASK) != 0;
- Interpolator allAppsFade = builder.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR);
- Interpolator headerFade = builder.getInterpolator(ANIM_ALL_APPS_HEADER_FADE, allAppsFade);
+ Interpolator allAppsFade = config.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR);
+ Interpolator headerFade = config.getInterpolator(ANIM_ALL_APPS_HEADER_FADE, allAppsFade);
setter.setViewAlpha(mAppsView.getContentView(), hasAllAppsContent ? 1 : 0, allAppsFade);
setter.setViewAlpha(mAppsView.getScrollBar(), hasAllAppsContent ? 1 : 0, allAppsFade);
mAppsView.getFloatingHeaderView().setContentVisibility(hasHeaderExtra, hasAllAppsContent,
diff --git a/src/com/android/launcher3/anim/AnimatorPlaybackController.java b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
index 1fc21fd..958c863 100644
--- a/src/com/android/launcher3/anim/AnimatorPlaybackController.java
+++ b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
@@ -64,13 +64,6 @@
return new AnimatorPlaybackController(anim, duration, childAnims);
}
- public static AnimatorPlaybackController wrap(PendingAnimation anim, long duration) {
- /**
- * TODO: use {@link AnimatorSet#setCurrentPlayTime(long)} once b/68382377 is fixed.
- */
- return new AnimatorPlaybackController(anim.anim, duration, anim.animHolders);
- }
-
private static final FloatProperty<ValueAnimator> CURRENT_PLAY_TIME =
new FloatProperty<ValueAnimator>("current-play-time") {
@Override
@@ -96,8 +89,8 @@
protected boolean mTargetCancelled = false;
protected Runnable mOnCancelRunnable;
- private AnimatorPlaybackController(
- AnimatorSet anim, long duration, ArrayList<Holder> childAnims) {
+ /** package private */
+ AnimatorPlaybackController(AnimatorSet anim, long duration, ArrayList<Holder> childAnims) {
mAnim = anim;
mDuration = duration;
diff --git a/src/com/android/launcher3/anim/AnimatorSetBuilder.java b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
deleted file mode 100644
index d814b19..0000000
--- a/src/com/android/launcher3/anim/AnimatorSetBuilder.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.anim;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.util.SparseArray;
-import android.view.animation.Interpolator;
-
-import java.util.ArrayList;
-
-/**
- * Utility class for building animator set
- */
-public class AnimatorSetBuilder {
-
- public static final int ANIM_VERTICAL_PROGRESS = 0;
- public static final int ANIM_WORKSPACE_SCALE = 1;
- public static final int ANIM_WORKSPACE_TRANSLATE = 2;
- public static final int ANIM_WORKSPACE_FADE = 3;
- public static final int ANIM_HOTSEAT_SCALE = 4;
- public static final int ANIM_HOTSEAT_TRANSLATE = 5;
- public static final int ANIM_OVERVIEW_SCALE = 6;
- public static final int ANIM_OVERVIEW_TRANSLATE_X = 7;
- public static final int ANIM_OVERVIEW_TRANSLATE_Y = 8;
- public static final int ANIM_OVERVIEW_FADE = 9;
- public static final int ANIM_ALL_APPS_FADE = 10;
- public static final int ANIM_OVERVIEW_SCRIM_FADE = 11;
- public static final int ANIM_ALL_APPS_HEADER_FADE = 12; // e.g. predictions
-
- protected final ArrayList<Animator> mAnims = new ArrayList<>();
-
- private final SparseArray<Interpolator> mInterpolators = new SparseArray<>();
-
- public void play(Animator anim) {
- mAnims.add(anim);
- }
-
- public AnimatorSet build() {
- AnimatorSet anim = new AnimatorSet();
- anim.playTogether(mAnims);
- return anim;
- }
-
- public Interpolator getInterpolator(int animId, Interpolator fallback) {
- return mInterpolators.get(animId, fallback);
- }
-
- public void setInterpolator(int animId, Interpolator interpolator) {
- mInterpolators.put(animId, interpolator);
- }
-}
diff --git a/src/com/android/launcher3/anim/PendingAnimation.java b/src/com/android/launcher3/anim/PendingAnimation.java
index 562d160..9a25c47 100644
--- a/src/com/android/launcher3/anim/PendingAnimation.java
+++ b/src/com/android/launcher3/anim/PendingAnimation.java
@@ -19,9 +19,12 @@
import android.animation.Animator;
import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
-import android.annotation.TargetApi;
-import android.os.Build;
+import android.animation.ValueAnimator;
+import android.util.FloatProperty;
+import android.util.IntProperty;
+import android.view.View;
import com.android.launcher3.anim.AnimatorPlaybackController.Holder;
@@ -37,14 +40,24 @@
*
* TODO: Find a better name
*/
-@TargetApi(Build.VERSION_CODES.O)
-public class PendingAnimation {
+public class PendingAnimation implements PropertySetter {
private final ArrayList<Consumer<EndState>> mEndListeners = new ArrayList<>();
- /** package private **/
- final AnimatorSet anim = new AnimatorSet();
- final ArrayList<Holder> animHolders = new ArrayList<>();
+ private final ArrayList<Holder> mAnimHolders = new ArrayList<>();
+ private final AnimatorSet mAnim;
+ private final long mDuration;
+
+ private ValueAnimator mProgressAnimator;
+
+ public PendingAnimation(long duration) {
+ this(duration, new AnimatorSet());
+ }
+
+ public PendingAnimation(long duration, AnimatorSet targetSet) {
+ mDuration = duration;
+ mAnim = targetSet;
+ }
/**
* Utility method to sent an interpolator on an animation and add it to the list
@@ -63,8 +76,8 @@
}
public void add(Animator a, SpringProperty springProperty) {
- anim.play(a);
- addAnimationHoldersRecur(a, springProperty, animHolders);
+ mAnim.play(a);
+ addAnimationHoldersRecur(a, springProperty, mAnimHolders);
}
public void finish(boolean isSuccess, int logAction) {
@@ -74,6 +87,67 @@
mEndListeners.clear();
}
+ @Override
+ public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
+ if (view == null || view.getAlpha() == alpha) {
+ return;
+ }
+ ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha);
+ anim.addListener(new AlphaUpdateListener(view));
+ anim.setDuration(mDuration).setInterpolator(interpolator);
+ add(anim);
+ }
+
+ @Override
+ public <T> void setFloat(T target, FloatProperty<T> property, float value,
+ TimeInterpolator interpolator) {
+ if (property.get(target) == value) {
+ return;
+ }
+ Animator anim = ObjectAnimator.ofFloat(target, property, value);
+ anim.setDuration(mDuration).setInterpolator(interpolator);
+ add(anim);
+ }
+
+ @Override
+ public <T> void setInt(T target, IntProperty<T> property, int value,
+ TimeInterpolator interpolator) {
+ if (property.get(target) == value) {
+ return;
+ }
+ Animator anim = ObjectAnimator.ofInt(target, property, value);
+ anim.setDuration(mDuration).setInterpolator(interpolator);
+ add(anim);
+ }
+
+ /**
+ * Adds a callback to be run on every frame of the animation
+ */
+ public void addOnFrameCallback(Runnable runnable) {
+ if (mProgressAnimator == null) {
+ mProgressAnimator = ValueAnimator.ofFloat(0, 1).setDuration(mDuration);
+ add(mProgressAnimator);
+ }
+
+ mProgressAnimator.addUpdateListener(anim -> runnable.run());
+ }
+
+ public AnimatorSet getAnim() {
+ return mAnim;
+ }
+
+ /**
+ * Creates a controller for this animation
+ */
+ public AnimatorPlaybackController createPlaybackController() {
+ return new AnimatorPlaybackController(mAnim, mDuration, mAnimHolders);
+ }
+
+ /**
+ * Add a listener of receiving the end state.
+ * Note that the listeners are called as a result of calling {@link #finish(boolean, int)}
+ * and not automatically
+ */
public void addEndListener(Consumer<EndState> listener) {
mEndListeners.add(listener);
}
diff --git a/src/com/android/launcher3/anim/PropertySetter.java b/src/com/android/launcher3/anim/PropertySetter.java
index 0b2eb48..2ce620b 100644
--- a/src/com/android/launcher3/anim/PropertySetter.java
+++ b/src/com/android/launcher3/anim/PropertySetter.java
@@ -16,8 +16,6 @@
package com.android.launcher3.anim;
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.util.FloatProperty;
import android.util.IntProperty;
@@ -26,68 +24,35 @@
/**
* Utility class for setting a property with or without animation
*/
-public class PropertySetter {
+public interface PropertySetter {
- public static final PropertySetter NO_ANIM_PROPERTY_SETTER = new PropertySetter();
+ PropertySetter NO_ANIM_PROPERTY_SETTER = new PropertySetter() { };
- public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
+ /**
+ * Sets the view alpha using the provided interpolator.
+ * Unlike {@link #setFloat}, this also updates the visibility of the view as alpha changes
+ * between zero and non-zero.
+ */
+ default void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
if (view != null) {
view.setAlpha(alpha);
AlphaUpdateListener.updateVisibility(view);
}
}
- public <T> void setFloat(T target, FloatProperty<T> property, float value,
+ /**
+ * Updates the float property of the target using the provided interpolator
+ */
+ default <T> void setFloat(T target, FloatProperty<T> property, float value,
TimeInterpolator interpolator) {
property.setValue(target, value);
}
- public <T> void setInt(T target, IntProperty<T> property, int value,
+ /**
+ * Updates the int property of the target using the provided interpolator
+ */
+ default <T> void setInt(T target, IntProperty<T> property, int value,
TimeInterpolator interpolator) {
property.setValue(target, value);
}
-
- public static class AnimatedPropertySetter extends PropertySetter {
-
- private final long mDuration;
- private final AnimatorSetBuilder mStateAnimator;
-
- public AnimatedPropertySetter(long duration, AnimatorSetBuilder builder) {
- mDuration = duration;
- mStateAnimator = builder;
- }
-
- @Override
- public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
- if (view == null || view.getAlpha() == alpha) {
- return;
- }
- ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha);
- anim.addListener(new AlphaUpdateListener(view));
- anim.setDuration(mDuration).setInterpolator(interpolator);
- mStateAnimator.play(anim);
- }
-
- @Override
- public <T> void setFloat(T target, FloatProperty<T> property, float value,
- TimeInterpolator interpolator) {
- if (property.get(target) == value) {
- return;
- }
- Animator anim = ObjectAnimator.ofFloat(target, property, value);
- anim.setDuration(mDuration).setInterpolator(interpolator);
- mStateAnimator.play(anim);
- }
-
- @Override
- public <T> void setInt(T target, IntProperty<T> property, int value,
- TimeInterpolator interpolator) {
- if (property.get(target) == value) {
- return;
- }
- Animator anim = ObjectAnimator.ofInt(target, property, value);
- anim.setDuration(mDuration).setInterpolator(interpolator);
- mStateAnimator.play(anim);
- }
- }
}
diff --git a/src/com/android/launcher3/states/StateAnimationConfig.java b/src/com/android/launcher3/states/StateAnimationConfig.java
new file mode 100644
index 0000000..82cde64
--- /dev/null
+++ b/src/com/android/launcher3/states/StateAnimationConfig.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.states;
+
+import android.view.animation.Interpolator;
+
+import androidx.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Utility class for building animator set
+ */
+public class StateAnimationConfig {
+
+ // We separate the state animations into "atomic" and "non-atomic" components. The atomic
+ // components may be run atomically - that is, all at once, instead of user-controlled. However,
+ // atomic components are not restricted to this purpose; they can be user-controlled alongside
+ // non atomic components as well. Note that each gesture model has exactly one atomic component,
+ // PLAY_ATOMIC_OVERVIEW_SCALE *or* PLAY_ATOMIC_OVERVIEW_PEEK.
+ @IntDef(flag = true, value = {
+ PLAY_NON_ATOMIC,
+ PLAY_ATOMIC_OVERVIEW_SCALE,
+ PLAY_ATOMIC_OVERVIEW_PEEK,
+ SKIP_OVERVIEW,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AnimationFlags {}
+ public static final int PLAY_NON_ATOMIC = 1 << 0;
+ public static final int PLAY_ATOMIC_OVERVIEW_SCALE = 1 << 1;
+ public static final int PLAY_ATOMIC_OVERVIEW_PEEK = 1 << 2;
+ public static final int SKIP_OVERVIEW = 1 << 3;
+
+ public long duration;
+ public boolean userControlled;
+ public @AnimationFlags int animFlags = ANIM_ALL_COMPONENTS;
+
+ public static final int ANIM_ALL_COMPONENTS = PLAY_NON_ATOMIC | PLAY_ATOMIC_OVERVIEW_SCALE
+ | PLAY_ATOMIC_OVERVIEW_PEEK;
+
+ // Various types of animation state transition
+ @IntDef(value = {
+ ANIM_VERTICAL_PROGRESS,
+ ANIM_WORKSPACE_SCALE,
+ ANIM_WORKSPACE_TRANSLATE,
+ ANIM_WORKSPACE_FADE,
+ ANIM_HOTSEAT_SCALE,
+ ANIM_HOTSEAT_TRANSLATE,
+ ANIM_OVERVIEW_SCALE,
+ ANIM_OVERVIEW_TRANSLATE_X,
+ ANIM_OVERVIEW_TRANSLATE_Y,
+ ANIM_OVERVIEW_FADE,
+ ANIM_ALL_APPS_FADE,
+ ANIM_OVERVIEW_SCRIM_FADE,
+ ANIM_ALL_APPS_HEADER_FADE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AnimType {}
+ public static final int ANIM_VERTICAL_PROGRESS = 0;
+ public static final int ANIM_WORKSPACE_SCALE = 1;
+ public static final int ANIM_WORKSPACE_TRANSLATE = 2;
+ public static final int ANIM_WORKSPACE_FADE = 3;
+ public static final int ANIM_HOTSEAT_SCALE = 4;
+ public static final int ANIM_HOTSEAT_TRANSLATE = 5;
+ public static final int ANIM_OVERVIEW_SCALE = 6;
+ public static final int ANIM_OVERVIEW_TRANSLATE_X = 7;
+ public static final int ANIM_OVERVIEW_TRANSLATE_Y = 8;
+ public static final int ANIM_OVERVIEW_FADE = 9;
+ public static final int ANIM_ALL_APPS_FADE = 10;
+ public static final int ANIM_OVERVIEW_SCRIM_FADE = 11;
+ public static final int ANIM_ALL_APPS_HEADER_FADE = 12; // e.g. predictions
+
+ private static final int ANIM_TYPES_COUNT = 13;
+
+ private final Interpolator[] mInterpolators = new Interpolator[ANIM_TYPES_COUNT];
+
+ public StateAnimationConfig() { }
+
+ /**
+ * Copies the config to target
+ */
+ public void copyTo(StateAnimationConfig target) {
+ target.duration = duration;
+ target.animFlags = animFlags;
+ target.userControlled = userControlled;
+ for (int i = 0; i < ANIM_TYPES_COUNT; i++) {
+ target.mInterpolators[i] = mInterpolators[i];
+ }
+ }
+
+ /**
+ * Returns the interpolator set for animId or fallback if nothing is set
+ *
+ * @see #setInterpolator(int, Interpolator)
+ */
+ public Interpolator getInterpolator(@AnimType int animId, Interpolator fallback) {
+ return mInterpolators[animId] == null ? fallback : mInterpolators[animId];
+ }
+
+ /**
+ * Sets an interpolator for a given animation type
+ */
+ public void setInterpolator(@AnimType int animId, Interpolator interpolator) {
+ mInterpolators[animId] = interpolator;
+ }
+
+ /**
+ * @return Whether Overview is scaling as part of this animation. If this is the only
+ * component (i.e. NON_ATOMIC_COMPONENT isn't included), then this scaling is happening
+ * atomically, rather than being part of a normal state animation. StateHandlers can use
+ * this to designate part of their animation that should scale with Overview.
+ */
+ public boolean playAtomicOverviewScaleComponent() {
+ return hasAnimationFlag(StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE);
+ }
+
+ /**
+ * @return Whether this animation will play atomically at the same time as a different,
+ * user-controlled state transition. StateHandlers, which contribute to both animations, can
+ * use this to avoid animating the same properties in both animations, since they'd conflict
+ * with one another.
+ */
+ public boolean onlyPlayAtomicComponent() {
+ return getAnimComponents() == StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE
+ || getAnimComponents() == StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
+ }
+
+ /**
+ * Returns true if the config and any of the provided component flags
+ */
+ public boolean hasAnimationFlag(@AnimationFlags int a) {
+ return (animFlags & a) != 0;
+ }
+
+ /**
+ * @return Only the flags that determine which animation components to play.
+ */
+ public @AnimationFlags int getAnimComponents() {
+ return animFlags & StateAnimationConfig.ANIM_ALL_COMPONENTS;
+ }
+}
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index c3664c3..1d14a8f 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -19,11 +19,11 @@
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.LauncherStateManager.ANIM_ALL_COMPONENTS;
-import static com.android.launcher3.LauncherStateManager.PLAY_ATOMIC_OVERVIEW_SCALE;
-import static com.android.launcher3.LauncherStateManager.PLAY_NON_ATOMIC;
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
+import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE;
+import static com.android.launcher3.states.StateAnimationConfig.PLAY_NON_ATOMIC;
import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
import android.animation.Animator;
@@ -37,12 +37,12 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager.AnimationFlags;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
@@ -358,14 +358,18 @@
private AnimatorSet createAtomicAnimForState(LauncherState fromState, LauncherState targetState,
long duration) {
- AnimatorSetBuilder builder = getAnimatorSetBuilderForStates(fromState, targetState);
- return mLauncher.getStateManager().createAtomicAnimation(fromState, targetState, builder,
- PLAY_ATOMIC_OVERVIEW_SCALE, duration);
+ StateAnimationConfig config = getConfigForStates(fromState, targetState);
+ config.animFlags = PLAY_ATOMIC_OVERVIEW_SCALE;
+ config.duration = duration;
+ return mLauncher.getStateManager().createAtomicAnimation(fromState, targetState, config);
}
- protected AnimatorSetBuilder getAnimatorSetBuilderForStates(LauncherState fromState,
- LauncherState toState) {
- return new AnimatorSetBuilder();
+ /**
+ * Returns animation config for state transition between provided states
+ */
+ protected StateAnimationConfig getConfigForStates(
+ LauncherState fromState, LauncherState toState) {
+ return new StateAnimationConfig();
}
@Override
diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java
index 8d5f33d..4a202b6 100644
--- a/src/com/android/launcher3/touch/AllAppsSwipeController.java
+++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java
@@ -23,7 +23,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager.AnimationFlags;
+import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
/**
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index a7078a2..8d1a3b0 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -16,8 +16,8 @@
package com.android.launcher3.widget;
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+
import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.graphics.Rect;
@@ -28,16 +28,15 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.animation.Interpolator;
import android.widget.TextView;
-import androidx.annotation.Nullable;
-
import com.android.launcher3.Insettable;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.ResourceUtils;
-import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.util.PackageUserKey;
@@ -156,7 +155,7 @@
setupNavBarColor();
mOpenCloseAnimator.setValues(
PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
- mOpenCloseAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ mOpenCloseAnimator.setInterpolator(FAST_OUT_SLOW_IN);
mOpenCloseAnimator.start();
}
@@ -191,9 +190,9 @@
mIsOpen ? R.string.widgets_list : R.string.widgets_list_closed));
}
- @Nullable
@Override
- public Animator createHintCloseAnim(float distanceToMove) {
- return ObjectAnimator.ofInt(this, PADDING_BOTTOM, (int) (distanceToMove + mInsets.bottom));
+ public void addHintCloseAnim(
+ float distanceToMove, Interpolator interpolator, PendingAnimation target) {
+ target.setInt(this, PADDING_BOTTOM, (int) (distanceToMove + mInsets.bottom), interpolator);
}
}
diff --git a/src/com/android/launcher3/widget/WidgetsFullSheet.java b/src/com/android/launcher3/widget/WidgetsFullSheet.java
index 2a102d2..b07a4f4 100644
--- a/src/com/android/launcher3/widget/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsFullSheet.java
@@ -15,12 +15,11 @@
*/
package com.android.launcher3.widget;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.testing.TestProtocol.NORMAL_STATE_ORDINAL;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.graphics.Rect;
@@ -30,8 +29,8 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
-import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.Insettable;
@@ -39,6 +38,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
import com.android.launcher3.R;
+import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.TopRoundedCornerView;
@@ -242,13 +242,11 @@
return mAdapter.getItemCount();
}
- @Nullable
@Override
- public Animator createHintCloseAnim(float distanceToMove) {
- AnimatorSet anim = new AnimatorSet();
- anim.play(ObjectAnimator.ofFloat(mRecyclerView, TRANSLATION_Y, -distanceToMove));
- anim.play(ObjectAnimator.ofFloat(mRecyclerView, ALPHA, 0.5f));
- return anim;
+ public void addHintCloseAnim(
+ float distanceToMove, Interpolator interpolator, PendingAnimation target) {
+ target.setFloat(mRecyclerView, VIEW_TRANSLATE_Y, -distanceToMove, interpolator);
+ target.setViewAlpha(mRecyclerView, 0.5f, interpolator);
}
@Override