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