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
17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.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.test.annotation.UiThreadTest;
274e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport android.support.test.filters.MediumTest;
284e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport android.view.View;
294e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport android.view.ViewGroup;
304e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
314d1d6a17310a57807dabb3f404715cfe43a90ed0Aurimas Liutikasimport androidx.annotation.NonNull;
324d1d6a17310a57807dabb3f404715cfe43a90ed0Aurimas Liutikasimport androidx.annotation.Nullable;
334d1d6a17310a57807dabb3f404715cfe43a90ed0Aurimas Liutikas
344e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport org.junit.Before;
354e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport org.junit.Test;
364e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
374e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport java.util.Arrays;
384e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
394e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki@MediumTest
404e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakipublic class VisibilityTest extends BaseTest {
414e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
424e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    private View mView;
434e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    private ViewGroup mRoot;
444e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
454e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    @UiThreadTest
464e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    @Before
474e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    public void setUp() {
484e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        mRoot = rule.getActivity().getRoot();
494e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        mView = new View(rule.getActivity());
504e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        mRoot.addView(mView, new ViewGroup.LayoutParams(100, 100));
514e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    }
524e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
534e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    @Test
54a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    public void testMode() {
55a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        final CustomVisibility visibility = new CustomVisibility();
56a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        assertThat(visibility.getMode(), is(Visibility.MODE_IN | Visibility.MODE_OUT));
57a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        visibility.setMode(Visibility.MODE_IN);
58a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        assertThat(visibility.getMode(), is(Visibility.MODE_IN));
59a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    }
60a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
61a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    @Test
624e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    @UiThreadTest
634e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    public void testCustomVisibility() {
644e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        final CustomVisibility visibility = new CustomVisibility();
654e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        assertThat(visibility.getName(), is(equalTo(CustomVisibility.class.getName())));
664e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        assertNotNull(visibility.getTransitionProperties());
674e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
684e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        // Capture start values
694e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        mView.setScaleX(0.5f);
704e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        final TransitionValues startValues = new TransitionValues();
714e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        startValues.view = mView;
724e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        visibility.captureStartValues(startValues);
734e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        assertThat((float) startValues.values.get(CustomVisibility.PROPNAME_SCALE_X), is(0.5f));
744e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
754e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        // Hide the view and capture end values
764e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        mView.setVisibility(View.GONE);
774e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        final TransitionValues endValues = new TransitionValues();
784e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        endValues.view = mView;
794e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        visibility.captureEndValues(endValues);
804e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
814e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        // This should invoke onDisappear, not onAppear
824e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        ObjectAnimator animator = (ObjectAnimator) visibility
834e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                .createAnimator(mRoot, startValues, endValues);
844e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        assertNotNull(animator);
854e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        assertThat(animator.getPropertyName(), is(equalTo("scaleX")));
864e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
874e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        // Jump to the end of the animation
884e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        animator.end();
894e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
904e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        // This value confirms that onDisappear, not onAppear, was called
914e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        assertThat((float) animator.getAnimatedValue(), is(0.25f));
924e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    }
934e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
94a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    @Test
95a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    @UiThreadTest
96a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    public void testCustomVisibility2() {
97a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        final CustomVisibility2 visibility = new CustomVisibility2();
98a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        final TransitionValues startValues = new TransitionValues();
99a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        startValues.view = mView;
100a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        visibility.captureStartValues(startValues);
101a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        mView.setVisibility(View.GONE);
102a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        final TransitionValues endValues = new TransitionValues();
103a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        endValues.view = mView;
104a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        visibility.captureEndValues(endValues);
105a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        ObjectAnimator animator = (ObjectAnimator) visibility
106a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                .createAnimator(mRoot, startValues, endValues);
107a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        assertNotNull(animator);
108a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
109a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        // Jump to the end of the animation
110a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        animator.end();
111a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
112a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        // This value confirms that onDisappear, not onAppear, was called
113a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        assertThat((float) animator.getAnimatedValue(), is(0.25f));
114a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    }
115a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
116a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    /**
117a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * A custom {@link Visibility} with 5-arg onAppear/Disappear
118a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     */
1194e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    public static class CustomVisibility extends Visibility {
1204e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
1214e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        static final String PROPNAME_SCALE_X = "customVisibility:scaleX";
1224e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
1234e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        private static String[] sTransitionProperties;
1244e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
1254e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        @Nullable
1264e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        @Override
1274e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        public String[] getTransitionProperties() {
1284e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            if (sTransitionProperties == null) {
1294e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                String[] properties = super.getTransitionProperties();
1304e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                if (properties != null) {
1314e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                    sTransitionProperties = Arrays.copyOf(properties, properties.length + 1);
1324e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                } else {
1334e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                    sTransitionProperties = new String[1];
1344e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                }
1354e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                sTransitionProperties[sTransitionProperties.length - 1] = PROPNAME_SCALE_X;
1364e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            }
1374e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            return sTransitionProperties;
1384e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        }
1394e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
1404e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        @Override
1414e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        public void captureStartValues(@NonNull TransitionValues transitionValues) {
1424e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            super.captureStartValues(transitionValues);
1434e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            transitionValues.values.put(PROPNAME_SCALE_X, transitionValues.view.getScaleX());
1444e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        }
1454e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
1464e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        @Override
1474e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues,
1484e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                int startVisibility, TransitionValues endValues, int endVisibility) {
1494e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            if (startValues == null) {
1504e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                return null;
1514e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            }
1524e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            float startScaleX = (float) startValues.values.get(PROPNAME_SCALE_X);
1534e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            return ObjectAnimator.ofFloat(startValues.view, "scaleX", startScaleX, 0.75f);
1544e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        }
1554e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
1564e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        @Override
1574e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues,
1584e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                int startVisibility, TransitionValues endValues, int endVisibility) {
1594e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            if (startValues == null) {
1604e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                return null;
1614e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            }
1624e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            float startScaleX = (float) startValues.values.get(PROPNAME_SCALE_X);
1634e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            return ObjectAnimator.ofFloat(startValues.view, "scaleX", startScaleX, 0.25f);
1644e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        }
1654e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
1664e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    }
1674e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
168a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    /**
169a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * A custom {@link Visibility} with 4-arg onAppear/Disappear
170a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     */
171a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    public static class CustomVisibility2 extends Visibility {
172a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
173a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        static final String PROPNAME_SCALE_X = "customVisibility:scaleX";
174a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
175a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        @Override
176a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        public void captureStartValues(@NonNull TransitionValues transitionValues) {
177a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            super.captureStartValues(transitionValues);
178a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            transitionValues.values.put(PROPNAME_SCALE_X, transitionValues.view.getScaleX());
179a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        }
180a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
181a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        @Override
182a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
183a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                TransitionValues endValues) {
184a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            float startScaleX = startValues == null ? 0.25f :
185a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                    (float) startValues.values.get(PROPNAME_SCALE_X);
186a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            return ObjectAnimator.ofFloat(view, "scaleX", startScaleX, 0.75f);
187a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        }
188a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
189a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        @Override
190a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
191a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                TransitionValues endValues) {
192a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            if (startValues == null) {
193a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                return null;
194a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            }
195a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            float startScaleX = (float) startValues.values.get(PROPNAME_SCALE_X);
196a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            return ObjectAnimator.ofFloat(view, "scaleX", startScaleX, 0.25f);
197a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        }
198a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
199a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    }
200a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
2014e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki}
202