1 /*
2  * Copyright (C) 2012 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.animation.cts;
17 
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertFalse;
20 import static org.junit.Assert.assertNull;
21 import static org.junit.Assert.assertTrue;
22 
23 import android.animation.Animator;
24 import android.animation.LayoutTransition;
25 import android.animation.LayoutTransition.TransitionListener;
26 import android.animation.ObjectAnimator;
27 import android.animation.PropertyValuesHolder;
28 import android.animation.TimeInterpolator;
29 import android.os.SystemClock;
30 import android.view.View;
31 import android.view.ViewGroup;
32 import android.view.animation.AccelerateInterpolator;
33 import android.widget.Button;
34 import android.widget.LinearLayout;
35 
36 import androidx.test.InstrumentationRegistry;
37 import androidx.test.filters.MediumTest;
38 import androidx.test.rule.ActivityTestRule;
39 import androidx.test.runner.AndroidJUnit4;
40 
41 import org.junit.Before;
42 import org.junit.Rule;
43 import org.junit.Test;
44 import org.junit.runner.RunWith;
45 
46 import java.util.Iterator;
47 import java.util.LinkedList;
48 import java.util.List;
49 
50 @MediumTest
51 @RunWith(AndroidJUnit4.class)
52 public class LayoutAnimationTest {
53     private LayoutAnimationActivity mActivity;
54     private LayoutTransition mLayoutTransition;
55     private LinearLayout mView;
56     private Button mButton;
57 
58     @Rule
59     public ActivityTestRule<LayoutAnimationActivity> mActivityRule =
60             new ActivityTestRule<>(LayoutAnimationActivity.class);
61 
62     @Before
setup()63     public void setup() {
64         InstrumentationRegistry.getInstrumentation().setInTouchMode(true);
65         mActivity = mActivityRule.getActivity();
66         mView = (LinearLayout) mActivity.findViewById(R.id.container);
67         mButton = (Button)mActivity.findViewById(R.id.button1);
68         mLayoutTransition = new LayoutTransition();
69     }
70 
71     @Test
testAddTransitionListener()72     public void testAddTransitionListener() throws Throwable {
73         MyTransitionListener listener = new MyTransitionListener();
74         assertNull(mLayoutTransition.getTransitionListeners());
75         mLayoutTransition.addTransitionListener(listener);
76 
77         List<TransitionListener> layoutTransitionList = mLayoutTransition.getTransitionListeners();
78         TransitionListener actualListener = layoutTransitionList.get(0);
79         assertEquals(1, layoutTransitionList.size());
80         assertEquals(listener, actualListener);
81     }
82 
83     @Test
testIsRunning()84     public void testIsRunning() throws Throwable {
85         setDefaultTransition();
86         assertFalse(mLayoutTransition.isRunning());
87         clickButton();
88         assertTrue(mLayoutTransition.isRunning());
89     }
90 
91     @Test
testIsChangingLayout()92     public void testIsChangingLayout() throws Throwable {
93         long duration = 2000l;
94         mView.setLayoutTransition(mLayoutTransition);
95         mLayoutTransition.setDuration(duration);
96         mLayoutTransition.setInterpolator(LayoutTransition.CHANGE_APPEARING,
97                 new AccelerateInterpolator());
98 
99         assertFalse(mLayoutTransition.isChangingLayout());
100         clickButton();
101         assertTrue(mLayoutTransition.isChangingLayout());
102     }
103 
104     @Test
testSetDuration()105     public void testSetDuration() {
106         long duration = 1000l;
107         mLayoutTransition.setDuration(duration);
108 
109         assertEquals(duration, mLayoutTransition.getDuration(LayoutTransition.APPEARING));
110         assertEquals(duration, mLayoutTransition.getDuration(LayoutTransition.CHANGE_APPEARING));
111         assertEquals(duration,
112                      mLayoutTransition.getDuration(LayoutTransition.CHANGE_DISAPPEARING));
113         assertEquals(duration, mLayoutTransition.getDuration(LayoutTransition.DISAPPEARING));
114     }
115 
116     @Test
testSetDurationForTransitionType()117     public void testSetDurationForTransitionType() {
118         long duration = 1000l;
119         mLayoutTransition.setDuration(LayoutTransition.APPEARING, duration);
120         assertEquals(duration, mLayoutTransition.getDuration(LayoutTransition.APPEARING));
121     }
122 
123     @Test
testSetInterpolator()124     public void testSetInterpolator() {
125         TimeInterpolator interpolator = new AccelerateInterpolator();
126         mLayoutTransition.setInterpolator(LayoutTransition.APPEARING, interpolator);
127         assertEquals(interpolator, mLayoutTransition.getInterpolator(
128                 LayoutTransition.APPEARING));
129     }
130 
131     @Test
testSetAnimator()132     public void testSetAnimator() {
133         float startAlpha = 0.0f;
134         float endAlpha = 0.5f;
135         PropertyValuesHolder pvhAlpha = PropertyValuesHolder.ofFloat("alpha", startAlpha,
136                 endAlpha);
137         ObjectAnimator appearingAnimator = ObjectAnimator.ofPropertyValuesHolder(
138                 (Object) null, pvhAlpha);
139         appearingAnimator.setInterpolator(new AccelerateInterpolator());
140         mLayoutTransition.setAnimator(LayoutTransition.APPEARING, appearingAnimator);
141         assertEquals(appearingAnimator, mLayoutTransition.getAnimator(LayoutTransition.APPEARING));
142     }
143 
144     @Test
testAnimationWithAnimator()145     public void testAnimationWithAnimator() throws Throwable {
146         MyTransitionListener listener = new MyTransitionListener();
147         mLayoutTransition.addTransitionListener(listener);
148         mLayoutTransition.setAnimateParentHierarchy(false);
149         long duration = 2000;
150         mView.setLayoutTransition(mLayoutTransition);
151         mLayoutTransition.setDuration(duration);
152         float startAlpha = 0.0f;
153         float endAlpha = 0.5f;
154         PropertyValuesHolder pvhAlpha = PropertyValuesHolder.ofFloat("alpha", startAlpha,
155                 endAlpha);
156         ObjectAnimator appearingAnimator = ObjectAnimator.ofPropertyValuesHolder(
157                 (Object) null, pvhAlpha);
158         appearingAnimator.setInterpolator(new AccelerateInterpolator());
159 
160         mLayoutTransition.setAnimator(LayoutTransition.APPEARING, appearingAnimator);
161 
162         List<Float> alphaList = new LinkedList<>();
163         clickButton();
164         while (listener.mTransition) {
165             float alpha = mActivity.getLastButton().getAlpha();
166             alphaList.add(alpha);
167             SystemClock.sleep(200);
168         }
169         Iterator<Float> iterator = alphaList.iterator();
170         float lastValue = 0.0f;
171         while(iterator.hasNext()){
172             float alphaValue = iterator.next();
173             assertTrue(alphaValue >= lastValue);
174             assertTrue(alphaValue >= startAlpha);
175             assertTrue(alphaValue <= endAlpha);
176             lastValue = alphaValue;
177         }
178     }
179 
180     @Test
testStartDelay()181     public void testStartDelay() {
182         long delay = 100l;
183         int transitionType = LayoutTransition.APPEARING;
184         mLayoutTransition.setStartDelay(transitionType, delay);
185         assertEquals(delay, mLayoutTransition.getStartDelay(transitionType));
186     }
187 
188     @Test
testSetStagger()189     public void testSetStagger() {
190         long duration = 100;
191         int transitionType = LayoutTransition.CHANGE_APPEARING;
192         mLayoutTransition.setStagger(transitionType, duration);
193         assertEquals(duration, mLayoutTransition.getStagger(transitionType));
194     }
195 
setDefaultTransition()196     private void setDefaultTransition() {
197         long duration = 1000;
198         mView.setLayoutTransition(mLayoutTransition);
199         mLayoutTransition.setDuration(duration);
200         mLayoutTransition.setInterpolator(LayoutTransition.APPEARING,
201                 new AccelerateInterpolator());
202     }
203 
clickButton()204     private void clickButton() throws Throwable {
205         mActivityRule.runOnUiThread(mButton::callOnClick);
206         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
207     }
208 
209     class MyTransitionListener implements LayoutTransition.TransitionListener {
210         ViewGroup mContainer;
211         View mView;
212         int mTransitionType;
213         boolean mTransition = false;
endTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType)214         public void endTransition(LayoutTransition transition,
215                 ViewGroup container, View view, int transitionType) {
216             this.mContainer = container;
217             this.mView = view;
218             this.mTransitionType = transitionType;
219             mTransition = false;
220         }
221 
startTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType)222         public void startTransition(LayoutTransition transition,
223                 ViewGroup container, View view, int transitionType) {
224             this.mContainer = container;
225             this.mView = view;
226             this.mTransitionType = transitionType;
227             mTransition = true;
228         }
229     }
230 
231     class MyLayoutTransition extends LayoutTransition {
232         boolean mAddChild = false;
233         boolean mHideChild = false;
234         boolean mRemoveChild = false;
235         boolean mShowChild = false;
236         boolean mSetAnimator = false;
237         boolean mRemoveListener = false;
238         boolean isChangingLayout = false;
239 
240         @Override
addChild(ViewGroup parent, View child)241         public void addChild(ViewGroup parent, View child) {
242             super.addChild(parent, child);
243             mAddChild = true;
244         }
245 
246         @Override
hideChild(ViewGroup parent, View child)247         public void hideChild(ViewGroup parent, View child) {
248             super.hideChild(parent, child);
249             mHideChild = true;
250         }
251 
252         @Override
isChangingLayout()253         public boolean isChangingLayout() {
254             return super.isChangingLayout();
255         }
256 
257         @Override
isRunning()258         public boolean isRunning() {
259             isChangingLayout =  true;
260             return super.isRunning();
261         }
262 
263         @Override
removeChild(ViewGroup parent, View child)264         public void removeChild(ViewGroup parent, View child) {
265             super.removeChild(parent, child);
266             mRemoveChild = true;
267         }
268 
269         @Override
removeTransitionListener(TransitionListener listener)270         public void removeTransitionListener(TransitionListener listener) {
271             super.removeTransitionListener(listener);
272             mRemoveListener = true;
273         }
274 
275         @Override
setAnimator(int transitionType, Animator animator)276         public void setAnimator(int transitionType, Animator animator) {
277             super.setAnimator(transitionType, animator);
278             mSetAnimator = true;
279         }
280 
281         @Override
showChild(ViewGroup parent, View child)282         public void showChild(ViewGroup parent, View child) {
283             super.showChild(parent, child);
284             mShowChild = true;
285         }
286     }
287 }
288 
289