diff options
| -rw-r--r-- | core/java/android/view/animation/TranslateAnimation.java | 58 | ||||
| -rw-r--r-- | services/core/java/com/android/server/wm/WindowAnimationSpec.java | 59 |
2 files changed, 104 insertions, 13 deletions
diff --git a/core/java/android/view/animation/TranslateAnimation.java b/core/java/android/view/animation/TranslateAnimation.java index ec55a0273999..3365c70b5b34 100644 --- a/core/java/android/view/animation/TranslateAnimation.java +++ b/core/java/android/view/animation/TranslateAnimation.java @@ -57,6 +57,9 @@ public class TranslateAnimation extends Animation { /** @hide */ protected float mToYDelta; + private int mWidth; + private int mParentWidth; + /** * Constructor used when a TranslateAnimation is loaded from a resource. * @@ -179,5 +182,60 @@ public class TranslateAnimation extends Animation { mToXDelta = resolveSize(mToXType, mToXValue, width, parentWidth); mFromYDelta = resolveSize(mFromYType, mFromYValue, height, parentHeight); mToYDelta = resolveSize(mToYType, mToYValue, height, parentHeight); + + mWidth = width; + mParentWidth = parentWidth; + } + + /** + * Checks whether or not the translation is exclusively an x axis translation. + * + * @hide + */ + public boolean isXAxisTransition() { + return mFromXDelta - mToXDelta != 0 && mFromYDelta - mToYDelta == 0; + } + + /** + * Checks whether or not the translation is a full width x axis slide in or out translation. + * + * @hide + */ + public boolean isFullWidthTranslate() { + boolean isXAxisSlideTransition = + isSlideInLeft() || isSlideOutRight() || isSlideInRight() || isSlideOutLeft(); + return mWidth == mParentWidth && isXAxisSlideTransition; + } + + private boolean isSlideInLeft() { + boolean startsOutOfParentOnLeft = mFromXDelta <= -mWidth; + return startsOutOfParentOnLeft && endsXEnclosedWithinParent(); + } + + private boolean isSlideOutRight() { + boolean endOutOfParentOnRight = mToXDelta >= mParentWidth; + return startsXEnclosedWithinParent() && endOutOfParentOnRight; + } + + private boolean isSlideInRight() { + boolean startsOutOfParentOnRight = mFromXDelta >= mParentWidth; + return startsOutOfParentOnRight && endsXEnclosedWithinParent(); + } + + private boolean isSlideOutLeft() { + boolean endOutOfParentOnLeft = mToXDelta <= -mWidth; + return startsXEnclosedWithinParent() && endOutOfParentOnLeft; + } + + private boolean endsXEnclosedWithinParent() { + return mWidth <= mParentWidth + && mToXDelta + mWidth <= mParentWidth + && mToXDelta >= 0; + } + + private boolean startsXEnclosedWithinParent() { + return mWidth <= mParentWidth + && mFromXDelta + mWidth <= mParentWidth + && mFromXDelta >= 0; } } diff --git a/services/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java index 70822eebba82..08758afcb0b2 100644 --- a/services/core/java/com/android/server/wm/WindowAnimationSpec.java +++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java @@ -125,16 +125,30 @@ public class WindowAnimationSpec implements AnimationSpec { @Override public long calculateStatusBarTransitionStartTime() { TranslateAnimation openTranslateAnimation = findTranslateAnimation(mAnimation); - if (openTranslateAnimation != null) { - // Some interpolators are extremely quickly mostly finished, but not completely. For - // our purposes, we need to find the fraction for which ther interpolator is mostly - // there, and use that value for the calculation. - float t = findAlmostThereFraction(openTranslateAnimation.getInterpolator()); - return SystemClock.uptimeMillis() - + openTranslateAnimation.getStartOffset() - + (long)(openTranslateAnimation.getDuration() * t) - - STATUS_BAR_TRANSITION_DURATION; + if (openTranslateAnimation != null) { + if (openTranslateAnimation.isXAxisTransition() + && openTranslateAnimation.isFullWidthTranslate()) { + // On X axis transitions that are fullscreen (heuristic for task like transitions) + // we want the status bar to animate right in the middle of the translation when + // the windows/tasks have each moved half way across. + float t = findMiddleOfTranslationFraction(openTranslateAnimation.getInterpolator()); + + return SystemClock.uptimeMillis() + + openTranslateAnimation.getStartOffset() + + (long) (openTranslateAnimation.getDuration() * t) + - (long) (STATUS_BAR_TRANSITION_DURATION * 0.5); + } else { + // Some interpolators are extremely quickly mostly finished, but not completely. For + // our purposes, we need to find the fraction for which their interpolator is mostly + // there, and use that value for the calculation. + float t = findAlmostThereFraction(openTranslateAnimation.getInterpolator()); + + return SystemClock.uptimeMillis() + + openTranslateAnimation.getStartOffset() + + (long) (openTranslateAnimation.getDuration() * t) + - STATUS_BAR_TRANSITION_DURATION; + } } else { return SystemClock.uptimeMillis(); } @@ -183,20 +197,39 @@ public class WindowAnimationSpec implements AnimationSpec { } /** - * Binary searches for a {@code t} such that there exists a {@code -0.01 < eps < 0.01} for which - * {@code interpolator(t + eps) > 0.99}. + * Finds the fraction of the animation's duration at which the transition is almost done with a + * maximal error of 0.01 when it is animated with {@code interpolator}. */ private static float findAlmostThereFraction(Interpolator interpolator) { + return findInterpolationAdjustedTargetFraction(interpolator, 0.99f, 0.01f); + } + + /** + * Finds the fraction of the animation's duration at which the transition is spacially half way + * done with a maximal error of 0.01 when it is animated with {@code interpolator}. + */ + private float findMiddleOfTranslationFraction(Interpolator interpolator) { + return findInterpolationAdjustedTargetFraction(interpolator, 0.5f, 0.01f); + } + + /** + * Binary searches for a {@code val} such that there exists an {@code -0.01 < epsilon < 0.01} + * for which {@code interpolator(val + epsilon) > target}. + */ + private static float findInterpolationAdjustedTargetFraction( + Interpolator interpolator, float target, float epsilon) { float val = 0.5f; float adj = 0.25f; - while (adj >= 0.01f) { - if (interpolator.getInterpolation(val) < 0.99f) { + + while (adj >= epsilon) { + if (interpolator.getInterpolation(val) < target) { val += adj; } else { val -= adj; } adj /= 2; } + return val; } |