summaryrefslogtreecommitdiff
path: root/android/support/transition/FadeTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'android/support/transition/FadeTest.java')
-rw-r--r--android/support/transition/FadeTest.java275
1 files changed, 275 insertions, 0 deletions
diff --git a/android/support/transition/FadeTest.java b/android/support/transition/FadeTest.java
new file mode 100644
index 00000000..3b171e2c
--- /dev/null
+++ b/android/support/transition/FadeTest.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.transition;
+
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.lessThan;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.junit.Before;
+import org.junit.Test;
+
+@MediumTest
+public class FadeTest extends BaseTest {
+
+ private View mView;
+ private ViewGroup mRoot;
+
+ @UiThreadTest
+ @Before
+ public void setUp() {
+ mRoot = rule.getActivity().getRoot();
+ mView = new View(rule.getActivity());
+ mRoot.addView(mView, new ViewGroup.LayoutParams(100, 100));
+ }
+
+ @Test
+ public void testMode() {
+ assertThat(Fade.IN, is(Visibility.MODE_IN));
+ assertThat(Fade.OUT, is(Visibility.MODE_OUT));
+ final Fade fade = new Fade();
+ assertThat(fade.getMode(), is(Visibility.MODE_IN | Visibility.MODE_OUT));
+ fade.setMode(Visibility.MODE_IN);
+ assertThat(fade.getMode(), is(Visibility.MODE_IN));
+ }
+
+ @Test
+ @UiThreadTest
+ public void testDisappear() {
+ final Fade fade = new Fade();
+ final TransitionValues startValues = new TransitionValues();
+ startValues.view = mView;
+ fade.captureStartValues(startValues);
+ mView.setVisibility(View.INVISIBLE);
+ final TransitionValues endValues = new TransitionValues();
+ endValues.view = mView;
+ fade.captureEndValues(endValues);
+ Animator animator = fade.createAnimator(mRoot, startValues, endValues);
+ assertThat(animator, is(notNullValue()));
+ }
+
+ @Test
+ @UiThreadTest
+ public void testAppear() {
+ mView.setVisibility(View.INVISIBLE);
+ final Fade fade = new Fade();
+ final TransitionValues startValues = new TransitionValues();
+ startValues.view = mView;
+ fade.captureStartValues(startValues);
+ mView.setVisibility(View.VISIBLE);
+ final TransitionValues endValues = new TransitionValues();
+ endValues.view = mView;
+ fade.captureEndValues(endValues);
+ Animator animator = fade.createAnimator(mRoot, startValues, endValues);
+ assertThat(animator, is(notNullValue()));
+ }
+
+ @Test
+ @UiThreadTest
+ public void testNoChange() {
+ final Fade fade = new Fade();
+ final TransitionValues startValues = new TransitionValues();
+ startValues.view = mView;
+ fade.captureStartValues(startValues);
+ final TransitionValues endValues = new TransitionValues();
+ endValues.view = mView;
+ fade.captureEndValues(endValues);
+ Animator animator = fade.createAnimator(mRoot, startValues, endValues);
+ // No visibility change; no animation should happen
+ assertThat(animator, is(nullValue()));
+ }
+
+ @Test
+ public void testFadeOutThenIn() throws Throwable {
+ // Fade out
+ final Runnable interrupt = mock(Runnable.class);
+ float[] valuesOut = new float[2];
+ final InterruptibleFade fadeOut = new InterruptibleFade(Fade.MODE_OUT, interrupt,
+ valuesOut);
+ final Transition.TransitionListener listenerOut = mock(Transition.TransitionListener.class);
+ fadeOut.addListener(listenerOut);
+ changeVisibility(fadeOut, mRoot, mView, View.INVISIBLE);
+ verify(listenerOut, timeout(3000)).onTransitionStart(any(Transition.class));
+
+ // The view is in the middle of fading out
+ verify(interrupt, timeout(3000)).run();
+
+ // Fade in
+ float[] valuesIn = new float[2];
+ final InterruptibleFade fadeIn = new InterruptibleFade(Fade.MODE_IN, null, valuesIn);
+ final Transition.TransitionListener listenerIn = mock(Transition.TransitionListener.class);
+ fadeIn.addListener(listenerIn);
+ changeVisibility(fadeIn, mRoot, mView, View.VISIBLE);
+ verify(listenerOut, timeout(3000)).onTransitionPause(any(Transition.class));
+ verify(listenerIn, timeout(3000)).onTransitionStart(any(Transition.class));
+ assertThat(valuesOut[1], allOf(greaterThan(0f), lessThan(1f)));
+ if (Build.VERSION.SDK_INT >= 19) {
+ // These won't match on API levels 18 and below due to lack of Animator pause.
+ assertEquals(valuesOut[1], valuesIn[0], 0.01f);
+ }
+
+ verify(listenerIn, timeout(3000)).onTransitionEnd(any(Transition.class));
+ assertThat(mView.getVisibility(), is(View.VISIBLE));
+ assertEquals(valuesIn[1], 1.f, 0.01f);
+ }
+
+ @Test
+ public void testFadeInThenOut() throws Throwable {
+ changeVisibility(null, mRoot, mView, View.INVISIBLE);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ // Fade in
+ final Runnable interrupt = mock(Runnable.class);
+ float[] valuesIn = new float[2];
+ final InterruptibleFade fadeIn = new InterruptibleFade(Fade.MODE_IN, interrupt, valuesIn);
+ final Transition.TransitionListener listenerIn = mock(Transition.TransitionListener.class);
+ fadeIn.addListener(listenerIn);
+ changeVisibility(fadeIn, mRoot, mView, View.VISIBLE);
+ verify(listenerIn, timeout(3000)).onTransitionStart(any(Transition.class));
+
+ // The view is in the middle of fading in
+ verify(interrupt, timeout(3000)).run();
+
+ // Fade out
+ float[] valuesOut = new float[2];
+ final InterruptibleFade fadeOut = new InterruptibleFade(Fade.MODE_OUT, null, valuesOut);
+ final Transition.TransitionListener listenerOut = mock(Transition.TransitionListener.class);
+ fadeOut.addListener(listenerOut);
+ changeVisibility(fadeOut, mRoot, mView, View.INVISIBLE);
+ verify(listenerIn, timeout(3000)).onTransitionPause(any(Transition.class));
+ verify(listenerOut, timeout(3000)).onTransitionStart(any(Transition.class));
+ assertThat(valuesIn[1], allOf(greaterThan(0f), lessThan(1f)));
+ if (Build.VERSION.SDK_INT >= 19) {
+ // These won't match on API levels 18 and below due to lack of Animator pause.
+ assertEquals(valuesIn[1], valuesOut[0], 0.01f);
+ }
+
+ verify(listenerOut, timeout(3000)).onTransitionEnd(any(Transition.class));
+ assertThat(mView.getVisibility(), is(View.INVISIBLE));
+ }
+
+ @Test
+ public void testFadeWithAlpha() throws Throwable {
+ // Set the view alpha to 0.5
+ rule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mView.setAlpha(0.5f);
+ }
+ });
+ // Fade out
+ final Fade fadeOut = new Fade(Fade.OUT);
+ final Transition.TransitionListener listenerOut = mock(Transition.TransitionListener.class);
+ fadeOut.addListener(listenerOut);
+ changeVisibility(fadeOut, mRoot, mView, View.INVISIBLE);
+ verify(listenerOut, timeout(3000)).onTransitionStart(any(Transition.class));
+ verify(listenerOut, timeout(3000)).onTransitionEnd(any(Transition.class));
+ // Fade in
+ final Fade fadeIn = new Fade(Fade.IN);
+ final Transition.TransitionListener listenerIn = mock(Transition.TransitionListener.class);
+ fadeIn.addListener(listenerIn);
+ changeVisibility(fadeIn, mRoot, mView, View.VISIBLE);
+ verify(listenerIn, timeout(3000)).onTransitionStart(any(Transition.class));
+ verify(listenerIn, timeout(3000)).onTransitionEnd(any(Transition.class));
+ // Confirm that the view still has the original alpha value
+ assertThat(mView.getVisibility(), is(View.VISIBLE));
+ assertEquals(0.5f, mView.getAlpha(), 0.01f);
+ }
+
+ private void changeVisibility(final Fade fade, final ViewGroup container, final View target,
+ final int visibility) throws Throwable {
+ rule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (fade != null) {
+ TransitionManager.beginDelayedTransition(container, fade);
+ }
+ target.setVisibility(visibility);
+ }
+ });
+ }
+
+ /**
+ * A special version of {@link Fade} that runs a specified {@link Runnable} soon after the
+ * target starts fading in or out.
+ */
+ private static class InterruptibleFade extends Fade {
+
+ static final float ALPHA_THRESHOLD = 0.2f;
+
+ float mInitialAlpha = -1;
+ Runnable mMiddle;
+ final float[] mAlphaValues;
+
+ InterruptibleFade(int mode, Runnable middle, float[] alphaValues) {
+ super(mode);
+ mMiddle = middle;
+ mAlphaValues = alphaValues;
+ }
+
+ @Nullable
+ @Override
+ public Animator createAnimator(@NonNull ViewGroup sceneRoot,
+ @Nullable final TransitionValues startValues,
+ @Nullable final TransitionValues endValues) {
+ final Animator animator = super.createAnimator(sceneRoot, startValues, endValues);
+ if (animator instanceof ObjectAnimator) {
+ ((ObjectAnimator) animator).addUpdateListener(
+ new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final float alpha = (float) animation.getAnimatedValue();
+ mAlphaValues[1] = alpha;
+ if (mInitialAlpha < 0) {
+ mInitialAlpha = alpha;
+ mAlphaValues[0] = mInitialAlpha;
+ } else if (Math.abs(alpha - mInitialAlpha) > ALPHA_THRESHOLD) {
+ if (mMiddle != null) {
+ mMiddle.run();
+ mMiddle = null;
+ }
+ }
+ }
+ });
+ }
+ return animator;
+ }
+
+ }
+
+}