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 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 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 84 public void testIsRunning() throws Throwable { 85 setDefaultTransition(); 86 assertFalse(mLayoutTransition.isRunning()); 87 clickButton(); 88 assertTrue(mLayoutTransition.isRunning()); 89 } 90 91 @Test 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 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 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 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 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 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 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 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 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 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; 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 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 241 public void addChild(ViewGroup parent, View child) { 242 super.addChild(parent, child); 243 mAddChild = true; 244 } 245 246 @Override 247 public void hideChild(ViewGroup parent, View child) { 248 super.hideChild(parent, child); 249 mHideChild = true; 250 } 251 252 @Override 253 public boolean isChangingLayout() { 254 return super.isChangingLayout(); 255 } 256 257 @Override 258 public boolean isRunning() { 259 isChangingLayout = true; 260 return super.isRunning(); 261 } 262 263 @Override 264 public void removeChild(ViewGroup parent, View child) { 265 super.removeChild(parent, child); 266 mRemoveChild = true; 267 } 268 269 @Override 270 public void removeTransitionListener(TransitionListener listener) { 271 super.removeTransitionListener(listener); 272 mRemoveListener = true; 273 } 274 275 @Override 276 public void setAnimator(int transitionType, Animator animator) { 277 super.setAnimator(transitionType, animator); 278 mSetAnimator = true; 279 } 280 281 @Override 282 public void showChild(ViewGroup parent, View child) { 283 super.showChild(parent, child); 284 mShowChild = true; 285 } 286 } 287 } 288 289