1 /*
2  * Copyright (C) 2015 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 package android.transition.cts;
17 
18 import com.android.cts.transition.R;
19 
20 import android.animation.Animator;
21 import android.animation.ObjectAnimator;
22 import android.os.SystemClock;
23 import android.test.ActivityInstrumentationTestCase2;
24 import android.transition.Scene;
25 import android.transition.TransitionManager;
26 import android.transition.TransitionValues;
27 import android.transition.Visibility;
28 import android.view.Choreographer;
29 import android.view.Choreographer.FrameCallback;
30 import android.view.View;
31 import android.view.ViewGroup;
32 import android.widget.FrameLayout;
33 
34 import java.util.ArrayList;
35 
36 public class BaseTransitionTest extends ActivityInstrumentationTestCase2<TransitionActivity> {
37     protected TransitionActivity mActivity;
38     protected FrameLayout mSceneRoot;
39     public float mAnimatedValue;
40     protected ArrayList<View> mTargets = new ArrayList<>();
41     protected TestTransition mTransition;
42 
BaseTransitionTest()43     public BaseTransitionTest() {
44         super(TransitionActivity.class);
45     }
46 
47     @Override
setUp()48     protected void setUp() throws Exception {
49         super.setUp();
50         setActivityInitialTouchMode(false);
51         mActivity = getActivity();
52         mSceneRoot = (FrameLayout) mActivity.findViewById(R.id.container);
53         mTargets.clear();
54         mTransition = new TestTransition();
55     }
56 
waitForStart()57     protected void waitForStart() throws InterruptedException {
58         waitForStart(mTransition.listener);
59     }
60 
waitForStart(SimpleTransitionListener listener)61     protected static void waitForStart(SimpleTransitionListener listener) throws InterruptedException {
62         long endTime = SystemClock.uptimeMillis() + 50;
63         synchronized (listener) {
64             while (!listener.started) {
65                 long now = SystemClock.uptimeMillis();
66                 long waitTime = endTime - now;
67                 if (waitTime <= 0) {
68                     throw new InterruptedException();
69                 }
70                 listener.wait(waitTime);
71             }
72         }
73     }
74 
waitForEnd(long waitMillis)75     protected void waitForEnd(long waitMillis) throws InterruptedException {
76         waitForEnd(mTransition.listener, waitMillis);
77     }
78 
waitForEnd(SimpleTransitionListener listener, long waitMillis)79     protected static void waitForEnd(SimpleTransitionListener listener, long waitMillis)
80             throws InterruptedException {
81         long endTime = SystemClock.uptimeMillis() + waitMillis;
82         synchronized (listener) {
83             while (!listener.ended) {
84                 long now = SystemClock.uptimeMillis();
85                 long waitTime = endTime - now;
86                 if (waitTime <= 0) {
87                     throw new InterruptedException();
88                 }
89                 listener.wait(waitTime);
90             }
91         }
92     }
93 
startTransition(final int layoutId)94     protected void startTransition(final int layoutId) throws Throwable {
95         runTestOnUiThread(new Runnable() {
96             @Override
97             public void run() {
98                 Scene scene = Scene.getSceneForLayout(mSceneRoot, layoutId, mActivity);
99                 TransitionManager.go(scene, mTransition);
100             }
101         });
102         waitForStart();
103     }
104 
endTransition()105     protected void endTransition() throws Throwable {
106         runTestOnUiThread(new Runnable() {
107             @Override
108             public void run() {
109                 TransitionManager.endTransitions(mSceneRoot);
110             }
111         });
112     }
113 
enterScene(final int layoutId)114     protected void enterScene(final int layoutId) throws Throwable {
115         runTestOnUiThread(new Runnable() {
116             @Override
117             public void run() {
118                 Scene scene = Scene.getSceneForLayout(mSceneRoot, layoutId, mActivity);
119                 scene.enter();
120             }
121         });
122         getInstrumentation().waitForIdleSync();
123     }
124 
125     // Waits at least one frame and it could be more. The animated values should have changed
126     // from the previously recorded values by the end of this method.
waitForAnimationFrame()127     protected void waitForAnimationFrame() throws Throwable {
128         final boolean[] tripped = new boolean[] { false };
129         runTestOnUiThread(new Runnable() {
130             @Override
131             public void run() {
132                 Choreographer.getInstance().postFrameCallbackDelayed(new FrameCallback() {
133                     @Override
134                     public void doFrame(long frameTimeNanos) {
135                         synchronized (tripped) {
136                             tripped[0] = true;
137                             tripped.notifyAll();
138                         }
139                     }
140                 }, 16); // make sure it is the next animation frame.
141             }
142         });
143         synchronized (tripped) {
144             long endTime = SystemClock.uptimeMillis() + 60;
145             while (!tripped[0]) {
146                 long waitTime = endTime - SystemClock.uptimeMillis();
147                 if (waitTime <= 0) {
148                     throw new InterruptedException();
149                 }
150                 tripped.wait(waitTime);
151             }
152         }
153     }
154 
155     public class TestTransition extends Visibility {
156         public final SimpleTransitionListener listener = new SimpleTransitionListener();
157 
TestTransition()158         public TestTransition() {
159             addListener(listener);
160             setDuration(100);
161         }
162 
163         @Override
onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues)164         public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
165                 TransitionValues endValues) {
166             mTargets.add(endValues.view);
167             return ObjectAnimator.ofFloat(BaseTransitionTest.this, "mAnimatedValue", 0, 1);
168         }
169 
170         @Override
onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues)171         public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
172                 TransitionValues endValues) {
173             mTargets.add(startValues.view);
174             return ObjectAnimator.ofFloat(BaseTransitionTest.this, "mAnimatedValue", 1, 0);
175         }
176     }
177 }
178