14e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki/*
24e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki * Copyright (C) 2016 The Android Open Source Project
34e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki *
44e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki * Licensed under the Apache License, Version 2.0 (the "License");
54e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki * you may not use this file except in compliance with the License.
64e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki * You may obtain a copy of the License at
74e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki *
84e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki *      http://www.apache.org/licenses/LICENSE-2.0
94e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki *
104e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki * Unless required by applicable law or agreed to in writing, software
114e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki * distributed under the License is distributed on an "AS IS" BASIS,
124e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki * See the License for the specific language governing permissions and
144e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki * limitations under the License.
154e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki */
164e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
174e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakipackage android.support.transition;
184e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
194e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport static org.hamcrest.core.Is.is;
204e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport static org.hamcrest.core.IsEqual.equalTo;
214e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport static org.junit.Assert.assertNotNull;
224e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport static org.junit.Assert.assertThat;
234e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
244e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport android.animation.Animator;
254e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport android.animation.ObjectAnimator;
264e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport android.support.annotation.NonNull;
274e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport android.support.annotation.Nullable;
284e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport android.support.test.annotation.UiThreadTest;
294e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport android.support.test.filters.MediumTest;
304e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport android.view.View;
314e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport android.view.ViewGroup;
324e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
334e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport org.junit.Before;
344e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport org.junit.Test;
354e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
364e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport java.util.Arrays;
374e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
384e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki@MediumTest
394e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakipublic class VisibilityTest extends BaseTest {
404e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
414e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    private View mView;
424e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    private ViewGroup mRoot;
434e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
444e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    @UiThreadTest
454e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    @Before
464e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    public void setUp() {
474e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        mRoot = rule.getActivity().getRoot();
484e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        mView = new View(rule.getActivity());
494e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        mRoot.addView(mView, new ViewGroup.LayoutParams(100, 100));
504e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    }
514e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
524e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    @Test
53a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    public void testMode() {
54a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        final CustomVisibility visibility = new CustomVisibility();
55a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        assertThat(visibility.getMode(), is(Visibility.MODE_IN | Visibility.MODE_OUT));
56a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        visibility.setMode(Visibility.MODE_IN);
57a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        assertThat(visibility.getMode(), is(Visibility.MODE_IN));
58a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    }
59a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
60a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    @Test
614e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    @UiThreadTest
624e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    public void testCustomVisibility() {
634e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        final CustomVisibility visibility = new CustomVisibility();
644e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        assertThat(visibility.getName(), is(equalTo(CustomVisibility.class.getName())));
654e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        assertNotNull(visibility.getTransitionProperties());
664e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
674e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        // Capture start values
684e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        mView.setScaleX(0.5f);
694e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        final TransitionValues startValues = new TransitionValues();
704e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        startValues.view = mView;
714e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        visibility.captureStartValues(startValues);
724e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        assertThat((float) startValues.values.get(CustomVisibility.PROPNAME_SCALE_X), is(0.5f));
734e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
744e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        // Hide the view and capture end values
754e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        mView.setVisibility(View.GONE);
764e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        final TransitionValues endValues = new TransitionValues();
774e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        endValues.view = mView;
784e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        visibility.captureEndValues(endValues);
794e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
804e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        // This should invoke onDisappear, not onAppear
814e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        ObjectAnimator animator = (ObjectAnimator) visibility
824e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                .createAnimator(mRoot, startValues, endValues);
834e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        assertNotNull(animator);
844e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        assertThat(animator.getPropertyName(), is(equalTo("scaleX")));
854e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
864e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        // Jump to the end of the animation
874e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        animator.end();
884e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
894e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        // This value confirms that onDisappear, not onAppear, was called
904e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        assertThat((float) animator.getAnimatedValue(), is(0.25f));
914e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    }
924e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
93a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    @Test
94a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    @UiThreadTest
95a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    public void testCustomVisibility2() {
96a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        final CustomVisibility2 visibility = new CustomVisibility2();
97a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        final TransitionValues startValues = new TransitionValues();
98a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        startValues.view = mView;
99a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        visibility.captureStartValues(startValues);
100a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        mView.setVisibility(View.GONE);
101a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        final TransitionValues endValues = new TransitionValues();
102a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        endValues.view = mView;
103a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        visibility.captureEndValues(endValues);
104a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        ObjectAnimator animator = (ObjectAnimator) visibility
105a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                .createAnimator(mRoot, startValues, endValues);
106a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        assertNotNull(animator);
107a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
108a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        // Jump to the end of the animation
109a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        animator.end();
110a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
111a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        // This value confirms that onDisappear, not onAppear, was called
112a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        assertThat((float) animator.getAnimatedValue(), is(0.25f));
113a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    }
114a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
115a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    /**
116a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * A custom {@link Visibility} with 5-arg onAppear/Disappear
117a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     */
1184e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    public static class CustomVisibility extends Visibility {
1194e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
1204e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        static final String PROPNAME_SCALE_X = "customVisibility:scaleX";
1214e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
1224e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        private static String[] sTransitionProperties;
1234e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
1244e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        @Nullable
1254e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        @Override
1264e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        public String[] getTransitionProperties() {
1274e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            if (sTransitionProperties == null) {
1284e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                String[] properties = super.getTransitionProperties();
1294e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                if (properties != null) {
1304e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                    sTransitionProperties = Arrays.copyOf(properties, properties.length + 1);
1314e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                } else {
1324e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                    sTransitionProperties = new String[1];
1334e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                }
1344e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                sTransitionProperties[sTransitionProperties.length - 1] = PROPNAME_SCALE_X;
1354e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            }
1364e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            return sTransitionProperties;
1374e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        }
1384e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
1394e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        @Override
1404e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        public void captureStartValues(@NonNull TransitionValues transitionValues) {
1414e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            super.captureStartValues(transitionValues);
1424e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            transitionValues.values.put(PROPNAME_SCALE_X, transitionValues.view.getScaleX());
1434e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        }
1444e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
1454e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        @Override
1464e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues,
1474e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                int startVisibility, TransitionValues endValues, int endVisibility) {
1484e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            if (startValues == null) {
1494e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                return null;
1504e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            }
1514e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            float startScaleX = (float) startValues.values.get(PROPNAME_SCALE_X);
1524e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            return ObjectAnimator.ofFloat(startValues.view, "scaleX", startScaleX, 0.75f);
1534e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        }
1544e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
1554e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        @Override
1564e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues,
1574e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                int startVisibility, TransitionValues endValues, int endVisibility) {
1584e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            if (startValues == null) {
1594e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                return null;
1604e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            }
1614e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            float startScaleX = (float) startValues.values.get(PROPNAME_SCALE_X);
1624e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            return ObjectAnimator.ofFloat(startValues.view, "scaleX", startScaleX, 0.25f);
1634e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        }
1644e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
1654e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    }
1664e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
167a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    /**
168a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * A custom {@link Visibility} with 4-arg onAppear/Disappear
169a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     */
170a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    public static class CustomVisibility2 extends Visibility {
171a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
172a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        static final String PROPNAME_SCALE_X = "customVisibility:scaleX";
173a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
174a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        @Override
175a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        public void captureStartValues(@NonNull TransitionValues transitionValues) {
176a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            super.captureStartValues(transitionValues);
177a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            transitionValues.values.put(PROPNAME_SCALE_X, transitionValues.view.getScaleX());
178a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        }
179a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
180a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        @Override
181a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
182a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                TransitionValues endValues) {
183a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            float startScaleX = startValues == null ? 0.25f :
184a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                    (float) startValues.values.get(PROPNAME_SCALE_X);
185a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            return ObjectAnimator.ofFloat(view, "scaleX", startScaleX, 0.75f);
186a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        }
187a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
188a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        @Override
189a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
190a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                TransitionValues endValues) {
191a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            if (startValues == null) {
192a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                return null;
193a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            }
194a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            float startScaleX = (float) startValues.values.get(PROPNAME_SCALE_X);
195a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            return ObjectAnimator.ofFloat(view, "scaleX", startScaleX, 0.25f);
196a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        }
197a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
198a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    }
199a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
2004e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki}
201