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