package org.robolectric.shadows;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.Activity;
import android.os.Build;
import android.view.View;
import android.view.ViewAnimationUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.robolectric.Robolectric;
import org.robolectric.TestRunners;
import static android.os.Build.VERSION_CODES.LOLLIPOP;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(TestRunners.MultiApiSelfTest.class)
@Config(minSdk = LOLLIPOP)
public class ShadowRenderNodeAnimatorTest {
private Activity activity;
private View view;
private TestListener listener;
@Before
public void setUp() {
activity = Robolectric.setupActivity(Activity.class);
view = new View(activity);
activity.setContentView(view);
listener = new TestListener();
}
@Test
public void normal() {
Animator animator = ViewAnimationUtils.createCircularReveal(view, 10, 10, 10f, 100f);
animator.addListener(listener);
animator.start();
assertThat(listener.startCount).isEqualTo(1);
assertThat(listener.endCount).isEqualTo(1);
}
@Test
public void canceled() {
Animator animator = ViewAnimationUtils.createCircularReveal(view, 10, 10, 10f, 100f);
animator.addListener(listener);
Robolectric.getForegroundThreadScheduler().pause();
animator.start();
animator.cancel();
assertThat(listener.startCount).isEqualTo(1);
assertThat(listener.cancelCount).isEqualTo(1);
assertThat(listener.endCount).isEqualTo(1);
}
@Test
public void delayed() {
Animator animator = ViewAnimationUtils.createCircularReveal(view, 10, 10, 10f, 100f);
animator.setStartDelay(1000);
animator.addListener(listener);
animator.start();
assertThat(listener.startCount).isEqualTo(1);
assertThat(listener.endCount).isEqualTo(1);
}
@Test
public void neverStartedCanceled() {
Animator animator = ViewAnimationUtils.createCircularReveal(view, 10, 10, 10f, 100f);
animator.addListener(listener);
animator.cancel();
assertThat(listener.startCount).isEqualTo(0);
// This behavior changed between L and L MR1. In older versions, onAnimationCancel and
// onAnimationEnd would always be called regardless of whether the animation was started.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
assertThat(listener.cancelCount).isEqualTo(0);
assertThat(listener.endCount).isEqualTo(0);
} else {
assertThat(listener.cancelCount).isEqualTo(1);
assertThat(listener.endCount).isEqualTo(1);
}
}
@Test
public void neverStartedEnded() {
Animator animator = ViewAnimationUtils.createCircularReveal(view, 10, 10, 10f, 100f);
animator.addListener(listener);
animator.end();
// This behavior changed between L and L MR1. In older versions, onAnimationEnd would always be
// called without any guarantee that onAnimationStart had been called first.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
assertThat(listener.startCount).isEqualTo(1);
assertThat(listener.endCount).isEqualTo(1);
} else {
assertThat(listener.startCount).isEqualTo(0);
assertThat(listener.endCount).isEqualTo(1);
}
}
@Test
public void doubleCanceled() {
Animator animator = ViewAnimationUtils.createCircularReveal(view, 10, 10, 10f, 100f);
animator.addListener(listener);
Robolectric.getForegroundThreadScheduler().pause();
animator.start();
animator.cancel();
animator.cancel();
assertThat(listener.startCount).isEqualTo(1);
assertThat(listener.cancelCount).isEqualTo(1);
assertThat(listener.endCount).isEqualTo(1);
}
@Test
public void doubleEnded() {
Animator animator = ViewAnimationUtils.createCircularReveal(view, 10, 10, 10f, 100f);
animator.addListener(listener);
Robolectric.getForegroundThreadScheduler().pause();
animator.start();
animator.end();
animator.end();
assertThat(listener.startCount).isEqualTo(1);
assertThat(listener.endCount).isEqualTo(1);
}
@Test
public void delayedAndCanceled() {
Animator animator = ViewAnimationUtils.createCircularReveal(view, 10, 10, 10f, 100f);
animator.setStartDelay(1000);
animator.addListener(listener);
Robolectric.getForegroundThreadScheduler().pause();
animator.start();
animator.cancel();
// This behavior changed between L and L MR1. In older versions, onAnimationStart gets called
// *twice* if you cancel a delayed animation before any of its frames run (as both cancel() and
// onFinished() implement special behavior for STATE_DELAYED, but the state only gets set to
// finished after onFinished()).
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
assertThat(listener.startCount).isEqualTo(1);
} else {
assertThat(listener.startCount).isEqualTo(2);
}
assertThat(listener.cancelCount).isEqualTo(1);
assertThat(listener.endCount).isEqualTo(1);
}
private static class TestListener extends AnimatorListenerAdapter {
public int startCount;
public int cancelCount;
public int endCount;
@Override
public void onAnimationStart(Animator animation) {
startCount++;
}
@Override
public void onAnimationCancel(Animator animation) {
cancelCount++;
}
@Override
public void onAnimationEnd(Animator animation) {
endCount++;
}
}
}