1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.core.animation; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertThrows; 22 import static org.junit.Assert.assertTrue; 23 24 import android.content.Context; 25 import android.os.Build; 26 import android.view.InflateException; 27 28 import androidx.core.animation.testapp.test.R; 29 import androidx.test.annotation.UiThreadTest; 30 import androidx.test.core.app.ApplicationProvider; 31 import androidx.test.ext.junit.runners.AndroidJUnit4; 32 import androidx.test.filters.SmallTest; 33 34 import org.junit.ClassRule; 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 38 @SmallTest 39 @RunWith(AndroidJUnit4.class) 40 public class AnimatorInflaterTest { 41 42 private static final float EPSILON = 0.01f; 43 44 @ClassRule 45 public static AnimatorTestRule sAnimatorTestRule = new AnimatorTestRule(); 46 47 @UiThreadTest 48 @Test testLoadAnimator()49 public void testLoadAnimator() { 50 Context context = ApplicationProvider.getApplicationContext(); 51 Animator anim = AnimatorInflater.loadAnimator(context, R.animator.animator_set_with_dimens); 52 assertEquals(100, anim.getTotalDuration()); 53 54 TestObject obj = new TestObject(); 55 anim.setTarget(obj); 56 anim.start(); 57 58 assertTrue(anim.isRunning()); 59 sAnimatorTestRule.advanceTimeBy(anim.getTotalDuration()); 60 assertFalse(anim.isRunning()); 61 62 float targetX = context.getResources().getDimension(R.dimen.test_animator_target_x); 63 float targetY = context.getResources().getDimension(R.dimen.test_animator_target_y); 64 65 assertEquals(targetX, obj.x, EPSILON); 66 assertEquals(targetY, obj.y, EPSILON); 67 assertEquals(2, obj.left); 68 } 69 70 71 @UiThreadTest 72 @Test testLoadAnimatorAlongPath()73 public void testLoadAnimatorAlongPath() { 74 Context context = ApplicationProvider.getApplicationContext(); 75 Animator anim = AnimatorInflater.loadAnimator(context, R.animator.animator_along_path); 76 assertTrue(anim.getInterpolator() instanceof LinearInterpolator); 77 assertEquals(100, anim.getDuration()); 78 TestObject obj = new TestObject(); 79 anim.setTarget(obj); 80 anim.start(); 81 82 // Check whether the animation is indeed running along the path. 83 int inc = 2; 84 for (int i = 0; i <= 100; i += inc) { 85 float y = i <= 50 ? 0 : 100; 86 assertEquals(i, obj.x, EPSILON); 87 assertEquals(y, obj.y, EPSILON); 88 sAnimatorTestRule.advanceTimeBy(inc); 89 } 90 } 91 92 @Test pathInterpolator()93 public void pathInterpolator() { 94 final Interpolator interpolator = AnimatorInflater.loadInterpolator( 95 ApplicationProvider.getApplicationContext(), 96 R.interpolator.path_interpolator 97 ); 98 assertEquals(0.85f, interpolator.getInterpolation(0.5f), EPSILON); 99 } 100 101 @Test pathInterpolator_controlPoints()102 public void pathInterpolator_controlPoints() { 103 final Interpolator interpolator = AnimatorInflater.loadInterpolator( 104 ApplicationProvider.getApplicationContext(), 105 R.interpolator.control_points_interpolator 106 ); 107 assertEquals(0.89f, interpolator.getInterpolation(0.5f), EPSILON); 108 } 109 110 @Test pathInterpolator_singleControlPoint()111 public void pathInterpolator_singleControlPoint() { 112 final Interpolator interpolator = AnimatorInflater.loadInterpolator( 113 ApplicationProvider.getApplicationContext(), 114 R.interpolator.single_control_point_interpolator 115 ); 116 assertEquals(0.086f, interpolator.getInterpolation(0.5f), EPSILON); 117 } 118 119 @Test pathInterpolator_wrongControlPoint()120 public void pathInterpolator_wrongControlPoint() { 121 InflateException exception = assertThrows(InflateException.class, () -> { 122 AnimatorInflater.loadInterpolator(ApplicationProvider.getApplicationContext(), 123 R.interpolator.wrong_control_point_interpolator); 124 }); 125 assertEquals("pathInterpolator requires the controlY1 attribute", exception.getMessage()); 126 } 127 128 @Test pathInterpolator_wrongControlPoints()129 public void pathInterpolator_wrongControlPoints() { 130 131 132 InflateException exception = assertThrows(InflateException.class, () -> { 133 AnimatorInflater.loadInterpolator(ApplicationProvider.getApplicationContext(), 134 R.interpolator.wrong_control_points_interpolator); 135 }); 136 assertEquals("pathInterpolator requires both controlX2 and controlY2 for cubic Beziers.", 137 exception.getMessage()); 138 } 139 140 @Test pathInterpolator_wrongStartEnd()141 public void pathInterpolator_wrongStartEnd() { 142 IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { 143 AnimatorInflater.loadInterpolator(ApplicationProvider.getApplicationContext(), 144 R.interpolator.wrong_path_interpolator_1); 145 }); 146 assertEquals("The Path must start at (0,0) and end at (1,1)", exception.getMessage()); 147 } 148 149 @Test pathInterpolator_loopBack()150 public void pathInterpolator_loopBack() { 151 IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { 152 AnimatorInflater.loadInterpolator(ApplicationProvider.getApplicationContext(), 153 R.interpolator.wrong_path_interpolator_2); 154 }); 155 assertEquals("The Path cannot loop back on itself.", exception.getMessage()); 156 157 } 158 159 @Test pathInterpolator_discontinuity()160 public void pathInterpolator_discontinuity() { 161 IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { 162 AnimatorInflater.loadInterpolator(ApplicationProvider.getApplicationContext(), 163 R.interpolator.wrong_path_interpolator_3); 164 }); 165 assertEquals(Build.VERSION.SDK_INT >= 26 166 ? "The Path cannot have discontinuity in the X axis." 167 // Older APIs don't detect discontinuity, but they report it as loop back. 168 : "The Path cannot loop back on itself.", exception.getMessage()); 169 } 170 171 static class TestObject { 172 173 public float x; 174 public float y; 175 public int left; 176 getX()177 public float getX() { 178 return x; 179 } 180 setX(float x)181 public void setX(float x) { 182 this.x = x; 183 } 184 getY()185 public float getY() { 186 return y; 187 } 188 setY(float y)189 public void setY(float y) { 190 this.y = y; 191 } 192 setLeft(int left)193 public void setLeft(int left) { 194 this.left = left; 195 } 196 getLeft()197 public int getLeft() { 198 return left; 199 } 200 } 201 202 } 203