Made it easier to use updatable Animators
The existing system is extended such that AnimationProperties
can be easier animated and running animations updated.
As a first sample this animates the scale of the
icons in the shelf.
Change-Id: Ic88e8094d53f37ab13f5e9e00796b63d229a5114
Test: runtest systemui
Bug: 32437839
(cherry picked from commit f082fe2319884737225952547bbaf5fc02359fc6)
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 8c80c71..2a895f9 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -20,12 +20,16 @@
<item type="id" name="translation_y_animator_tag"/>
<item type="id" name="translation_z_animator_tag"/>
<item type="id" name="alpha_animator_tag"/>
+ <item type="id" name="scale_x_animator_tag"/>
+ <item type="id" name="scale_y_animator_tag"/>
<item type="id" name="top_inset_animator_tag"/>
<item type="id" name="height_animator_tag"/>
<item type="id" name="shadow_alpha_animator_tag"/>
<item type="id" name="translation_x_animator_end_value_tag"/>
<item type="id" name="translation_y_animator_end_value_tag"/>
<item type="id" name="translation_z_animator_end_value_tag"/>
+ <item type="id" name="scale_x_animator_end_value_tag"/>
+ <item type="id" name="scale_y_animator_end_value_tag"/>
<item type="id" name="alpha_animator_end_value_tag"/>
<item type="id" name="top_inset_animator_end_value_tag"/>
<item type="id" name="height_animator_end_value_tag"/>
@@ -33,6 +37,8 @@
<item type="id" name="translation_x_animator_start_value_tag"/>
<item type="id" name="translation_y_animator_start_value_tag"/>
<item type="id" name="translation_z_animator_start_value_tag"/>
+ <item type="id" name="scale_x_animator_start_value_tag"/>
+ <item type="id" name="scale_y_animator_start_value_tag"/>
<item type="id" name="alpha_animator_start_value_tag"/>
<item type="id" name="top_inset_animator_start_value_tag"/>
<item type="id" name="height_animator_start_value_tag"/>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
new file mode 100644
index 0000000..80ba943
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2016 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.systemui.statusbar.notification;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.util.Property;
+import android.view.View;
+import android.view.animation.Interpolator;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.statusbar.stack.AnimationFilter;
+import com.android.systemui.statusbar.stack.AnimationProperties;
+import com.android.systemui.statusbar.stack.ViewState;
+
+/**
+ * An animator to animate properties
+ */
+public class PropertyAnimator {
+
+ public static <T extends View> void startAnimation(final T view,
+ AnimatableProperty animatableProperty, float newEndValue,
+ AnimationProperties properties) {
+ Property<T, Float> property = animatableProperty.getProperty();
+ int animationStartTag = animatableProperty.getAnimationStartTag();
+ int animationEndTag = animatableProperty.getAnimationEndTag();
+ Float previousStartValue = ViewState.getChildTag(view, animationStartTag);
+ Float previousEndValue = ViewState.getChildTag(view, animationEndTag);
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ int animatorTag = animatableProperty.getAnimatorTag();
+ ValueAnimator previousAnimator = ViewState.getChildTag(view, animatorTag);
+ AnimationFilter filter = properties.getAnimationFilter();
+ if (!filter.shouldAnimateProperty(property)) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ float relativeDiff = newEndValue - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ view.setTag(animationStartTag, newStartValue);
+ view.setTag(animationEndTag, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ property.set(view, newEndValue);
+ return;
+ }
+ }
+
+ Float currentValue = property.get(view);
+ ValueAnimator animator = ValueAnimator.ofFloat(currentValue, newEndValue);
+ animator.addUpdateListener(
+ animation -> property.set(view, (Float) animation.getAnimatedValue()));
+ Interpolator customInterpolator = properties.getCustomInterpolator(view, property);
+ Interpolator interpolator = customInterpolator != null ? customInterpolator
+ : Interpolators.FAST_OUT_SLOW_IN;
+ animator.setInterpolator(interpolator);
+ long newDuration = ViewState.cancelAnimatorAndGetNewDuration(properties.duration,
+ previousAnimator);
+ animator.setDuration(newDuration);
+ if (properties.delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
+ animator.setStartDelay(properties.delay);
+ }
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ if (listener != null) {
+ animator.addListener(listener);
+ }
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ view.setTag(animatorTag, null);
+ view.setTag(animationStartTag, null);
+ view.setTag(animationEndTag, null);
+ }
+ });
+ ViewState.startAnimator(animator, listener);
+ view.setTag(animatorTag, animator);
+ view.setTag(animationStartTag, currentValue);
+ view.setTag(animationEndTag, newEndValue);
+ }
+
+ public interface AnimatableProperty {
+ int getAnimationStartTag();
+ int getAnimationEndTag();
+ int getAnimatorTag();
+ Property getProperty();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 4b0f454..9fb5980 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -62,8 +62,8 @@
}.setDuration(200);
private static final AnimationProperties ICON_ANIMATION_PROPERTIES = new AnimationProperties() {
- private AnimationFilter mAnimationFilter = new AnimationFilter().animateY().animateAlpha();
- // TODO: add scale
+ private AnimationFilter mAnimationFilter = new AnimationFilter().animateY().animateAlpha()
+ .animateScale();
@Override
public AnimationFilter getAnimationFilter() {
@@ -75,13 +75,12 @@
private static final AnimationProperties mTempProperties = new AnimationProperties() {
private AnimationFilter mAnimationFilter = new AnimationFilter();
- // TODO: add scale
@Override
public AnimationFilter getAnimationFilter() {
return mAnimationFilter;
}
- }.setDuration(CANNED_ANIMATION_DURATION);
+ };
private static final AnimationProperties ADD_ICON_PROPERTIES = new AnimationProperties() {
private AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
index 38bb40e..34fa658 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
@@ -16,7 +16,12 @@
package com.android.systemui.statusbar.stack;
+import android.support.v4.util.ArraySet;
+import android.util.Property;
+import android.view.View;
+
import java.util.ArrayList;
+import java.util.HashSet;
/**
* Filters the animations for only a certain type of properties.
@@ -37,12 +42,19 @@
boolean hasDarkEvent;
boolean hasHeadsUpDisappearClickEvent;
int darkAnimationOriginIndex;
+ private ArraySet<Property> mAnimatedProperties = new ArraySet<>();
public AnimationFilter animateAlpha() {
animateAlpha = true;
return this;
}
+ public AnimationFilter animateScale() {
+ animate(View.SCALE_X);
+ animate(View.SCALE_Y);
+ return this;
+ }
+
public AnimationFilter animateX() {
animateX = true;
return this;
@@ -132,6 +144,7 @@
animateHideSensitive |= filter.animateHideSensitive;
animateShadowAlpha |= filter.animateShadowAlpha;
hasDelays |= filter.hasDelays;
+ mAnimatedProperties.addAll(filter.mAnimatedProperties);
}
public void reset() {
@@ -151,5 +164,16 @@
hasHeadsUpDisappearClickEvent = false;
darkAnimationOriginIndex =
NotificationStackScrollLayout.AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE;
+ mAnimatedProperties.clear();
+ }
+
+ public AnimationFilter animate(Property property) {
+ mAnimatedProperties.add(property);
+ return this;
+ }
+
+ public boolean shouldAnimateProperty(Property property) {
+ // TODO: migrate all existing animators to properties
+ return mAnimatedProperties.contains(property);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
index b747592..e0a6159 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
@@ -21,12 +21,14 @@
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
+import android.util.Property;
import android.view.View;
import android.view.animation.Interpolator;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.policy.HeadsUpManager;
/**
@@ -60,6 +62,54 @@
private static final int TAG_START_TRANSLATION_Z = R.id.translation_z_animator_start_value_tag;
private static final int TAG_START_ALPHA = R.id.alpha_animator_start_value_tag;
+ private static final PropertyAnimator.AnimatableProperty SCALE_X_PROPERTY
+ = new PropertyAnimator.AnimatableProperty() {
+
+ @Override
+ public int getAnimationStartTag() {
+ return R.id.scale_x_animator_start_value_tag;
+ }
+
+ @Override
+ public int getAnimationEndTag() {
+ return R.id.scale_x_animator_end_value_tag;
+ }
+
+ @Override
+ public int getAnimatorTag() {
+ return R.id.scale_x_animator_tag;
+ }
+
+ @Override
+ public Property getProperty() {
+ return View.SCALE_X;
+ }
+ };
+
+ private static final PropertyAnimator.AnimatableProperty SCALE_Y_PROPERTY
+ = new PropertyAnimator.AnimatableProperty() {
+
+ @Override
+ public int getAnimationStartTag() {
+ return R.id.scale_y_animator_start_value_tag;
+ }
+
+ @Override
+ public int getAnimationEndTag() {
+ return R.id.scale_y_animator_end_value_tag;
+ }
+
+ @Override
+ public int getAnimatorTag() {
+ return R.id.scale_y_animator_tag;
+ }
+
+ @Override
+ public Property getProperty() {
+ return View.SCALE_Y;
+ }
+ };
+
public float alpha;
public float xTranslation;
public float yTranslation;
@@ -125,13 +175,19 @@
}
// apply scaleX
- if (view.getScaleX() != this.scaleX) {
- view.setScaleX(this.scaleX);
+ boolean animatingScaleX = isAnimating(view, SCALE_X_PROPERTY);
+ if (animatingScaleX) {
+ updateAnimation(view, SCALE_X_PROPERTY, scaleX);
+ } else if (view.getScaleX() != scaleX) {
+ view.setScaleX(scaleX);
}
// apply scaleY
- if (view.getScaleY() != this.scaleY) {
- view.setScaleY(this.scaleY);
+ boolean animatingScaleY = isAnimating(view, SCALE_Y_PROPERTY);
+ if (animatingScaleY) {
+ updateAnimation(view, SCALE_Y_PROPERTY, scaleY);
+ } else if (view.getScaleY() != scaleY) {
+ view.setScaleY(scaleY);
}
boolean becomesInvisible = this.alpha == 0.0f || (this.hidden && !isAnimating(view));
@@ -179,13 +235,23 @@
if (isAnimating(view, TAG_ANIMATOR_ALPHA)) {
return true;
}
+ if (isAnimating(view, SCALE_X_PROPERTY)) {
+ return true;
+ }
+ if (isAnimating(view, SCALE_Y_PROPERTY)) {
+ return true;
+ }
return false;
}
- private boolean isAnimating(View view, int tag) {
+ private static boolean isAnimating(View view, int tag) {
return getChildTag(view, tag) != null;
}
+ public static boolean isAnimating(View view, PropertyAnimator.AnimatableProperty property) {
+ return getChildTag(view, property.getAnimatorTag()) != null;
+ }
+
/**
* Start an animation to this viewstate
* @param child the view to animate
@@ -226,6 +292,20 @@
abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Z);
}
+ // start scaleX animation
+ if (child.getScaleX() != scaleX) {
+ PropertyAnimator.startAnimation(child, SCALE_X_PROPERTY, scaleX, animationProperties);
+ } else {
+ abortAnimation(child, SCALE_X_PROPERTY.getAnimatorTag());
+ }
+
+ // start scaleX animation
+ if (child.getScaleY() != scaleY) {
+ PropertyAnimator.startAnimation(child, SCALE_Y_PROPERTY, scaleY, animationProperties);
+ } else {
+ abortAnimation(child, SCALE_Y_PROPERTY.getAnimatorTag());
+ }
+
// start alpha animation
if (alphaChanging) {
startAlphaAnimation(child, animationProperties);
@@ -320,6 +400,11 @@
startZTranslationAnimation(view, NO_NEW_ANIMATIONS);
}
+ private void updateAnimation(View view, PropertyAnimator.AnimatableProperty property,
+ float endValue) {
+ PropertyAnimator.startAnimation(view, property, endValue, NO_NEW_ANIMATIONS);
+ }
+
private void startZTranslationAnimation(final View child, AnimationProperties properties) {
Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z);
Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z);
@@ -514,7 +599,7 @@
}
}
- protected void startAnimator(Animator animator, AnimatorListenerAdapter listener) {
+ public static void startAnimator(Animator animator, AnimatorListenerAdapter listener) {
if (listener != null) {
// Even if there's a delay we'd want to notify it of the start immediately.
listener.onAnimationStart(animator);
@@ -540,7 +625,8 @@
* @param previousAnimator the animator which was running before
* @return the new duration
*/
- protected long cancelAnimatorAndGetNewDuration(long duration, ValueAnimator previousAnimator) {
+ public static long cancelAnimatorAndGetNewDuration(long duration,
+ ValueAnimator previousAnimator) {
long newDuration = duration;
if (previousAnimator != null) {
// We take either the desired length of the new animation or the remaining time of
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notification/PropertyAnimatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/notification/PropertyAnimatorTest.java
new file mode 100644
index 0000000..193250f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/notification/PropertyAnimatorTest.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2016 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.systemui.notification;
+
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+
+import android.util.FloatProperty;
+import android.util.Property;
+import android.view.View;
+import android.view.animation.Interpolator;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.notification.PropertyAnimator;
+import com.android.systemui.statusbar.stack.AnimationFilter;
+import com.android.systemui.statusbar.stack.AnimationProperties;
+import com.android.systemui.statusbar.stack.ViewState;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PropertyAnimatorTest extends SysuiTestCase {
+
+ private View mView;
+ private FloatProperty<View> mEffectiveProperty = new FloatProperty<View>("TEST") {
+ public float mValue = 100;
+
+ @Override
+ public void setValue(View view, float value) {
+ mValue = value;
+ }
+
+ @Override
+ public Float get(View object) {
+ return mValue;
+ }
+ };
+ private PropertyAnimator.AnimatableProperty mProperty
+ = new PropertyAnimator.AnimatableProperty() {
+
+ @Override
+ public int getAnimationStartTag() {
+ return R.id.scale_x_animator_start_value_tag;
+ }
+
+ @Override
+ public int getAnimationEndTag() {
+ return R.id.scale_x_animator_end_value_tag;
+ }
+
+ @Override
+ public int getAnimatorTag() {
+ return R.id.scale_x_animator_tag;
+ }
+
+ @Override
+ public Property getProperty() {
+ return mEffectiveProperty;
+ }
+ };
+ private AnimatorListenerAdapter mFinishListener = mock(AnimatorListenerAdapter.class);
+ private AnimationProperties mAnimationProperties = new AnimationProperties() {
+ @Override
+ public AnimationFilter getAnimationFilter() {
+ return mAnimationFilter;
+ }
+
+ @Override
+ public AnimatorListenerAdapter getAnimationFinishListener() {
+ return mFinishListener;
+ }
+ }.setDuration(200);
+ private AnimationFilter mAnimationFilter = new AnimationFilter();
+ private Interpolator mTestInterpolator = Interpolators.ALPHA_IN;
+
+
+ @Before
+ @UiThreadTest
+ public void setUp() {
+ mView = new View(getContext());
+ }
+
+ @Test
+ @UiThreadTest
+ public void testAnimationStarted() {
+ mAnimationFilter.reset();
+ mAnimationFilter.animate(mProperty.getProperty());
+ PropertyAnimator.startAnimation(mView, mProperty, 200, mAnimationProperties);
+ assertTrue(ViewState.isAnimating(mView, mProperty));
+ }
+
+ @Test
+ @UiThreadTest
+ public void testNoAnimationStarted() {
+ mAnimationFilter.reset();
+ PropertyAnimator.startAnimation(mView, mProperty, 200, mAnimationProperties);
+ assertFalse(ViewState.isAnimating(mView, mProperty));
+ }
+
+ @Test
+ @UiThreadTest
+ public void testEndValueUpdated() {
+ mAnimationFilter.reset();
+ mAnimationFilter.animate(mProperty.getProperty());
+ PropertyAnimator.startAnimation(mView, mProperty, 200f, mAnimationProperties);
+ assertEquals(ViewState.getChildTag(mView, mProperty.getAnimationEndTag()),
+ Float.valueOf(200f));
+ }
+
+ @Test
+ @UiThreadTest
+ public void testStartTagUpdated() {
+ mEffectiveProperty.set(mView, 100f);
+ mAnimationFilter.reset();
+ mAnimationFilter.animate(mProperty.getProperty());
+ PropertyAnimator.startAnimation(mView, mProperty, 200f, mAnimationProperties);
+ assertEquals(ViewState.getChildTag(mView, mProperty.getAnimationStartTag()),
+ Float.valueOf(100f));
+ }
+
+ @Test
+ @UiThreadTest
+ public void testValueIsSetUnAnimated() {
+ mAnimationFilter.reset();
+ PropertyAnimator.startAnimation(mView, mProperty, 200f, mAnimationProperties);
+ assertEquals(Float.valueOf(200f), mEffectiveProperty.get(mView));
+ }
+
+ @Test
+ @UiThreadTest
+ public void testAnimationToRightValueUpdated() {
+ mAnimationFilter.reset();
+ mAnimationFilter.animate(mProperty.getProperty());
+ PropertyAnimator.startAnimation(mView, mProperty, 200f, mAnimationProperties);
+ mAnimationFilter.reset();
+ PropertyAnimator.startAnimation(mView, mProperty, 220f, mAnimationProperties);
+ assertTrue(ViewState.isAnimating(mView, mProperty));
+ assertEquals(ViewState.getChildTag(mView, mProperty.getAnimationEndTag()),
+ Float.valueOf(220f));
+ }
+
+ @Test
+ @UiThreadTest
+ public void testAnimationToRightValueUpdateAnimated() {
+ mAnimationFilter.reset();
+ mAnimationFilter.animate(mProperty.getProperty());
+ PropertyAnimator.startAnimation(mView, mProperty, 200f, mAnimationProperties);
+ mAnimationFilter.reset();
+ mAnimationFilter.animate(mProperty.getProperty());
+ PropertyAnimator.startAnimation(mView, mProperty, 220f, mAnimationProperties);
+ assertTrue(ViewState.isAnimating(mView, mProperty));
+ assertEquals(ViewState.getChildTag(mView, mProperty.getAnimationEndTag()),
+ Float.valueOf(220f));
+ }
+
+ @Test
+ @UiThreadTest
+ public void testStartTagShiftedWhenChanging() {
+ mEffectiveProperty.set(mView, 100f);
+ mAnimationFilter.reset();
+ mAnimationFilter.animate(mProperty.getProperty());
+ PropertyAnimator.startAnimation(mView, mProperty, 200f, mAnimationProperties);
+ mAnimationFilter.reset();
+ PropertyAnimator.startAnimation(mView, mProperty, 220f, mAnimationProperties);
+ assertEquals(ViewState.getChildTag(mView, mProperty.getAnimationStartTag()),
+ Float.valueOf(120f));
+ }
+
+ @Test
+ @UiThreadTest
+ public void testUsingDuration() {
+ mAnimationFilter.reset();
+ mAnimationFilter.animate(mProperty.getProperty());
+ mAnimationProperties.setDuration(500);
+ PropertyAnimator.startAnimation(mView, mProperty, 200f, mAnimationProperties);
+ ValueAnimator animator = ViewState.getChildTag(mView, mProperty.getAnimatorTag());
+ assertNotNull(animator);
+ assertEquals(animator.getDuration(), 500);
+ }
+
+ @Test
+ @UiThreadTest
+ public void testUsingDelay() {
+ mAnimationFilter.reset();
+ mAnimationFilter.animate(mProperty.getProperty());
+ mAnimationProperties.setDelay(200);
+ PropertyAnimator.startAnimation(mView, mProperty, 200f, mAnimationProperties);
+ ValueAnimator animator = ViewState.getChildTag(mView, mProperty.getAnimatorTag());
+ assertNotNull(animator);
+ assertEquals(animator.getStartDelay(), 200);
+ }
+
+ @Test
+ @UiThreadTest
+ public void testUsingInterpolator() {
+ mAnimationFilter.reset();
+ mAnimationFilter.animate(mProperty.getProperty());
+ mAnimationProperties.setCustomInterpolator(mEffectiveProperty, mTestInterpolator);
+ PropertyAnimator.startAnimation(mView, mProperty, 200f, mAnimationProperties);
+ ValueAnimator animator = ViewState.getChildTag(mView, mProperty.getAnimatorTag());
+ assertNotNull(animator);
+ assertEquals(animator.getInterpolator(), mTestInterpolator);
+ }
+
+ @Test
+ @UiThreadTest
+ public void testUsingListener() {
+ mAnimationFilter.reset();
+ mAnimationFilter.animate(mProperty.getProperty());
+ mAnimationProperties.setCustomInterpolator(mEffectiveProperty, mTestInterpolator);
+ PropertyAnimator.startAnimation(mView, mProperty, 200f, mAnimationProperties);
+ ValueAnimator animator = ViewState.getChildTag(mView, mProperty.getAnimatorTag());
+ assertNotNull(animator);
+ assertTrue(animator.getListeners().contains(mFinishListener));
+ }
+}