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