1 /*
2  * Copyright (C) 2008 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 android.view.animation.cts;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertSame;
23 import static org.junit.Assert.assertTrue;
24 
25 import android.Manifest;
26 import android.app.Activity;
27 import android.app.Instrumentation;
28 import android.content.res.XmlResourceParser;
29 import android.platform.test.annotations.AppModeSdkSandbox;
30 import android.util.AttributeSet;
31 import android.util.Xml;
32 import android.view.View;
33 import android.view.animation.AccelerateInterpolator;
34 import android.view.animation.AlphaAnimation;
35 import android.view.animation.Animation;
36 import android.view.animation.AnimationSet;
37 import android.view.animation.ScaleAnimation;
38 import android.view.animation.Transformation;
39 import android.view.animation.TranslateAnimation;
40 import android.view.cts.R;
41 
42 import androidx.test.InstrumentationRegistry;
43 import androidx.test.filters.MediumTest;
44 import androidx.test.rule.ActivityTestRule;
45 import androidx.test.runner.AndroidJUnit4;
46 
47 import com.android.compatibility.common.util.AdoptShellPermissionsRule;
48 
49 import org.junit.Before;
50 import org.junit.Rule;
51 import org.junit.Test;
52 import org.junit.runner.RunWith;
53 
54 import java.util.List;
55 
56 @MediumTest
57 @RunWith(AndroidJUnit4.class)
58 @AppModeSdkSandbox(reason = "Allow test in the SDK sandbox (does not prevent other modes).")
59 public class AnimationSetTest {
60     private static final float DELTA = 0.001f;
61     private static final long SHORT_CHILD_DURATION = 400;
62     private static final long MEDIUM_CHILD_DURATION = 800;
63     private static final long LONG_CHILD_DURATION = 1200;
64     /**
65      * initial size for initialize(int width, int height, int parentWidth, int parentHeight)
66      */
67     private static final int INITIAL_SIZE = 100;
68     private static final long ANIMATIONSET_DURATION = 1000;
69 
70     private Instrumentation mInstrumentation;
71     private Activity mActivity;
72 
73     @Rule(order = 0)
74     public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule(
75             androidx.test.platform.app.InstrumentationRegistry
76                     .getInstrumentation().getUiAutomation(),
77             Manifest.permission.START_ACTIVITIES_FROM_SDK_SANDBOX);
78 
79     @Rule(order = 1)
80     public ActivityTestRule<AnimationTestCtsActivity> mActivityRule =
81             new ActivityTestRule<>(AnimationTestCtsActivity.class);
82 
83     @Before
setup()84     public void setup() {
85         mInstrumentation = InstrumentationRegistry.getInstrumentation();
86         mActivity = mActivityRule.getActivity();
87     }
88 
89     @Test
testConstructor()90     public void testConstructor() {
91         new AnimationSet(true);
92 
93         final XmlResourceParser parser = mActivity.getResources().getAnimation(
94                 R.anim.anim_set);
95         final AttributeSet attr = Xml.asAttributeSet(parser);
96         assertNotNull(attr);
97         // Test with real AttributeSet
98         new AnimationSet(mActivity, attr);
99     }
100 
101     @Test
testInitialize()102     public void testInitialize() {
103         final AnimationSet animationSet = createAnimationSet();
104         animationSet.setDuration(ANIMATIONSET_DURATION);
105         // Before initialize, the durations are original.
106         List<Animation> children = animationSet.getAnimations();
107         assertEquals(SHORT_CHILD_DURATION, children.get(0).getDuration());
108         assertEquals(MEDIUM_CHILD_DURATION, children.get(1).getDuration());
109         assertEquals(LONG_CHILD_DURATION, children.get(2).getDuration());
110 
111         // After initialize, AnimationSet override the child values.
112         assertFalse(animationSet.isInitialized());
113         animationSet.initialize(INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE);
114         assertTrue(animationSet.isInitialized());
115         children = animationSet.getAnimations();
116         assertEquals(ANIMATIONSET_DURATION, children.get(0).getDuration());
117         assertEquals(ANIMATIONSET_DURATION, children.get(1).getDuration());
118         assertEquals(ANIMATIONSET_DURATION, children.get(2).getDuration());
119     }
120 
createAnimationSet()121     private AnimationSet createAnimationSet() {
122         AnimationSet animationSet = new AnimationSet(true);
123 
124         Animation animation1 = new AlphaAnimation(0.0f, 1.0f);
125         animation1.setDuration(SHORT_CHILD_DURATION);
126         animationSet.addAnimation(animation1);
127 
128         Animation animation2 = new ScaleAnimation(1.0f, 2.0f, 1.0f, 3.0f);
129         animation2.setDuration(MEDIUM_CHILD_DURATION);
130         animationSet.addAnimation(animation2);
131 
132         Animation animation3 = new TranslateAnimation(0.0f, 50.0f, 0.0f, 5.0f);
133         animation3.setDuration(LONG_CHILD_DURATION);
134         animationSet.addAnimation(animation3);
135 
136         return animationSet;
137     }
138 
139     @Test
testSetFillAfter()140     public void testSetFillAfter() {
141         final AnimationSet animationSet = createAnimationSet();
142         assertFalse(animationSet.getFillAfter());
143 
144         List<Animation> children = animationSet.getAnimations();
145         children.get(0).setFillAfter(true);
146         children.get(1).setFillAfter(false);
147 
148         animationSet.setFillAfter(true);
149         animationSet.initialize(INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE);
150         assertTrue(animationSet.getFillAfter());
151         children = animationSet.getAnimations();
152         for (int i = 0; i < children.size(); i++) {
153             assertTrue(children.get(i).getFillAfter());
154         }
155     }
156 
157     @Test
testSetFillBefore()158     public void testSetFillBefore() {
159         final AnimationSet animationSet = createAnimationSet();
160         assertTrue(animationSet.getFillBefore());
161 
162         List<Animation> children = animationSet.getAnimations();
163         children.get(0).setFillBefore(true);
164         children.get(1).setFillBefore(false);
165 
166         animationSet.setFillBefore(false);
167         animationSet.initialize(INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE);
168         assertFalse(animationSet.getFillBefore());
169         children = animationSet.getAnimations();
170         for (int i = 0; i < children.size(); i++) {
171             assertFalse(children.get(i).getFillBefore());
172         }
173     }
174 
175     @Test
testAccessDuration()176     public void testAccessDuration() {
177         final AnimationSet animationSet = createAnimationSet();
178         assertEquals(LONG_CHILD_DURATION, animationSet.getDuration());
179 
180         assertTrue(animationSet.getDuration() > ANIMATIONSET_DURATION);
181         animationSet.setDuration(ANIMATIONSET_DURATION);
182         animationSet.initialize(INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE);
183         assertEquals(ANIMATIONSET_DURATION, animationSet.getDuration());
184         final List<Animation> children = animationSet.getAnimations();
185         for (int i = 0; i < children.size(); i++) {
186             assertEquals(ANIMATIONSET_DURATION, children.get(i).getDuration());
187         }
188     }
189 
190     @Test
testRestrictDuration()191     public void testRestrictDuration() {
192         final AnimationSet animationSet = new AnimationSet(false);
193         Animation child = null;
194         final long[] originChildDuration = { 1000, 1000, 500 };
195         final long[] originChildStartOffset = { 2000, 1000, 0 };
196         final int[] originChildRepeatCount = { 0, 0, 4 };
197         final long[] originChildDurationHint = new long[3];
198         for (int i = 0; i < 3; i++) {
199             child = new AlphaAnimation(0.0f, 1.0f);
200             child.setDuration(originChildDuration[i]);
201             child.setStartOffset(originChildStartOffset[i]);
202             child.setRepeatCount(originChildRepeatCount[i]);
203             originChildDurationHint[i] = child.computeDurationHint();
204             animationSet.addAnimation(child);
205         }
206         final long restrictDuration = 1500;
207         animationSet.restrictDuration(restrictDuration);
208         final List<Animation> children = animationSet.getAnimations();
209 
210         assertTrue(originChildStartOffset[0] > restrictDuration);
211         assertEquals(0, children.get(0).getDuration());
212         assertEquals(restrictDuration, children.get(0).getStartOffset());
213 
214         assertTrue(originChildStartOffset[1] < restrictDuration);
215         assertTrue(originChildDurationHint[1] > restrictDuration);
216         assertTrue(children.get(1).computeDurationHint() <= restrictDuration);
217 
218         assertTrue(originChildDurationHint[2] > restrictDuration);
219         assertTrue(children.get(2).computeDurationHint() <= restrictDuration);
220         assertTrue(originChildRepeatCount[2] > children.get(2).getRepeatCount());
221     }
222 
223     @Test
testComputeDurationHint()224     public void testComputeDurationHint() {
225         final AnimationSet animationSet = createAnimationSet();
226         final List<Animation> children = animationSet.getAnimations();
227         long expectedDuration = 0;
228         for (int i = 0; i < children.size(); i++) {
229             expectedDuration = Math.max(expectedDuration, children.get(i).computeDurationHint());
230         }
231         assertEquals(expectedDuration, animationSet.computeDurationHint());
232     }
233 
234     @Test
testScaleCurrentDuration()235     public void testScaleCurrentDuration() {
236         final AnimationSet animationSet = createAnimationSet();
237         List<Animation> children = animationSet.getAnimations();
238         final long[] originDurations = new long[children.size()];
239         for (int i = 0; i < children.size(); i++) {
240             originDurations[i] = children.get(i).getDuration();
241         }
242 
243         final float scaleFactor = 2.0f;
244         animationSet.scaleCurrentDuration(scaleFactor);
245         children = animationSet.getAnimations();
246         for (int i = 0; i < children.size(); i++) {
247             assertEquals((long) (originDurations[i] * scaleFactor), children.get(i).getDuration());
248         }
249     }
250 
251     @Test
testAccessRepeatMode()252     public void testAccessRepeatMode() {
253         final AnimationSet animationSet = createAnimationSet();
254         animationSet.setRepeatMode(Animation.RESTART);
255         animationSet.initialize(INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE);
256         assertEquals(Animation.RESTART, animationSet.getRepeatMode());
257         List<Animation> children = animationSet.getAnimations();
258         for (int i = 0; i < children.size(); i++) {
259             assertEquals(Animation.RESTART, children.get(i).getRepeatMode());
260         }
261 
262         animationSet.setRepeatMode(Animation.REVERSE);
263         animationSet.initialize(INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE);
264         assertEquals(Animation.REVERSE, animationSet.getRepeatMode());
265         children = animationSet.getAnimations();
266         for (int i = 0; i < children.size(); i++) {
267             assertEquals(Animation.REVERSE, children.get(i).getRepeatMode());
268         }
269     }
270 
271     @Test
testAccessStartOffset()272     public void testAccessStartOffset() {
273         final AnimationSet animationSet = createAnimationSet();
274         assertEquals(0, animationSet.getStartOffset());
275         List<Animation> children = animationSet.getAnimations();
276         final long[] originStartOffset = new long[children.size()];
277         for (int i = 0; i < children.size(); i++) {
278             originStartOffset[i] = children.get(i).getStartOffset();
279         }
280 
281         animationSet.setStartOffset(100);
282         animationSet.initialize(INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE);
283         assertEquals(100, animationSet.getStartOffset());
284         children = animationSet.getAnimations();
285         for (int i = 0; i < children.size(); i++) {
286             assertEquals(originStartOffset[i] + animationSet.getStartOffset(),
287                     children.get(i).getStartOffset());
288         }
289 
290         assertTrue(animationSet.isInitialized());
291         animationSet.reset();
292         assertFalse(animationSet.isInitialized());
293         children = animationSet.getAnimations();
294         for (int i = 0; i < children.size(); i++) {
295             assertEquals(originStartOffset[i], children.get(i).getStartOffset());
296         }
297     }
298 
299     @Test
testAccessStartTime()300     public void testAccessStartTime() {
301         final AnimationSet animationSet = createAnimationSet();
302         final long[] originChildStartTime = {1000, 2000, 3000};
303         List<Animation> children = animationSet.getAnimations();
304         for (int i = 0; i < children.size(); i++) {
305             children.get(i).setStartTime(originChildStartTime[i]);
306         }
307 
308         // Get earliest start time of children animations
309         assertEquals(1000, animationSet.getStartTime());
310 
311         final long startTime = 200;
312         animationSet.setStartTime(startTime);
313         assertEquals(startTime, animationSet.getStartTime());
314 
315         children = animationSet.getAnimations();
316         for (int i = 0; i < children.size(); i++) {
317             assertEquals(startTime, children.get(i).getStartTime());
318         }
319     }
320 
321     @Test
testGetTransformation()322     public void testGetTransformation() throws Throwable {
323         final View animWindowParent = mActivity.findViewById(R.id.anim_window_parent);
324         final View animWindow = mActivity.findViewById(R.id.anim_window);
325         final AnimationSet animationSet = createAnimationSet();
326         animationSet.setDuration(2000);
327         animationSet.initialize(animWindow.getWidth(), animWindow.getHeight(),
328                 animWindowParent.getWidth(), animWindowParent.getHeight());
329 
330         AnimationTestUtils.assertRunAnimation(mInstrumentation, mActivityRule, animWindow,
331                 animationSet);
332         final long startTime = animationSet.getStartTime();
333 
334         assertGetTransformation(animationSet, startTime, true);
335         assertGetTransformation(animationSet, startTime + 100, true);
336         assertGetTransformation(animationSet, startTime + animationSet.getDuration(), false);
337     }
338 
assertGetTransformation(final AnimationSet animationSet, final long currentTime, final boolean result)339     private void assertGetTransformation(final AnimationSet animationSet,
340             final long currentTime, final boolean result) {
341         final Transformation transformation = new Transformation();
342         final Transformation expectedTransformation = new Transformation();
343         final Transformation tempTransformation = new Transformation();
344 
345         assertEquals(result, animationSet.getTransformation(currentTime, transformation));
346         final List<Animation> children = animationSet.getAnimations();
347         for (int i = children.size() - 1; i >= 0; i--) {
348             tempTransformation.clear();
349             children.get(i).getTransformation(currentTime, tempTransformation);
350             expectedTransformation.compose(tempTransformation);
351         }
352         assertTransformationEquals(expectedTransformation, transformation);
353     }
354 
assertTransformationEquals(final Transformation expected, final Transformation actual)355     private void assertTransformationEquals(final Transformation expected,
356             final Transformation actual) {
357         assertEquals(expected.getAlpha(), actual.getAlpha(), DELTA);
358         final float[] expectedValues = new float[9];
359         final float[] actualValues = new float[9];
360         expected.getMatrix().getValues(expectedValues);
361         actual.getMatrix().getValues(actualValues);
362         for (int i = 0; i < expectedValues.length; i++) {
363             assertEquals(expectedValues[i], actualValues[i], DELTA);
364         }
365     }
366 
367     @Test
testAccessAnimations()368     public void testAccessAnimations() {
369         final AnimationSet animationSet = new AnimationSet(true);
370         final Animation animation1 = new AlphaAnimation(0.0f, 1.0f);
371         animationSet.addAnimation(animation1);
372         final Animation animation2 = new AlphaAnimation(0.5f, 1.0f);
373         animationSet.addAnimation(animation2);
374         final Animation animation3 = new AlphaAnimation(1.0f, 0.5f);
375         animationSet.addAnimation(animation3);
376 
377         final List<Animation> children = animationSet.getAnimations();
378         assertEquals(3, children.size());
379         assertSame(animation1, children.get(0));
380         assertSame(animation2, children.get(1));
381         assertSame(animation3, children.get(2));
382     }
383 
384     @Test
testWillChangeTransformationMatrix()385     public void testWillChangeTransformationMatrix() {
386         final AnimationSet animationSet = new AnimationSet(true);
387         assertFalse(animationSet.willChangeTransformationMatrix());
388 
389         // Add first animation, this is an alpha animation and will not change
390         // the transformation matrix.
391         animationSet.addAnimation(new AlphaAnimation(0.0f, 1.0f));
392         assertFalse(animationSet.willChangeTransformationMatrix());
393         assertFalse(animationSet.willChangeBounds());
394 
395         // Add second animation, this is an scale animation and will change
396         // the transformation matrix.
397         animationSet.addAnimation(new ScaleAnimation(1.0f, 2.0f, 1.0f, 2.0f));
398         assertTrue(animationSet.willChangeTransformationMatrix());
399         assertTrue(animationSet.willChangeBounds());
400     }
401 
402     @Test
testClone()403     public void testClone() throws CloneNotSupportedException {
404         final MyAnimationSet animationSet = new MyAnimationSet(false);
405         final Animation alpha = new AlphaAnimation(0.0f, 1.0f);
406         alpha.setInterpolator(new AccelerateInterpolator());
407         alpha.initialize(INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE);
408         final Animation scale = new ScaleAnimation(1.0f, 2.0f, 1.0f, 3.0f);
409         scale.initialize(INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE);
410         animationSet.addAnimation(alpha);
411         animationSet.addAnimation(scale);
412         final long startTime = 0;
413         animationSet.setStartTime(startTime);
414         animationSet.setDuration(ANIMATIONSET_DURATION);
415         animationSet.initialize(INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE);
416 
417         final AnimationSet clone = animationSet.clone();
418         clone.initialize(INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE, INITIAL_SIZE);
419         final List<Animation> children = animationSet.getAnimations();
420         final List<Animation> cloneChildren = clone.getAnimations();
421         assertEquals(children.size(), cloneChildren.size());
422         final Transformation expectedTransformation = new Transformation();
423         final Transformation transformation = new Transformation();
424         for (int i = 0; i < children.size(); i++) {
425             children.get(i).getTransformation(startTime, expectedTransformation);
426             cloneChildren.get(i).getTransformation(startTime, transformation);
427             assertTransformationEquals(expectedTransformation, transformation);
428 
429             children.get(i).getTransformation(startTime + ANIMATIONSET_DURATION / 2,
430                     expectedTransformation);
431             cloneChildren.get(i).getTransformation(startTime  + ANIMATIONSET_DURATION /2,
432                     transformation);
433             assertTransformationEquals(expectedTransformation, transformation);
434 
435             children.get(i).getTransformation(startTime + ANIMATIONSET_DURATION,
436                     expectedTransformation);
437             cloneChildren.get(i).getTransformation(startTime  + ANIMATIONSET_DURATION,
438                     transformation);
439             assertTransformationEquals(expectedTransformation, transformation);
440         }
441     }
442 
443     private static class MyAnimationSet extends AnimationSet {
444 
MyAnimationSet(boolean shareInterpolator)445         public MyAnimationSet(boolean shareInterpolator) {
446             super(shareInterpolator);
447         }
448 
449         @Override
clone()450         protected AnimationSet clone() throws CloneNotSupportedException {
451             return super.clone();
452         }
453     }
454 }
455