blob: 9415b7307b35b8da18649e21ffcbe8c4678c6e41 [file] [log] [blame]
/*
* 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 androidx.dynamicanimation.tests;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.floatThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.view.View;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.FlingAnimation;
import androidx.dynamicanimation.animation.FloatPropertyCompat;
import androidx.dynamicanimation.animation.FloatValueHolder;
import androidx.dynamicanimation.test.R;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.internal.matchers.GreaterThan;
import org.mockito.internal.matchers.LessThan;
@MediumTest
@RunWith(AndroidJUnit4.class)
public class FlingTests {
@Rule
public final ActivityTestRule<AnimationActivity> mActivityTestRule;
public View mView1;
public View mView2;
@Rule
public ExpectedException mExpectedException = ExpectedException.none();
public FlingTests() {
mActivityTestRule = new ActivityTestRule<>(AnimationActivity.class);
}
@Before
public void setup() throws Exception {
mView1 = mActivityTestRule.getActivity().findViewById(R.id.anim_view);
mView2 = mActivityTestRule.getActivity().findViewById(R.id.anim_another_view);
}
/**
* Test that custom properties are supported.
*/
@Test
public void testCustomProperties() {
final Object animObj = new Object();
FloatPropertyCompat property = new FloatPropertyCompat("") {
private float mValue = 0f;
@Override
public float getValue(Object object) {
assertEquals(animObj, object);
return mValue;
}
@Override
public void setValue(Object object, float value) {
assertEquals(animObj, object);
assertTrue(value > mValue);
assertTrue(value >= 100);
mValue = value;
}
};
final FlingAnimation anim = new FlingAnimation(animObj, property);
DynamicAnimation.OnAnimationEndListener listener = mock(
DynamicAnimation.OnAnimationEndListener.class);
anim.addEndListener(listener);
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
anim.setStartValue(100).setStartVelocity(2000).start();
}
});
verify(listener, timeout(1000)).onAnimationEnd(eq(anim), eq(false), floatThat(
new GreaterThan(110f)), eq(0f));
}
/**
* Test that spring animation can work with a single property without an object.
*/
@Test
public void testFloatValueHolder() {
FloatValueHolder floatValueHolder = new FloatValueHolder();
assertEquals(0.0f, floatValueHolder.getValue(), 0.01f);
final FlingAnimation anim = new FlingAnimation(floatValueHolder).setStartVelocity(-2500);
DynamicAnimation.OnAnimationEndListener listener = mock(
DynamicAnimation.OnAnimationEndListener.class);
anim.addEndListener(listener);
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
anim.start();
}
});
verify(listener, timeout(1000)).onAnimationEnd(eq(anim), eq(false), floatThat(
new LessThan(-50f)), eq(0f));
}
/**
* Test that friction does affect how fast the slow down happens. Fling animation with
* higher friction should finish first.
*/
@Test
public void testFriction() {
FloatValueHolder floatValueHolder = new FloatValueHolder();
float lowFriction = 0.5f;
float highFriction = 2f;
final FlingAnimation animLowFriction = new FlingAnimation(floatValueHolder);
final FlingAnimation animHighFriction = new FlingAnimation(floatValueHolder);
animHighFriction.setFriction(highFriction);
animLowFriction.setFriction(lowFriction);
DynamicAnimation.OnAnimationEndListener listener = mock(
DynamicAnimation.OnAnimationEndListener.class);
animHighFriction.addEndListener(listener);
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
animHighFriction.setStartVelocity(5000).setStartValue(0).start();
animLowFriction.setStartVelocity(5000).setStartValue(0).start();
}
});
verify(listener, timeout(1000)).onAnimationEnd(eq(animHighFriction), eq(false), floatThat(
new GreaterThan(200f)), eq(0f));
// By the time high scalar animation finishes, the lower friction animation should still be
// running.
assertTrue(animLowFriction.isRunning());
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
animLowFriction.cancel();
}
});
assertEquals(lowFriction, animLowFriction.getFriction(), 0f);
assertEquals(highFriction, animHighFriction.getFriction(), 0f);
}
/**
* Test that velocity threshold does affect how early fling animation ends. An animation with
* higher velocity threshold should finish first.
*/
@Test
public void testVelocityThreshold() {
FloatValueHolder floatValueHolder = new FloatValueHolder();
float lowThreshold = 5f;
final float highThreshold = 10f;
final FlingAnimation animLowThreshold = new FlingAnimation(floatValueHolder);
final FlingAnimation animHighThreshold = new FlingAnimation(floatValueHolder);
animHighThreshold.setMinimumVisibleChange(highThreshold);
animHighThreshold.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() {
@Override
public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) {
if (velocity != 0f) {
// Other than last frame, velocity should always be above threshold
assertTrue(velocity >= highThreshold);
}
}
});
animLowThreshold.setMinimumVisibleChange(lowThreshold);
DynamicAnimation.OnAnimationEndListener listener = mock(
DynamicAnimation.OnAnimationEndListener.class);
animHighThreshold.addEndListener(listener);
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
animHighThreshold.setStartVelocity(2000).setStartValue(0).start();
animLowThreshold.setStartVelocity(2000).setStartValue(0).start();
}
});
verify(listener, timeout(1000)).onAnimationEnd(eq(animHighThreshold), eq(false), floatThat(
new GreaterThan(200f)), eq(0f));
// By the time high scalar animation finishes, the lower friction animation should still be
// running.
assertTrue(animLowThreshold.isRunning());
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
animLowThreshold.cancel();
}
});
assertEquals(lowThreshold, animLowThreshold.getMinimumVisibleChange(), 0f);
assertEquals(highThreshold, animHighThreshold.getMinimumVisibleChange(), 0f);
}
}