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
17package android.view.animation.cts;
18
19import com.android.cts.stub.R;
20
21
22import android.app.ListActivity;
23import android.content.Context;
24import android.content.res.XmlResourceParser;
25import android.test.ActivityInstrumentationTestCase2;
26import android.util.AttributeSet;
27import android.util.Xml;
28import android.view.View;
29import android.view.ViewGroup.LayoutParams;
30import android.view.animation.AccelerateInterpolator;
31import android.view.animation.Animation;
32import android.view.animation.AnimationUtils;
33import android.view.animation.DecelerateInterpolator;
34import android.view.animation.Interpolator;
35import android.view.animation.LayoutAnimationController;
36import android.view.animation.ScaleAnimation;
37import android.view.animation.Transformation;
38import android.view.animation.LayoutAnimationController.AnimationParameters;
39import android.widget.AbsListView;
40import android.widget.ListView;
41
42public class LayoutAnimationControllerTest
43        extends ActivityInstrumentationTestCase2<LayoutAnimStubActivity> {
44
45    private ListActivity mActivity;
46    private Animation mDefaultAnimation;
47    private ListView mListView;
48    private LayoutAnimationController mController;
49    /** Duration defined in layout_anim_controller_animation.xml is 1000 */
50    private static final int DURATION = 1000;
51    private static final float DELTA = 0.1f;
52    private static final int INDEX_OF_CHILD1 = 0;
53    private static final int INDEX_OF_CHILD2 = 1;
54    private static final int INDEX_OF_CHILD3 = 2;
55    /** Default delay of LayoutAnimationController */
56    private static final float DEFAULT_DELAY = 0.5f;
57    /** Default max duration of these three children */
58    private static final long DEFAULT_MAX_DURATION = 2000;
59
60    public LayoutAnimationControllerTest() {
61        super("com.android.cts.stub", LayoutAnimStubActivity.class);
62    }
63
64    @Override
65    protected void setUp() throws Exception {
66        super.setUp();
67        mActivity = getActivity();
68        mListView = mActivity.getListView();
69        mDefaultAnimation = AnimationUtils.loadAnimation(mActivity,
70                R.anim.layout_anim_controller_animation);
71        mController = new LayoutAnimationController(mDefaultAnimation, DEFAULT_DELAY);
72    }
73
74    public void testAccessOrder() throws InterruptedException {
75
76        mController.setOrder(LayoutAnimationController.ORDER_NORMAL);
77        assertEquals(LayoutAnimationController.ORDER_NORMAL, mController.getOrder());
78
79        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, mController,
80                DEFAULT_MAX_DURATION);
81
82        Animation childAnimation1 = mListView.getChildAt(INDEX_OF_CHILD1).getAnimation();
83        Animation childAnimation2 = mListView.getChildAt(INDEX_OF_CHILD2).getAnimation();
84        Animation childAnimation3 = mListView.getChildAt(INDEX_OF_CHILD3).getAnimation();
85
86        // Test normal order
87        long startTime = childAnimation1.getStartTime();
88        assertEquals(0, childAnimation1.getStartOffset());
89        assertEquals(500, childAnimation2.getStartOffset());
90        assertEquals(1000, childAnimation3.getStartOffset());
91
92        Transformation transformation1 = new Transformation();
93        Transformation transformation2 = new Transformation();
94        Transformation transformation3 = new Transformation();
95
96        // child1 has started animation, child2 and child3 haven't started
97        childAnimation1.getTransformation(startTime + 500, transformation1);
98        childAnimation2.getTransformation(startTime + 500, transformation2);
99        childAnimation3.getTransformation(startTime + 500, transformation3);
100        assertIsRunningAnimation(transformation1.getAlpha());
101        assertEquals(0.0f, transformation2.getAlpha(), DELTA);
102        assertEquals(0.0f, transformation3.getAlpha(), DELTA);
103
104        // child2 has started animation, child1 has finished and child3 hasn't started
105        childAnimation1.getTransformation(startTime + 1000, transformation1);
106        childAnimation2.getTransformation(startTime + 1000, transformation2);
107        childAnimation3.getTransformation(startTime + 1000, transformation3);
108        assertEquals(1.0f, transformation1.getAlpha(), DELTA);
109        assertIsRunningAnimation(transformation2.getAlpha());
110        assertEquals(0.0f, transformation3.getAlpha(), DELTA);
111
112        // child3 has started animation, child1, child2 have finished
113        childAnimation1.getTransformation(startTime + 1500, transformation1);
114        childAnimation2.getTransformation(startTime + 1500, transformation2);
115        childAnimation3.getTransformation(startTime + 1500, transformation3);
116        assertEquals(1.0f, transformation1.getAlpha(), DELTA);
117        assertEquals(1.0f, transformation2.getAlpha(), DELTA);
118        assertIsRunningAnimation(transformation3.getAlpha());
119
120        // Test reverse order
121        mController.setOrder(LayoutAnimationController.ORDER_REVERSE);
122        assertEquals(LayoutAnimationController.ORDER_REVERSE, mController.getOrder());
123        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, mController,
124                DEFAULT_MAX_DURATION);
125
126        transformation1 = new Transformation();
127        transformation2 = new Transformation();
128        transformation3 = new Transformation();
129        childAnimation1 = mListView.getChildAt(INDEX_OF_CHILD1).getAnimation();
130        childAnimation2 = mListView.getChildAt(INDEX_OF_CHILD2).getAnimation();
131        childAnimation3 = mListView.getChildAt(INDEX_OF_CHILD3).getAnimation();
132        startTime = childAnimation1.getStartTime();
133        assertEquals(1000, childAnimation1.getStartOffset());
134        assertEquals(500, childAnimation2.getStartOffset());
135        assertEquals(0, childAnimation3.getStartOffset());
136
137        // child3 has started animation, child1 and child2 haven't started
138        childAnimation1.getTransformation(startTime + 500, transformation1);
139        childAnimation2.getTransformation(startTime + 500, transformation2);
140        childAnimation3.getTransformation(startTime + 500, transformation3);
141        assertEquals(0.0f, transformation1.getAlpha(), DELTA);
142        assertEquals(0.0f, transformation2.getAlpha(), DELTA);
143        assertIsRunningAnimation(transformation3.getAlpha());
144
145        // child2 has started animation, child3 has finished and child1 hasn't started
146        childAnimation1.getTransformation(startTime + 1000, transformation1);
147        childAnimation2.getTransformation(startTime + 1000, transformation2);
148        childAnimation3.getTransformation(startTime + 1000, transformation3);
149        assertEquals(0.0f, transformation1.getAlpha(), DELTA);
150        assertIsRunningAnimation(transformation2.getAlpha());
151        assertEquals(1.0f, transformation3.getAlpha(), DELTA);
152
153        // child1 has started animation, child2 and child3 has finished
154        childAnimation1.getTransformation(startTime + 1500, transformation1);
155        childAnimation2.getTransformation(startTime + 1500, transformation2);
156        childAnimation3.getTransformation(startTime + 1500, transformation3);
157        assertIsRunningAnimation(transformation1.getAlpha());
158        assertEquals(1.0f, transformation2.getAlpha(), DELTA);
159        assertEquals(1.0f, transformation3.getAlpha(), DELTA);
160    }
161
162    public void testAccessDelay() throws InterruptedException {
163        mController.setOrder(LayoutAnimationController.ORDER_NORMAL);
164        float delay = 1.5f;
165        mController.setDelay(delay);
166        assertEquals(delay, mController.getDelay());
167        long maxDuration = (long) (delay * INDEX_OF_CHILD3 * DURATION + DURATION);
168        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, mController,
169                maxDuration);
170
171        Animation childAnimation1 = mListView.getChildAt(INDEX_OF_CHILD1).getAnimation();
172        Animation childAnimation2 = mListView.getChildAt(INDEX_OF_CHILD2).getAnimation();
173        Animation childAnimation3 = mListView.getChildAt(INDEX_OF_CHILD3).getAnimation();
174
175        long startTime = childAnimation1.getStartTime();
176        long offsetTime1 = childAnimation1.getStartOffset();
177        long offsetTime2 = childAnimation2.getStartOffset();
178        long offsetTime3 = childAnimation3.getStartOffset();
179        // child animation delay = child index * delay * animation duration
180        assertEquals(0, offsetTime1);
181        assertEquals(1500, offsetTime2);
182        assertEquals(3000, offsetTime3);
183
184        Transformation transformation1 = new Transformation();
185        Transformation transformation2 = new Transformation();
186        Transformation transformation3 = new Transformation();
187
188        // child1 has started animation, child2 and child3 haven't started
189        childAnimation1.getTransformation(startTime + 500, transformation1);
190        childAnimation2.getTransformation(startTime + 500, transformation2);
191        childAnimation3.getTransformation(startTime + 500, transformation3);
192        assertIsRunningAnimation(transformation1.getAlpha());
193        assertEquals(0.0f, transformation2.getAlpha(), DELTA);
194        assertEquals(0.0f, transformation3.getAlpha(), DELTA);
195
196        // child1 has finished, child2 and child3 haven't started
197        childAnimation1.getTransformation(startTime + 1200, transformation1);
198        childAnimation2.getTransformation(startTime + 1200, transformation2);
199        childAnimation3.getTransformation(startTime + 1200, transformation3);
200        assertEquals(1.0f, transformation1.getAlpha(), DELTA);
201        assertEquals(0.0f, transformation2.getAlpha(), DELTA);
202        assertEquals(0.0f, transformation3.getAlpha(), DELTA);
203
204        // child1 has finished, child2 has started animation, child3 hasn't started.
205        childAnimation1.getTransformation(startTime + 2000, transformation1);
206        childAnimation2.getTransformation(startTime + 2000, transformation2);
207        childAnimation3.getTransformation(startTime + 2000, transformation3);
208        assertEquals(1.0f, transformation1.getAlpha(), DELTA);
209        assertIsRunningAnimation(transformation2.getAlpha());
210        assertEquals(0.0f, transformation3.getAlpha(), DELTA);
211
212        // child1 and child2 have finished, child3 hasn't started
213        childAnimation1.getTransformation(startTime + 2700, transformation1);
214        childAnimation2.getTransformation(startTime + 2700, transformation2);
215        childAnimation3.getTransformation(startTime + 2700, transformation3);
216        assertEquals(1.0f, transformation1.getAlpha(), DELTA);
217        assertEquals(1.0f, transformation2.getAlpha(), DELTA);
218        assertEquals(0.0f, transformation3.getAlpha(), DELTA);
219
220        // child1 and child2 have finished, child3 has started animation
221        childAnimation1.getTransformation(startTime + 3500, transformation1);
222        childAnimation2.getTransformation(startTime + 3500, transformation2);
223        childAnimation3.getTransformation(startTime + 3500, transformation3);
224        assertIsRunningAnimation(transformation3.getAlpha());
225    }
226
227    private void assertIsRunningAnimation(float alpha) {
228        assertTrue(alpha > 0.0f);
229        assertTrue(alpha < 1.0f);
230    }
231
232    public void testAccessAnimation() throws InterruptedException {
233        Animation animation = AnimationUtils.loadAnimation(mActivity, R.anim.decelerate_alpha);
234        animation.setFillAfter(true);
235        // duration defined in decelerate_alpha.xml is 2000
236        long duration = 2000;
237        mController.setAnimation(animation);
238        assertSame(animation, mController.getAnimation());
239        long maxDuration = (long) (DEFAULT_DELAY * INDEX_OF_CHILD3 * duration + duration);
240        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, mController,
241                maxDuration);
242
243        Animation childAnimation1 = mListView.getChildAt(INDEX_OF_CHILD1).getAnimation();
244        Animation childAnimation2 = mListView.getChildAt(INDEX_OF_CHILD2).getAnimation();
245        Animation childAnimation3 = mListView.getChildAt(INDEX_OF_CHILD3).getAnimation();
246        assertAnimation(childAnimation1, false, duration);
247        assertAnimation(childAnimation2, false, duration);
248        assertAnimation(childAnimation3, false, duration);
249
250        mController.setAnimation(mActivity, R.anim.layout_anim_controller_animation);
251        Animation actualAnimation = mController.getAnimation();
252        assertEquals(DURATION, actualAnimation.getDuration());
253        assertTrue(actualAnimation.getInterpolator() instanceof AccelerateInterpolator);
254        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, mController,
255                DEFAULT_MAX_DURATION);
256
257        childAnimation1 = mListView.getChildAt(INDEX_OF_CHILD1).getAnimation();
258        childAnimation2 = mListView.getChildAt(INDEX_OF_CHILD2).getAnimation();
259        childAnimation3 = mListView.getChildAt(INDEX_OF_CHILD3).getAnimation();
260        assertAnimation(childAnimation1, true, DURATION);
261        assertAnimation(childAnimation2, true, DURATION);
262        assertAnimation(childAnimation3, true, DURATION);
263    }
264
265    /**
266     * This method is used for asserting alpha of accelerate and decelerate animations to
267     * make sure their accelerate/decelerate functionalities really work.
268     * @param animation
269     * @param isAccelerate
270     * @param duration
271     */
272    private void assertAnimation(Animation animation, boolean isAccelerate, long duration) {
273        Transformation transformation = new Transformation();
274        long baseTime = animation.getStartTime() + animation.getStartOffset();
275        animation.getTransformation(baseTime, transformation);
276        long step = duration / 4;
277        float alpha1 = transformation.getAlpha();
278        animation.getTransformation(baseTime + step * 1, transformation);
279        float alpha2 = transformation.getAlpha();
280        animation.getTransformation(baseTime + step * 2, transformation);
281        float alpha3 = transformation.getAlpha();
282        animation.getTransformation(baseTime + step * 3, transformation);
283        float alpha4 = transformation.getAlpha();
284        animation.getTransformation(baseTime + step * 4, transformation);
285        float alpha5 = transformation.getAlpha();
286
287        // check decelerating delta alpha
288        float delta1 = alpha2 - alpha1;
289        float delta2 = alpha3 - alpha2;
290        float delta3 = alpha4 - alpha3;
291        float delta4 = alpha5 - alpha4;
292        if (isAccelerate) {
293            assertTrue(delta1 < delta2);
294            assertTrue(delta2 < delta3);
295            assertTrue(delta3 < delta4);
296        } else {
297            assertTrue(delta1 > delta2);
298            assertTrue(delta2 > delta3);
299            assertTrue(delta3 > delta4);
300        }
301    }
302
303    public void testAccessInterpolator() throws InterruptedException {
304        DecelerateInterpolator interpolator = new DecelerateInterpolator(1.0f);
305        mController.setInterpolator(interpolator);
306        assertSame(interpolator, mController.getInterpolator());
307        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, mController,
308                DEFAULT_MAX_DURATION);
309
310        Animation childAnimation1 = mListView.getChildAt(INDEX_OF_CHILD1).getAnimation();
311        Animation childAnimation2 = mListView.getChildAt(INDEX_OF_CHILD2).getAnimation();
312        Animation childAnimation3 = mListView.getChildAt(INDEX_OF_CHILD3).getAnimation();
313
314        long delta1 = childAnimation2.getStartOffset() - childAnimation1.getStartOffset();
315        long delta2 = childAnimation3.getStartOffset() - childAnimation2.getStartOffset();
316        assertTrue(delta2 < delta1);
317
318        mController.setInterpolator(mActivity, android.R.anim.accelerate_interpolator);
319        assertTrue(mController.getInterpolator() instanceof AccelerateInterpolator);
320        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, mController,
321                DEFAULT_MAX_DURATION);
322
323        childAnimation1 = mListView.getChildAt(INDEX_OF_CHILD1).getAnimation();
324        childAnimation2 = mListView.getChildAt(INDEX_OF_CHILD2).getAnimation();
325        childAnimation3 = mListView.getChildAt(INDEX_OF_CHILD3).getAnimation();
326
327        delta1 = childAnimation2.getStartOffset() - childAnimation1.getStartOffset();
328        delta2 = childAnimation3.getStartOffset() - childAnimation2.getStartOffset();
329        assertTrue(delta2 > delta1);
330    }
331
332    public void testConstructor() {
333        XmlResourceParser parser = mActivity.getResources().getAnimation(
334                R.anim.accelerate_decelerate_alpha);
335        AttributeSet attrs = Xml.asAttributeSet(parser);
336        new LayoutAnimationController(mActivity, attrs);
337        new LayoutAnimationController(mDefaultAnimation, DEFAULT_DELAY);
338        LayoutAnimationController controller = new LayoutAnimationController(mDefaultAnimation);
339        assertEquals(DEFAULT_DELAY, controller.getDelay());
340    }
341
342    public void testGetDelayForView() throws Throwable {
343        Animation animation = AnimationUtils.loadAnimation(mActivity, R.anim.decelerate_alpha);
344        animation.setFillAfter(true);
345        MyLayoutAnimationController controller = new MyLayoutAnimationController(animation);
346
347        // child1's animationParams
348        final AbsListView.LayoutParams layoutParams1 = setAnimationParameters(0);
349        // child2's animationParams
350        final AbsListView.LayoutParams layoutParams2 = setAnimationParameters(1);
351        // child3's animationParams
352        final AbsListView.LayoutParams layoutParams3 = setAnimationParameters(2);
353
354        final View child1 = mListView.getChildAt(INDEX_OF_CHILD1);
355        final View child2 = mListView.getChildAt(INDEX_OF_CHILD2);
356        final View child3 = mListView.getChildAt(INDEX_OF_CHILD3);
357        runTestOnUiThread(new Runnable() {
358            public void run() {
359                child1.setLayoutParams(layoutParams1);
360                child2.setLayoutParams(layoutParams2);
361                child3.setLayoutParams(layoutParams3);
362            }
363        });
364
365        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, controller,
366                DEFAULT_MAX_DURATION);
367
368        assertEquals(0, controller.getDelayForView(child1));
369        assertEquals(1000, controller.getDelayForView(child2));
370        assertEquals(2000, controller.getDelayForView(child3));
371    }
372
373    private AbsListView.LayoutParams setAnimationParameters(int index) {
374        AnimationParameters animationParams = new AnimationParameters();
375        animationParams.index = index;
376        animationParams.count = 3;
377        final AbsListView.LayoutParams layoutParams = new AbsListView.LayoutParams(
378                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
379        layoutParams.layoutAnimationParameters = animationParams;
380        return layoutParams;
381    }
382
383    public void testGetTransformedIndex() {
384        Animation animation = AnimationUtils.loadAnimation(mActivity, R.anim.decelerate_alpha);
385        animation.setFillAfter(true);
386        MyLayoutAnimationController controller = new MyLayoutAnimationController(animation);
387        AnimationParameters animationParams = new AnimationParameters();
388        animationParams.count = 3;
389
390        // Test getTransformedIndex in ORDER_NORMAL condition, child1_index == 0, child2_index == 1,
391        // child3_index == 2
392        animationParams.index = 0;
393        assertEquals(0, controller.getTransformedIndex(animationParams));
394        animationParams.index = 1;
395        assertEquals(1, controller.getTransformedIndex(animationParams));
396        animationParams.index = 2;
397        assertEquals(2, controller.getTransformedIndex(animationParams));
398        // Test getTransformedIndex in ORDER_REVERSE condition, child1_index == 2,
399        // child2_index == 1, child3_index == 0
400        controller.setOrder(LayoutAnimationController.ORDER_REVERSE);
401        animationParams.index = 0;
402        assertEquals(2, controller.getTransformedIndex(animationParams));
403        animationParams.index = 1;
404        assertEquals(1, controller.getTransformedIndex(animationParams));
405        animationParams.index = 2;
406        assertEquals(0, controller.getTransformedIndex(animationParams));
407    }
408
409    public void testStart() {
410        Animation animation = new ScaleAnimation(0.0f, 10.0f, 0.0f, 20.0f);
411        animation.setStartTime(500);
412        LayoutAnimationController controller = new LayoutAnimationController(animation);
413
414        assertTrue(Animation.START_ON_FIRST_FRAME != controller.getAnimation().getStartTime());
415
416        controller.start();
417        assertEquals(Animation.START_ON_FIRST_FRAME, controller.getAnimation().getStartTime());
418    }
419
420    public void testIsDone() throws InterruptedException {
421        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, mController,
422                DEFAULT_MAX_DURATION);
423        assertTrue(mController.isDone());
424    }
425
426    public void testGetAnimationForView() throws InterruptedException {
427        Animation animation = AnimationUtils.loadAnimation(mActivity, R.anim.decelerate_alpha);
428        animation.setFillAfter(true);
429        mController.setAnimation(animation);
430        AnimationTestUtils.assertRunController(getInstrumentation(), mListView, mController,
431                DEFAULT_MAX_DURATION);
432        Animation childAnimation1 = mListView.getChildAt(INDEX_OF_CHILD1).getAnimation();
433        Animation childAnimation2 = mListView.getChildAt(INDEX_OF_CHILD2).getAnimation();
434        Animation childAnimation3 = mListView.getChildAt(INDEX_OF_CHILD3).getAnimation();
435        // duration defined in decelerate_alpha.xml is 2000
436        long duration = 2000;
437        assertAnimation(childAnimation1, false, duration);
438        assertAnimation(childAnimation2, false, duration);
439        assertAnimation(childAnimation3, false, duration);
440        assertEquals(0, childAnimation1.getStartOffset());
441        assertEquals(1000, childAnimation2.getStartOffset());
442        assertEquals(2000, childAnimation3.getStartOffset());
443    }
444
445    public void testWillOverlap() {
446        LayoutAnimationController controller = new LayoutAnimationController(mDefaultAnimation);
447
448        controller.setDelay(0.5f);
449        assertTrue(controller.willOverlap());
450
451        controller.setDelay(1.0f);
452        assertFalse(controller.willOverlap());
453
454        controller.setDelay(1.5f);
455        assertFalse(controller.willOverlap());
456    }
457
458    private class MyLayoutAnimationController extends LayoutAnimationController {
459        public MyLayoutAnimationController(Animation animation) {
460            super(animation);
461        }
462
463        protected int getTransformedIndex(AnimationParameters params) {
464            return super.getTransformedIndex(params);
465        }
466
467        protected long getDelayForView(View view) {
468            return super.getDelayForView(view);
469        }
470    }
471}
472