diff options
| -rw-r--r-- | core/java/android/transition/Slide.java | 50 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/transition/SlideTransitionTest.java | 174 |
2 files changed, 202 insertions, 22 deletions
diff --git a/core/java/android/transition/Slide.java b/core/java/android/transition/Slide.java index 9af65e403679..2645f861a5ad 100644 --- a/core/java/android/transition/Slide.java +++ b/core/java/android/transition/Slide.java @@ -47,6 +47,7 @@ public class Slide extends Visibility { private static final String PROPNAME_SCREEN_POSITION = "android:slide:screenPosition"; private CalculateSlide mSlideCalculator = sCalculateBottom; private @GravityFlag int mSlideEdge = Gravity.BOTTOM; + private float mSlideFraction = 1; /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -56,16 +57,16 @@ public class Slide extends Visibility { private interface CalculateSlide { /** Returns the translation value for view when it goes out of the scene */ - float getGoneX(ViewGroup sceneRoot, View view); + float getGoneX(ViewGroup sceneRoot, View view, float fraction); /** Returns the translation value for view when it goes out of the scene */ - float getGoneY(ViewGroup sceneRoot, View view); + float getGoneY(ViewGroup sceneRoot, View view, float fraction); } private static abstract class CalculateSlideHorizontal implements CalculateSlide { @Override - public float getGoneY(ViewGroup sceneRoot, View view) { + public float getGoneY(ViewGroup sceneRoot, View view, float fraction) { return view.getTranslationY(); } } @@ -73,27 +74,27 @@ public class Slide extends Visibility { private static abstract class CalculateSlideVertical implements CalculateSlide { @Override - public float getGoneX(ViewGroup sceneRoot, View view) { + public float getGoneX(ViewGroup sceneRoot, View view, float fraction) { return view.getTranslationX(); } } private static final CalculateSlide sCalculateLeft = new CalculateSlideHorizontal() { @Override - public float getGoneX(ViewGroup sceneRoot, View view) { - return view.getTranslationX() - sceneRoot.getWidth(); + public float getGoneX(ViewGroup sceneRoot, View view, float fraction) { + return view.getTranslationX() - sceneRoot.getWidth() * fraction; } }; private static final CalculateSlide sCalculateStart = new CalculateSlideHorizontal() { @Override - public float getGoneX(ViewGroup sceneRoot, View view) { + public float getGoneX(ViewGroup sceneRoot, View view, float fraction) { final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; final float x; if (isRtl) { - x = view.getTranslationX() + sceneRoot.getWidth(); + x = view.getTranslationX() + sceneRoot.getWidth() * fraction; } else { - x = view.getTranslationX() - sceneRoot.getWidth(); + x = view.getTranslationX() - sceneRoot.getWidth() * fraction; } return x; } @@ -101,27 +102,27 @@ public class Slide extends Visibility { private static final CalculateSlide sCalculateTop = new CalculateSlideVertical() { @Override - public float getGoneY(ViewGroup sceneRoot, View view) { - return view.getTranslationY() - sceneRoot.getHeight(); + public float getGoneY(ViewGroup sceneRoot, View view, float fraction) { + return view.getTranslationY() - sceneRoot.getHeight() * fraction; } }; private static final CalculateSlide sCalculateRight = new CalculateSlideHorizontal() { @Override - public float getGoneX(ViewGroup sceneRoot, View view) { - return view.getTranslationX() + sceneRoot.getWidth(); + public float getGoneX(ViewGroup sceneRoot, View view, float fraction) { + return view.getTranslationX() + sceneRoot.getWidth() * fraction; } }; private static final CalculateSlide sCalculateEnd = new CalculateSlideHorizontal() { @Override - public float getGoneX(ViewGroup sceneRoot, View view) { + public float getGoneX(ViewGroup sceneRoot, View view, float fraction) { final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; final float x; if (isRtl) { - x = view.getTranslationX() - sceneRoot.getWidth(); + x = view.getTranslationX() - sceneRoot.getWidth() * fraction; } else { - x = view.getTranslationX() + sceneRoot.getWidth(); + x = view.getTranslationX() + sceneRoot.getWidth() * fraction; } return x; } @@ -129,8 +130,8 @@ public class Slide extends Visibility { private static final CalculateSlide sCalculateBottom = new CalculateSlideVertical() { @Override - public float getGoneY(ViewGroup sceneRoot, View view) { - return view.getTranslationY() + sceneRoot.getHeight(); + public float getGoneY(ViewGroup sceneRoot, View view, float fraction) { + return view.getTranslationY() + sceneRoot.getHeight() * fraction; } }; @@ -237,8 +238,8 @@ public class Slide extends Visibility { int[] position = (int[]) endValues.values.get(PROPNAME_SCREEN_POSITION); float endX = view.getTranslationX(); float endY = view.getTranslationY(); - float startX = mSlideCalculator.getGoneX(sceneRoot, view); - float startY = mSlideCalculator.getGoneY(sceneRoot, view); + float startX = mSlideCalculator.getGoneX(sceneRoot, view, mSlideFraction); + float startY = mSlideCalculator.getGoneY(sceneRoot, view, mSlideFraction); return TranslationAnimationCreator .createAnimation(view, endValues, position[0], position[1], startX, startY, endX, endY, sDecelerate, this); @@ -253,10 +254,15 @@ public class Slide extends Visibility { int[] position = (int[]) startValues.values.get(PROPNAME_SCREEN_POSITION); float startX = view.getTranslationX(); float startY = view.getTranslationY(); - float endX = mSlideCalculator.getGoneX(sceneRoot, view); - float endY = mSlideCalculator.getGoneY(sceneRoot, view); + float endX = mSlideCalculator.getGoneX(sceneRoot, view, mSlideFraction); + float endY = mSlideCalculator.getGoneY(sceneRoot, view, mSlideFraction); return TranslationAnimationCreator .createAnimation(view, startValues, position[0], position[1], startX, startY, endX, endY, sAccelerate, this); } + + /** @hide */ + public void setSlideFraction(float slideFraction) { + mSlideFraction = slideFraction; + } } diff --git a/core/tests/coretests/src/android/transition/SlideTransitionTest.java b/core/tests/coretests/src/android/transition/SlideTransitionTest.java new file mode 100644 index 000000000000..8b9ec74be8df --- /dev/null +++ b/core/tests/coretests/src/android/transition/SlideTransitionTest.java @@ -0,0 +1,174 @@ +/* + * 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.transition; + +import android.animation.AnimatorSetActivity; +import android.app.Activity; +import android.test.ActivityInstrumentationTestCase2; +import android.test.suitebuilder.annotation.SmallTest; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; + +import com.android.frameworks.coretests.R; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + + +public class SlideTransitionTest extends ActivityInstrumentationTestCase2<AnimatorSetActivity> { + + Activity mActivity; + + public SlideTransitionTest() { + super(AnimatorSetActivity.class); + } + + @Override + protected void setUp() throws Exception { + mActivity = getActivity(); + } + + @SmallTest + public void testShortSlide() throws Throwable { + final float slideFraction = 0.5f; + final View square1 = mActivity.findViewById(R.id.square1); + final View sceneRoot = mActivity.findViewById(R.id.container); + final SlideTranslationValueRatchet ratchet = new SlideTranslationValueRatchet(square1); + square1.getViewTreeObserver().addOnPreDrawListener(ratchet); + + final Slide slideOut = new Slide(Gravity.BOTTOM); + final float finalOffsetOut = sceneRoot.getHeight() * slideFraction; + slideOut.setSlideFraction(slideFraction); + TransitionLatch latch = setVisibilityInTransition(slideOut, R.id.square1, View.INVISIBLE); + assertTrue(latch.startLatch.await(200, TimeUnit.MILLISECONDS)); + assertEquals(0f, square1.getTranslationY(), 0.1f); + assertEquals(View.VISIBLE, square1.getVisibility()); + Thread.sleep(100); + assertFalse(square1.getTranslationY() < 0.1 + || square1.getTranslationY() > finalOffsetOut - 0.1); + assertTrue(latch.endLatch.await(400, TimeUnit.MILLISECONDS)); + // Give this 20% slop in case some frames get dropped. + assertTrue(finalOffsetOut * 0.8 < ratchet.maxY); + assertTrue(finalOffsetOut + 0.1 > ratchet.maxY); + assertEquals(View.INVISIBLE, square1.getVisibility()); + + ratchet.reset(); + final Slide slideIn = new Slide(Gravity.BOTTOM); + final float initialOffsetIn = sceneRoot.getHeight() * slideFraction; + slideIn.setSlideFraction(slideFraction); + latch = setVisibilityInTransition(slideIn, R.id.square1, View.VISIBLE); + assertTrue(latch.startLatch.await(200, TimeUnit.MILLISECONDS)); + assertEquals(initialOffsetIn, square1.getTranslationY(), 0.1f); + assertEquals(View.VISIBLE, square1.getVisibility()); + Thread.sleep(100); + assertFalse(square1.getTranslationY() < 0.1 + || square1.getTranslationY() > initialOffsetIn - 0.1); + assertTrue(latch.endLatch.await(400, TimeUnit.MILLISECONDS)); + assertEquals(0f, ratchet.minY, 0.1); + assertEquals(0f, square1.getTranslationY(), 0.1); + assertEquals(View.VISIBLE, square1.getVisibility()); + + square1.getViewTreeObserver().removeOnPreDrawListener(ratchet); + } + + public TransitionLatch setVisibilityInTransition(final Transition transition, int viewId, + final int visibility) throws Throwable { + final ViewGroup sceneRoot = (ViewGroup) mActivity.findViewById(R.id.container); + final View view = sceneRoot.findViewById(viewId); + TransitionLatch latch = new TransitionLatch(); + transition.addListener(latch); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + TransitionManager.beginDelayedTransition(sceneRoot, transition); + view.setVisibility(visibility); + } + }); + return latch; + } + + public static class TransitionLatch implements Transition.TransitionListener { + public CountDownLatch startLatch = new CountDownLatch(1); + public CountDownLatch endLatch = new CountDownLatch(1); + public CountDownLatch cancelLatch = new CountDownLatch(1); + public CountDownLatch pauseLatch = new CountDownLatch(1); + public CountDownLatch resumeLatch = new CountDownLatch(1); + + @Override + public void onTransitionStart(Transition transition) { + startLatch.countDown(); + } + + @Override + public void onTransitionEnd(Transition transition) { + endLatch.countDown(); + transition.removeListener(this); + } + + @Override + public void onTransitionCancel(Transition transition) { + cancelLatch.countDown(); + } + + @Override + public void onTransitionPause(Transition transition) { + pauseLatch.countDown(); + } + + @Override + public void onTransitionResume(Transition transition) { + resumeLatch.countDown(); + } + } + + private static class SlideTranslationValueRatchet + implements ViewTreeObserver.OnPreDrawListener { + + private final View mView; + private boolean mInitialized; + public float minX = Float.NaN; + public float minY = Float.NaN; + public float maxX = Float.NaN; + public float maxY = Float.NaN; + + public SlideTranslationValueRatchet(View view) { + mView = view; + } + + public void reset() { + minX = minY = maxX = maxY = Float.NaN; + mInitialized = false; + } + + @Override + public boolean onPreDraw() { + if (!mInitialized) { + minX = maxX = mView.getTranslationX(); + minY = maxY = mView.getTranslationY(); + mInitialized = true; + } else { + minX = Math.min(minX, mView.getTranslationX()); + minY = Math.min(minY, mView.getTranslationY()); + maxX = Math.max(maxX, mView.getTranslationX()); + maxY = Math.max(maxY, mView.getTranslationY()); + } + return true; + } + } +} |