Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3ea6b0ab authored by Pablo Gamito's avatar Pablo Gamito
Browse files

Update status bar transition start time

Update to feel less flickery with the new task transition animation

We want to try and have the navbar transition right when the animation is in between the two tasks

Bug: 200674544
Test: Existing tests
Change-Id: If99965c4b4776c902a3c6b32a3fcdb0b65811407
parent 49fa1851
Loading
Loading
Loading
Loading
+58 −0
Original line number Diff line number Diff line
@@ -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;
    }
}
+46 −13
Original line number Diff line number Diff line
@@ -125,16 +125,30 @@ public class WindowAnimationSpec implements AnimationSpec {
    @Override
    public long calculateStatusBarTransitionStartTime() {
        TranslateAnimation openTranslateAnimation = findTranslateAnimation(mAnimation);

        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 ther interpolator is mostly
                // 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;
    }