1/*
2 * Copyright (C) 2016 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.transition;
18
19import android.animation.Animator;
20import android.animation.AnimatorSetActivity;
21import android.app.Activity;
22import android.graphics.Bitmap;
23import android.graphics.drawable.BitmapDrawable;
24import android.test.ActivityInstrumentationTestCase2;
25import android.test.suitebuilder.annotation.SmallTest;
26import android.transition.Transition.TransitionListener;
27import android.view.View;
28import android.view.ViewGroup;
29import android.widget.FrameLayout;
30import android.widget.ImageView;
31
32import com.android.frameworks.coretests.R;
33
34import java.util.concurrent.CountDownLatch;
35import java.util.concurrent.TimeUnit;
36
37public class FadeTransitionTest extends ActivityInstrumentationTestCase2<AnimatorSetActivity> {
38    Activity mActivity;
39    public FadeTransitionTest() {
40        super(AnimatorSetActivity.class);
41    }
42
43    @Override
44    protected void setUp() throws Exception {
45        mActivity = getActivity();
46    }
47
48    @SmallTest
49    public void testFadeOutAndIn() throws Throwable {
50        View square1 = mActivity.findViewById(R.id.square1);
51        Fade fadeOut = new Fade(Fade.MODE_OUT);
52        TransitionLatch latch = setVisibilityInTransition(fadeOut, R.id.square1, View.INVISIBLE);
53        assertTrue(latch.startLatch.await(400, TimeUnit.MILLISECONDS));
54        assertEquals(View.VISIBLE, square1.getVisibility());
55        waitForAnimation();
56        assertFalse(square1.getTransitionAlpha() == 0 || square1.getTransitionAlpha() == 1);
57        assertTrue(latch.endLatch.await(800, TimeUnit.MILLISECONDS));
58        assertEquals(1.0f, square1.getTransitionAlpha());
59        assertEquals(View.INVISIBLE, square1.getVisibility());
60
61        Fade fadeIn = new Fade(Fade.MODE_IN);
62        latch = setVisibilityInTransition(fadeIn, R.id.square1, View.VISIBLE);
63        assertTrue(latch.startLatch.await(400, TimeUnit.MILLISECONDS));
64        assertEquals(View.VISIBLE, square1.getVisibility());
65        waitForAnimation();
66        final float transitionAlpha = square1.getTransitionAlpha();
67        assertTrue("expecting transitionAlpha to be between 0 and 1. Was " + transitionAlpha,
68                transitionAlpha > 0 && transitionAlpha < 1);
69        assertTrue(latch.endLatch.await(800, TimeUnit.MILLISECONDS));
70        assertEquals(1.0f, square1.getTransitionAlpha());
71        assertEquals(View.VISIBLE, square1.getVisibility());
72    }
73
74    @SmallTest
75    public void testFadeOutInterrupt() throws Throwable {
76        View square1 = mActivity.findViewById(R.id.square1);
77        Fade fadeOut = new Fade(Fade.MODE_OUT);
78        FadeValueCheck fadeOutValueCheck = new FadeValueCheck(square1);
79        fadeOut.addListener(fadeOutValueCheck);
80        TransitionLatch outLatch = setVisibilityInTransition(fadeOut, R.id.square1, View.INVISIBLE);
81        assertTrue(outLatch.startLatch.await(400, TimeUnit.MILLISECONDS));
82        waitForAnimation();
83
84        Fade fadeIn = new Fade(Fade.MODE_IN);
85        FadeValueCheck fadeInValueCheck = new FadeValueCheck(square1);
86        fadeIn.addListener(fadeInValueCheck);
87        TransitionLatch inLatch = setVisibilityInTransition(fadeIn, R.id.square1, View.VISIBLE);
88        assertTrue(inLatch.startLatch.await(400, TimeUnit.MILLISECONDS));
89
90        assertEquals(fadeOutValueCheck.pauseTransitionAlpha, fadeInValueCheck.startTransitionAlpha);
91        assertTrue("expecting transitionAlpha to be between 0 and 1. Was " +
92                fadeOutValueCheck.pauseTransitionAlpha,
93                fadeOutValueCheck.pauseTransitionAlpha > 0 &&
94                        fadeOutValueCheck.pauseTransitionAlpha < 1);
95
96        assertTrue(inLatch.endLatch.await(800, TimeUnit.MILLISECONDS));
97        assertEquals(1.0f, square1.getTransitionAlpha());
98        assertEquals(View.VISIBLE, square1.getVisibility());
99    }
100
101    @SmallTest
102    public void testFadeInInterrupt() throws Throwable {
103        final View square1 = mActivity.findViewById(R.id.square1);
104        runTestOnUiThread(new Runnable() {
105            @Override
106            public void run() {
107                square1.setVisibility(View.INVISIBLE);
108            }
109        });
110        Fade fadeIn = new Fade(Fade.MODE_IN);
111        FadeValueCheck fadeInValueCheck = new FadeValueCheck(square1);
112        fadeIn.addListener(fadeInValueCheck);
113        TransitionLatch inLatch = setVisibilityInTransition(fadeIn, R.id.square1, View.VISIBLE);
114        assertTrue(inLatch.startLatch.await(400, TimeUnit.MILLISECONDS));
115        waitForAnimation();
116
117        Fade fadeOut = new Fade(Fade.MODE_OUT);
118        FadeValueCheck fadeOutValueCheck = new FadeValueCheck(square1);
119        fadeOut.addListener(fadeOutValueCheck);
120        TransitionLatch outLatch = setVisibilityInTransition(fadeOut, R.id.square1, View.INVISIBLE);
121        assertTrue(outLatch.startLatch.await(400, TimeUnit.MILLISECONDS));
122
123        assertEquals(fadeInValueCheck.pauseTransitionAlpha, fadeOutValueCheck.startTransitionAlpha);
124        assertTrue("expecting transitionAlpha to be between 0 and 1. Was " +
125                        fadeInValueCheck.pauseTransitionAlpha,
126                fadeInValueCheck.pauseTransitionAlpha > 0 &&
127                        fadeInValueCheck.pauseTransitionAlpha < 1);
128
129        assertTrue(outLatch.endLatch.await(800, TimeUnit.MILLISECONDS));
130        assertEquals(1.0f, square1.getTransitionAlpha());
131        assertEquals(View.INVISIBLE, square1.getVisibility());
132    }
133
134    @SmallTest
135    public void testSnapshotView() throws Throwable {
136        final View square1 = mActivity.findViewById(R.id.square1);
137
138        final CountDownLatch disappearCalled = new CountDownLatch(1);
139        final Fade fadeOut = new Fade(Fade.MODE_OUT) {
140            @Override
141            public Animator onDisappear(ViewGroup sceneRoot, View view,
142                    TransitionValues startValues,
143                    TransitionValues endValues) {
144                assertNotSame(square1, view);
145                assertTrue(view instanceof ImageView);
146                ImageView imageView = (ImageView) view;
147                BitmapDrawable background = (BitmapDrawable) imageView.getDrawable();
148                Bitmap bitmap = background.getBitmap();
149                assertEquals(Bitmap.Config.HARDWARE, bitmap.getConfig());
150                Bitmap copy = bitmap.copy(Bitmap.Config.ARGB_8888, false);
151                assertEquals(0xFFFF0000, copy.getPixel(1, 1));
152                disappearCalled.countDown();
153                return super.onDisappear(sceneRoot, view, startValues, endValues);
154            }
155        };
156
157        runTestOnUiThread(new Runnable() {
158            @Override
159            public void run() {
160                ViewGroup container = mActivity.findViewById(R.id.container);
161                TransitionManager.beginDelayedTransition(container, fadeOut);
162                container.removeView(square1);
163                FrameLayout parent = new FrameLayout(mActivity);
164                parent.addView(square1);
165            }
166        });
167
168        assertTrue(disappearCalled.await(1, TimeUnit.SECONDS));
169    }
170
171    public TransitionLatch setVisibilityInTransition(final Transition transition, int viewId,
172            final int visibility) throws Throwable {
173        final ViewGroup sceneRoot = (ViewGroup) mActivity.findViewById(R.id.container);
174        final View view = sceneRoot.findViewById(viewId);
175        TransitionLatch latch = new TransitionLatch();
176        transition.addListener(latch);
177        runTestOnUiThread(new Runnable() {
178            @Override
179            public void run() {
180                TransitionManager.beginDelayedTransition(sceneRoot, transition);
181                view.setVisibility(visibility);
182            }
183        });
184        return latch;
185    }
186
187    /**
188     * Waits for two animation frames to ensure animation values change.
189     */
190    private void waitForAnimation() throws InterruptedException {
191        final CountDownLatch latch = new CountDownLatch(2);
192        mActivity.getWindow().getDecorView().postOnAnimation(new Runnable() {
193            @Override
194            public void run() {
195                latch.countDown();
196                if (latch.getCount() > 0) {
197                    mActivity.getWindow().getDecorView().postOnAnimation(this);
198                }
199            }
200        });
201        assertTrue(latch.await(1, TimeUnit.SECONDS));
202    }
203
204    public static class TransitionLatch implements TransitionListener {
205        public CountDownLatch startLatch = new CountDownLatch(1);
206        public CountDownLatch endLatch = new CountDownLatch(1);
207        public CountDownLatch cancelLatch = new CountDownLatch(1);
208        public CountDownLatch pauseLatch = new CountDownLatch(1);
209        public CountDownLatch resumeLatch = new CountDownLatch(1);
210
211        @Override
212        public void onTransitionStart(Transition transition) {
213            startLatch.countDown();
214        }
215
216        @Override
217        public void onTransitionEnd(Transition transition) {
218            endLatch.countDown();
219            transition.removeListener(this);
220        }
221
222        @Override
223        public void onTransitionCancel(Transition transition) {
224            cancelLatch.countDown();
225        }
226
227        @Override
228        public void onTransitionPause(Transition transition) {
229            pauseLatch.countDown();
230        }
231
232        @Override
233        public void onTransitionResume(Transition transition) {
234            resumeLatch.countDown();
235        }
236    }
237
238    private static class FadeValueCheck extends TransitionListenerAdapter {
239        public float startTransitionAlpha;
240        public float pauseTransitionAlpha;
241        private final View mView;
242
243        public FadeValueCheck(View view) {
244            mView = view;
245        }
246        @Override
247        public void onTransitionStart(Transition transition) {
248            startTransitionAlpha = mView.getTransitionAlpha();
249        }
250
251        @Override
252        public void onTransitionPause(Transition transition) {
253            pauseTransitionAlpha = mView.getTransitionAlpha();
254        }
255    }
256}
257