package com.android.launcher3;
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.TimeInterpolator;
import android.view.View;
-
-import com.android.launcher3.anim.AnimationLayerSet;
+import android.view.ViewPropertyAnimator;
import java.util.ArrayList;
+import java.util.EnumSet;
-/**
- * Extension of {@link ValueAnimator} to provide an interface similar to
- * {@link android.view.ViewPropertyAnimator}.
- */
-public class LauncherViewPropertyAnimator extends ValueAnimator {
+public class LauncherViewPropertyAnimator extends Animator implements AnimatorListener {
+
+ enum Properties {
+ TRANSLATION_X,
+ TRANSLATION_Y,
+ SCALE_X,
+ SCALE_Y,
+ ROTATION_Y,
+ ALPHA,
+ START_DELAY,
+ DURATION,
+ INTERPOLATOR,
+ WITH_LAYER
+ }
+ EnumSet<Properties> mPropertiesToSet = EnumSet.noneOf(Properties.class);
+ ViewPropertyAnimator mViewPropertyAnimator;
+ View mTarget;
+
+ float mTranslationX;
+ float mTranslationY;
+ float mScaleX;
+ float mScaleY;
+ float mRotationY;
+ float mAlpha;
+ long mStartDelay;
+ long mDuration;
+ TimeInterpolator mInterpolator;
+ ArrayList<Animator.AnimatorListener> mListeners = new ArrayList<>();
+ boolean mRunning = false;
+ FirstFrameAnimatorHelper mFirstFrameHelper;
+
+ public LauncherViewPropertyAnimator(View target) {
+ mTarget = target;
+ }
+
+ @Override
+ public void addListener(Animator.AnimatorListener listener) {
+ mListeners.add(listener);
+ }
+
+ @Override
+ public void cancel() {
+ if (mViewPropertyAnimator != null) {
+ mViewPropertyAnimator.cancel();
+ }
+ }
+
+ @Override
+ public Animator clone() {
+ throw new RuntimeException("Not implemented");
+ }
+
+ @Override
+ public void end() {
+ throw new RuntimeException("Not implemented");
+ }
+
+ @Override
+ public long getDuration() {
+ return mDuration;
+ }
+
+ @Override
+ public ArrayList<Animator.AnimatorListener> getListeners() {
+ return mListeners;
+ }
+
+ @Override
+ public long getStartDelay() {
+ return mStartDelay;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ for (int i = 0; i < mListeners.size(); i++) {
+ Animator.AnimatorListener listener = mListeners.get(i);
+ listener.onAnimationCancel(this);
+ }
+ mRunning = false;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ for (int i = 0; i < mListeners.size(); i++) {
+ Animator.AnimatorListener listener = mListeners.get(i);
+ listener.onAnimationEnd(this);
+ }
+ mRunning = false;
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ for (int i = 0; i < mListeners.size(); i++) {
+ Animator.AnimatorListener listener = mListeners.get(i);
+ listener.onAnimationRepeat(this);
+ }
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ // This is the first time we get a handle to the internal ValueAnimator
+ // used by the ViewPropertyAnimator.
+ mFirstFrameHelper.onAnimationStart(animation);
+
+ for (int i = 0; i < mListeners.size(); i++) {
+ Animator.AnimatorListener listener = mListeners.get(i);
+ listener.onAnimationStart(this);
+ }
+ mRunning = true;
+ }
+
+ @Override
+ public boolean isRunning() {
+ return mRunning;
+ }
+
+ @Override
+ public boolean isStarted() {
+ return mViewPropertyAnimator != null;
+ }
+
+ @Override
+ public void removeAllListeners() {
+ mListeners.clear();
+ }
+
+ @Override
+ public void removeListener(Animator.AnimatorListener listener) {
+ mListeners.remove(listener);
+ }
+
+ @Override
+ public Animator setDuration(long duration) {
+ mPropertiesToSet.add(Properties.DURATION);
+ mDuration = duration;
+ return this;
+ }
+
+ @Override
+ public void setInterpolator(TimeInterpolator value) {
+ mPropertiesToSet.add(Properties.INTERPOLATOR);
+ mInterpolator = value;
+ }
+
+ @Override
+ public void setStartDelay(long startDelay) {
+ mPropertiesToSet.add(Properties.START_DELAY);
+ mStartDelay = startDelay;
+ }
+
+ @Override
+ public void setTarget(Object target) {
+ throw new RuntimeException("Not implemented");
+ }
- private final View mTarget;
- private final ArrayList<PropertyValuesHolder> mProperties;
+ @Override
+ public void setupEndValues() {
- private boolean mPrepared = false;
+ }
- public LauncherViewPropertyAnimator(View view) {
- mTarget = view;
- mProperties = new ArrayList<>();
- setTarget(mTarget);
- addListener(new TransientStateUpdater(mTarget));
+ @Override
+ public void setupStartValues() {
}
@Override
public void start() {
- if (!mPrepared) {
- mPrepared = true;
- setValues(mProperties.toArray(new PropertyValuesHolder[mProperties.size()]));
+ mViewPropertyAnimator = mTarget.animate();
+
+ // FirstFrameAnimatorHelper hooks itself up to the updates on the animator,
+ // and then adjusts the play time to keep the first two frames jank-free
+ mFirstFrameHelper = new FirstFrameAnimatorHelper(mViewPropertyAnimator, mTarget);
+
+ if (mPropertiesToSet.contains(Properties.TRANSLATION_X)) {
+ mViewPropertyAnimator.translationX(mTranslationX);
+ }
+ if (mPropertiesToSet.contains(Properties.TRANSLATION_Y)) {
+ mViewPropertyAnimator.translationY(mTranslationY);
+ }
+ if (mPropertiesToSet.contains(Properties.SCALE_X)) {
+ mViewPropertyAnimator.scaleX(mScaleX);
+ }
+ if (mPropertiesToSet.contains(Properties.ROTATION_Y)) {
+ mViewPropertyAnimator.rotationY(mRotationY);
+ }
+ if (mPropertiesToSet.contains(Properties.SCALE_Y)) {
+ mViewPropertyAnimator.scaleY(mScaleY);
+ }
+ if (mPropertiesToSet.contains(Properties.ALPHA)) {
+ mViewPropertyAnimator.alpha(mAlpha);
+ }
+ if (mPropertiesToSet.contains(Properties.START_DELAY)) {
+ mViewPropertyAnimator.setStartDelay(mStartDelay);
+ }
+ if (mPropertiesToSet.contains(Properties.DURATION)) {
+ mViewPropertyAnimator.setDuration(mDuration);
+ }
+ if (mPropertiesToSet.contains(Properties.INTERPOLATOR)) {
+ mViewPropertyAnimator.setInterpolator(mInterpolator);
}
+ if (mPropertiesToSet.contains(Properties.WITH_LAYER)) {
+ mViewPropertyAnimator.withLayer();
+ }
+ mViewPropertyAnimator.setListener(this);
+ mViewPropertyAnimator.start();
LauncherAnimUtils.cancelOnDestroyActivity(this);
- super.start();
}
public LauncherViewPropertyAnimator translationX(float value) {
- mProperties.add(PropertyValuesHolder.ofFloat(View.TRANSLATION_X, value));
+ mPropertiesToSet.add(Properties.TRANSLATION_X);
+ mTranslationX = value;
return this;
}
public LauncherViewPropertyAnimator translationY(float value) {
- mProperties.add(PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, value));
+ mPropertiesToSet.add(Properties.TRANSLATION_Y);
+ mTranslationY = value;
return this;
}
public LauncherViewPropertyAnimator scaleX(float value) {
- mProperties.add(PropertyValuesHolder.ofFloat(View.SCALE_X, value));
+ mPropertiesToSet.add(Properties.SCALE_X);
+ mScaleX = value;
return this;
}
public LauncherViewPropertyAnimator scaleY(float value) {
- mProperties.add(PropertyValuesHolder.ofFloat(View.SCALE_Y, value));
+ mPropertiesToSet.add(Properties.SCALE_Y);
+ mScaleY = value;
return this;
}
- public LauncherViewPropertyAnimator alpha(float value) {
- mProperties.add(PropertyValuesHolder.ofFloat(View.ALPHA, value));
+ public LauncherViewPropertyAnimator rotationY(float value) {
+ mPropertiesToSet.add(Properties.ROTATION_Y);
+ mRotationY = value;
return this;
}
- public LauncherViewPropertyAnimator withLayer() {
- AnimationLayerSet listener = new AnimationLayerSet();
- listener.addView(mTarget);
- addListener(listener);
+ public LauncherViewPropertyAnimator alpha(float value) {
+ mPropertiesToSet.add(Properties.ALPHA);
+ mAlpha = value;
return this;
}
- private static class TransientStateUpdater extends AnimatorListenerAdapter {
- private final View mView;
-
- TransientStateUpdater(View v) {
- mView = v;
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- mView.setHasTransientState(true);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- mView.setHasTransientState(false);
- }
+ public LauncherViewPropertyAnimator withLayer() {
+ mPropertiesToSet.add(Properties.WITH_LAYER);
+ return this;
}
}
import android.animation.AnimatorListenerAdapter;
import android.view.View;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
+import java.util.HashSet;
/**
* Helper class to automatically build view hardware layers for the duration of an animation.
*/
public class AnimationLayerSet extends AnimatorListenerAdapter {
- private final HashMap<View, Integer> mViewsToLayerTypeMap = new HashMap<>();
+ private final HashSet<View> mViews = new HashSet<>();
public void addView(View v) {
- mViewsToLayerTypeMap.put(v, v.getLayerType());
+ mViews.add(v);
}
@Override
public void onAnimationStart(Animator animation) {
// Enable all necessary layers
- Iterator<Map.Entry<View, Integer>> itr = mViewsToLayerTypeMap.entrySet().iterator();
- while (itr.hasNext()) {
- Map.Entry<View, Integer> entry = itr.next();
- View v = entry.getKey();
- entry.setValue(v.getLayerType());
+ for (View v : mViews) {
v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
if (v.isAttachedToWindow() && v.getVisibility() == View.VISIBLE) {
v.buildLayer();
@Override
public void onAnimationEnd(Animator animation) {
- Iterator<Map.Entry<View, Integer>> itr = mViewsToLayerTypeMap.entrySet().iterator();
- while (itr.hasNext()) {
- Map.Entry<View, Integer> entry = itr.next();
- entry.getKey().setLayerType(entry.getValue(), null);
+ for (View v : mViews) {
+ v.setLayerType(View.LAYER_TYPE_NONE, null);
}
}
}