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.AnimatorSetActivity;
20import android.app.Activity;
21import android.test.ActivityInstrumentationTestCase2;
22import android.test.suitebuilder.annotation.SmallTest;
23import android.view.Gravity;
24import android.view.View;
25import android.view.ViewGroup;
26import android.view.ViewTreeObserver;
27
28import com.android.frameworks.coretests.R;
29
30import java.util.concurrent.CountDownLatch;
31import java.util.concurrent.TimeUnit;
32
33
34public class SlideTransitionTest extends ActivityInstrumentationTestCase2<AnimatorSetActivity> {
35
36    Activity mActivity;
37
38    public SlideTransitionTest() {
39        super(AnimatorSetActivity.class);
40    }
41
42    @Override
43    protected void setUp() throws Exception {
44        mActivity = getActivity();
45    }
46
47    @SmallTest
48    public void testShortSlide() throws Throwable {
49        final float slideFraction = 0.5f;
50        final View square1 = mActivity.findViewById(R.id.square1);
51        final View sceneRoot = mActivity.findViewById(R.id.container);
52        final SlideTranslationValueRatchet ratchet = new SlideTranslationValueRatchet(square1);
53        square1.getViewTreeObserver().addOnPreDrawListener(ratchet);
54
55        final Slide slideOut = new Slide(Gravity.BOTTOM);
56        final float finalOffsetOut = sceneRoot.getHeight() * slideFraction;
57        slideOut.setSlideFraction(slideFraction);
58        TransitionLatch latch = setVisibilityInTransition(slideOut, R.id.square1, View.INVISIBLE);
59        assertTrue(latch.startLatch.await(200, TimeUnit.MILLISECONDS));
60        assertEquals(0f, square1.getTranslationY(), 0.1f);
61        assertEquals(View.VISIBLE, square1.getVisibility());
62        Thread.sleep(100);
63        assertFalse(square1.getTranslationY() < 0.1
64                || square1.getTranslationY() > finalOffsetOut - 0.1);
65        assertTrue(latch.endLatch.await(400, TimeUnit.MILLISECONDS));
66        // Give this 20% slop in case some frames get dropped.
67        assertTrue(finalOffsetOut * 0.8 < ratchet.maxY);
68        assertTrue(finalOffsetOut + 0.1 > ratchet.maxY);
69        assertEquals(View.INVISIBLE, square1.getVisibility());
70
71        ratchet.reset();
72        final Slide slideIn = new Slide(Gravity.BOTTOM);
73        final float initialOffsetIn = sceneRoot.getHeight() * slideFraction;
74        slideIn.setSlideFraction(slideFraction);
75        latch = setVisibilityInTransition(slideIn, R.id.square1, View.VISIBLE);
76        assertTrue(latch.startLatch.await(200, TimeUnit.MILLISECONDS));
77        assertEquals(initialOffsetIn, square1.getTranslationY(), 0.1f);
78        assertEquals(View.VISIBLE, square1.getVisibility());
79        Thread.sleep(100);
80        assertFalse(square1.getTranslationY() < 0.1
81                || square1.getTranslationY() > initialOffsetIn - 0.1);
82        assertTrue(latch.endLatch.await(400, TimeUnit.MILLISECONDS));
83        assertEquals(0f, ratchet.minY, 0.1);
84        assertEquals(0f, square1.getTranslationY(), 0.1);
85        assertEquals(View.VISIBLE, square1.getVisibility());
86
87        square1.getViewTreeObserver().removeOnPreDrawListener(ratchet);
88    }
89
90    public TransitionLatch setVisibilityInTransition(final Transition transition, int viewId,
91            final int visibility) throws Throwable {
92        final ViewGroup sceneRoot = (ViewGroup) mActivity.findViewById(R.id.container);
93        final View view = sceneRoot.findViewById(viewId);
94        TransitionLatch latch = new TransitionLatch();
95        transition.addListener(latch);
96        runTestOnUiThread(new Runnable() {
97            @Override
98            public void run() {
99                TransitionManager.beginDelayedTransition(sceneRoot, transition);
100                view.setVisibility(visibility);
101            }
102        });
103        return latch;
104    }
105
106    public static class TransitionLatch implements Transition.TransitionListener {
107        public CountDownLatch startLatch = new CountDownLatch(1);
108        public CountDownLatch endLatch = new CountDownLatch(1);
109        public CountDownLatch cancelLatch = new CountDownLatch(1);
110        public CountDownLatch pauseLatch = new CountDownLatch(1);
111        public CountDownLatch resumeLatch = new CountDownLatch(1);
112
113        @Override
114        public void onTransitionStart(Transition transition) {
115            startLatch.countDown();
116        }
117
118        @Override
119        public void onTransitionEnd(Transition transition) {
120            endLatch.countDown();
121            transition.removeListener(this);
122        }
123
124        @Override
125        public void onTransitionCancel(Transition transition) {
126            cancelLatch.countDown();
127        }
128
129        @Override
130        public void onTransitionPause(Transition transition) {
131            pauseLatch.countDown();
132        }
133
134        @Override
135        public void onTransitionResume(Transition transition) {
136            resumeLatch.countDown();
137        }
138    }
139
140    private static class SlideTranslationValueRatchet
141            implements ViewTreeObserver.OnPreDrawListener {
142
143        private final View mView;
144        private boolean mInitialized;
145        public float minX = Float.NaN;
146        public float minY = Float.NaN;
147        public float maxX = Float.NaN;
148        public float maxY = Float.NaN;
149
150        public SlideTranslationValueRatchet(View view) {
151            mView = view;
152        }
153
154        public void reset() {
155            minX = minY = maxX = maxY = Float.NaN;
156            mInitialized = false;
157        }
158
159        @Override
160        public boolean onPreDraw() {
161            if (!mInitialized) {
162                minX = maxX = mView.getTranslationX();
163                minY = maxY = mView.getTranslationY();
164                mInitialized = true;
165            } else {
166                minX = Math.min(minX, mView.getTranslationX());
167                minY = Math.min(minY, mView.getTranslationY());
168                maxX = Math.max(maxX, mView.getTranslationX());
169                maxY = Math.max(maxY, mView.getTranslationY());
170            }
171            return true;
172        }
173    }
174}
175