1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.LOLLIPOP; 4 import static org.assertj.core.api.Assertions.assertThat; 5 6 import android.animation.Animator; 7 import android.animation.AnimatorListenerAdapter; 8 import android.app.Activity; 9 import android.os.Build; 10 import android.view.View; 11 import android.view.ViewAnimationUtils; 12 import org.junit.Before; 13 import org.junit.Test; 14 import org.junit.runner.RunWith; 15 import org.robolectric.Robolectric; 16 import org.robolectric.RobolectricTestRunner; 17 import org.robolectric.annotation.Config; 18 19 @RunWith(RobolectricTestRunner.class) 20 @Config(minSdk = LOLLIPOP) 21 public class ShadowRenderNodeAnimatorTest { 22 private Activity activity; 23 private View view; 24 private TestListener listener; 25 26 @Before 27 public void setUp() { 28 activity = Robolectric.setupActivity(Activity.class); 29 view = new View(activity); 30 activity.setContentView(view); 31 listener = new TestListener(); 32 } 33 34 @Test 35 public void normal() { 36 Animator animator = ViewAnimationUtils.createCircularReveal(view, 10, 10, 10f, 100f); 37 animator.addListener(listener); 38 animator.start(); 39 40 assertThat(listener.startCount).isEqualTo(1); 41 assertThat(listener.endCount).isEqualTo(1); 42 } 43 44 @Test 45 public void canceled() { 46 Animator animator = ViewAnimationUtils.createCircularReveal(view, 10, 10, 10f, 100f); 47 animator.addListener(listener); 48 49 Robolectric.getForegroundThreadScheduler().pause(); 50 animator.start(); 51 animator.cancel(); 52 53 assertThat(listener.startCount).isEqualTo(1); 54 assertThat(listener.cancelCount).isEqualTo(1); 55 assertThat(listener.endCount).isEqualTo(1); 56 } 57 58 @Test 59 public void delayed() { 60 Animator animator = ViewAnimationUtils.createCircularReveal(view, 10, 10, 10f, 100f); 61 animator.setStartDelay(1000); 62 animator.addListener(listener); 63 64 animator.start(); 65 66 assertThat(listener.startCount).isEqualTo(1); 67 assertThat(listener.endCount).isEqualTo(1); 68 } 69 70 @Test 71 public void neverStartedCanceled() { 72 Animator animator = ViewAnimationUtils.createCircularReveal(view, 10, 10, 10f, 100f); 73 animator.addListener(listener); 74 75 animator.cancel(); 76 77 assertThat(listener.startCount).isEqualTo(0); 78 // This behavior changed between L and L MR1. In older versions, onAnimationCancel and 79 // onAnimationEnd would always be called regardless of whether the animation was started. 80 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { 81 assertThat(listener.cancelCount).isEqualTo(0); 82 assertThat(listener.endCount).isEqualTo(0); 83 } else { 84 assertThat(listener.cancelCount).isEqualTo(1); 85 assertThat(listener.endCount).isEqualTo(1); 86 } 87 } 88 89 @Test 90 public void neverStartedEnded() { 91 Animator animator = ViewAnimationUtils.createCircularReveal(view, 10, 10, 10f, 100f); 92 animator.addListener(listener); 93 94 animator.end(); 95 96 // This behavior changed between L and L MR1. In older versions, onAnimationEnd would always be 97 // called without any guarantee that onAnimationStart had been called first. 98 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { 99 assertThat(listener.startCount).isEqualTo(1); 100 assertThat(listener.endCount).isEqualTo(1); 101 } else { 102 assertThat(listener.startCount).isEqualTo(0); 103 assertThat(listener.endCount).isEqualTo(1); 104 } 105 } 106 107 @Test 108 public void doubleCanceled() { 109 Animator animator = ViewAnimationUtils.createCircularReveal(view, 10, 10, 10f, 100f); 110 animator.addListener(listener); 111 112 Robolectric.getForegroundThreadScheduler().pause(); 113 animator.start(); 114 animator.cancel(); 115 animator.cancel(); 116 117 assertThat(listener.startCount).isEqualTo(1); 118 assertThat(listener.cancelCount).isEqualTo(1); 119 assertThat(listener.endCount).isEqualTo(1); 120 } 121 122 @Test 123 public void doubleEnded() { 124 Animator animator = ViewAnimationUtils.createCircularReveal(view, 10, 10, 10f, 100f); 125 animator.addListener(listener); 126 127 Robolectric.getForegroundThreadScheduler().pause(); 128 animator.start(); 129 animator.end(); 130 animator.end(); 131 132 assertThat(listener.startCount).isEqualTo(1); 133 assertThat(listener.endCount).isEqualTo(1); 134 } 135 136 @Test 137 public void delayedAndCanceled() { 138 Animator animator = ViewAnimationUtils.createCircularReveal(view, 10, 10, 10f, 100f); 139 animator.setStartDelay(1000); 140 animator.addListener(listener); 141 142 Robolectric.getForegroundThreadScheduler().pause(); 143 animator.start(); 144 animator.cancel(); 145 146 // This behavior changed between L and L MR1. In older versions, onAnimationStart gets called 147 // *twice* if you cancel a delayed animation before any of its frames run (as both cancel() and 148 // onFinished() implement special behavior for STATE_DELAYED, but the state only gets set to 149 // finished after onFinished()). 150 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { 151 assertThat(listener.startCount).isEqualTo(1); 152 } else { 153 assertThat(listener.startCount).isEqualTo(2); 154 } 155 assertThat(listener.cancelCount).isEqualTo(1); 156 assertThat(listener.endCount).isEqualTo(1); 157 } 158 159 private static class TestListener extends AnimatorListenerAdapter { 160 public int startCount; 161 public int cancelCount; 162 public int endCount; 163 164 @Override 165 public void onAnimationStart(Animator animation) { 166 startCount++; 167 } 168 169 @Override 170 public void onAnimationCancel(Animator animation) { 171 cancelCount++; 172 } 173 174 @Override 175 public void onAnimationEnd(Animator animation) { 176 endCount++; 177 } 178 } 179 } 180