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

Commit 1d480695 authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Change fling behavior of PanelView.

Change-Id: Ie700be6b1ef48350601ce6bc7fe60579fddae098
parent b7b61dda
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -233,9 +233,6 @@
         in dps over one second of time. -->
    <dimen name="recents_animation_movement_in_dps_per_second">800dp</dimen>

    <!-- Space below the notification stack -->
    <dimen name="notification_stack_margin_bottom">0dp</dimen>

    <!-- Space reserved for the cards behind the top card in the top stack -->
    <dimen name="top_stack_peek_amount">12dp</dimen>

+82 −8
Original line number Diff line number Diff line
@@ -27,23 +27,32 @@ import android.view.animation.PathInterpolator;
 */
public class FlingAnimationUtils {

    private static final float LINEAR_OUT_SLOW_IN_Y2 = 0.35f;
    private static final float MAX_LENGTH_SECONDS = 0.4f;
    private static final float LINEAR_OUT_SLOW_IN_X2 = 0.35f;
    private static final float LINEAR_OUT_FASTER_IN_Y2 = 0.7f;
    private static final float MIN_VELOCITY_DP_PER_SECOND = 250;

    /**
     * Crazy math. http://en.wikipedia.org/wiki/B%C3%A9zier_curve
     */
    private static final float LINEAR_OUT_SLOW_IN_START_GRADIENT = 1/LINEAR_OUT_SLOW_IN_Y2;
    private static final float LINEAR_OUT_SLOW_IN_START_GRADIENT = 1.0f / LINEAR_OUT_SLOW_IN_X2;
    private static final float LINEAR_OUT_FASTER_IN_START_GRADIENT = LINEAR_OUT_FASTER_IN_Y2;

    private Interpolator mLinearOutSlowIn;
    private Interpolator mFastOutSlowIn;
    private Interpolator mFastOutLinearIn;
    private Interpolator mLinearOutFasterIn;

    private float mMinVelocityPxPerSecond;
    private float mMaxLengthSeconds;

    public FlingAnimationUtils(Context ctx) {
        mLinearOutSlowIn = new PathInterpolator(0, 0, LINEAR_OUT_SLOW_IN_Y2, 1);
    public FlingAnimationUtils(Context ctx, float maxLengthSeconds) {
        mMaxLengthSeconds = maxLengthSeconds;
        mLinearOutSlowIn = new PathInterpolator(0, 0, LINEAR_OUT_SLOW_IN_X2, 1);
        mLinearOutFasterIn = new PathInterpolator(0, 0, 1, LINEAR_OUT_FASTER_IN_Y2);
        mFastOutSlowIn
                = AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_slow_in);
        mFastOutLinearIn
                = AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_linear_in);
        mMinVelocityPxPerSecond
                = MIN_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density;
    }
@@ -58,15 +67,33 @@ public class FlingAnimationUtils {
     * @param velocity the current velocity of the motion
     */
    public void apply(ValueAnimator animator, float currValue, float endValue, float velocity) {
        apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue));
    }

    /**
     * Applies the interpolator and length to the animator, such that the fling animation is
     * consistent with the finger motion.
     *
     * @param animator the animator to apply
     * @param currValue the current value
     * @param endValue the end value of the animator
     * @param velocity the current velocity of the motion
     * @param maxDistance the maximum distance for this interaction; the maximum animation length
     *                    gets multiplied by the ratio between the actual distance and this value
     */
    public void apply(ValueAnimator animator, float currValue, float endValue, float velocity,
            float maxDistance) {
        float maxLengthSeconds = (float) (mMaxLengthSeconds
                * Math.sqrt(Math.abs(endValue - currValue) / maxDistance));
        float diff = Math.abs(endValue - currValue);
        float velAbs = Math.abs(velocity);
        float durationSeconds = LINEAR_OUT_SLOW_IN_START_GRADIENT * diff / velAbs;
        if (durationSeconds <= MAX_LENGTH_SECONDS) {
        if (durationSeconds <= maxLengthSeconds) {
            animator.setInterpolator(mLinearOutSlowIn);
        } else if (velAbs >= mMinVelocityPxPerSecond) {

            // Cross fade between fast-out-slow-in and linear interpolator with current velocity.
            durationSeconds = MAX_LENGTH_SECONDS;
            durationSeconds = maxLengthSeconds;
            VelocityInterpolator velocityInterpolator
                    = new VelocityInterpolator(durationSeconds, velAbs, diff);
            InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator(
@@ -75,12 +102,59 @@ public class FlingAnimationUtils {
        } else {

            // Just use a normal interpolator which doesn't take the velocity into account.
            durationSeconds = MAX_LENGTH_SECONDS;
            durationSeconds = maxLengthSeconds;
            animator.setInterpolator(mFastOutSlowIn);
        }
        animator.setDuration((long) (durationSeconds * 1000));
    }

    /**
     * Applies the interpolator and length to the animator, such that the fling animation is
     * consistent with the finger motion for the case when the animation is making something
     * disappear.
     *
     * @param animator the animator to apply
     * @param currValue the current value
     * @param endValue the end value of the animator
     * @param velocity the current velocity of the motion
     * @param maxDistance the maximum distance for this interaction; the maximum animation length
     *                    gets multiplied by the ratio between the actual distance and this value
     */
    public void applyDismissing(ValueAnimator animator, float currValue, float endValue,
            float velocity, float maxDistance) {
        float maxLengthSeconds = (float) (mMaxLengthSeconds
                * Math.pow(Math.abs(endValue - currValue) / maxDistance, 0.5f));
        float diff = Math.abs(endValue - currValue);
        float velAbs = Math.abs(velocity);
        float durationSeconds = LINEAR_OUT_FASTER_IN_START_GRADIENT * diff / velAbs;
        if (durationSeconds <= maxLengthSeconds) {
            animator.setInterpolator(mLinearOutFasterIn);
        } else if (velAbs >= mMinVelocityPxPerSecond) {

            // Cross fade between linear-out-faster-in and linear interpolator with current
            // velocity.
            durationSeconds = maxLengthSeconds;
            VelocityInterpolator velocityInterpolator
                    = new VelocityInterpolator(durationSeconds, velAbs, diff);
            InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator(
                    velocityInterpolator, mLinearOutFasterIn, mLinearOutSlowIn);
            animator.setInterpolator(superInterpolator);
        } else {

            // Just use a normal interpolator which doesn't take the velocity into account.
            durationSeconds = maxLengthSeconds;
            animator.setInterpolator(mFastOutLinearIn);
        }
        animator.setDuration((long) (durationSeconds * 1000));
    }

    /**
     * @return the minimum velocity a gesture needs to have to be considered a fling
     */
    public float getMinVelocityPxPerSecond() {
        return mMinVelocityPxPerSecond;
    }

    /**
     * An interpolator which interpolates two interpolators with an interpolator.
     */
+9 −16
Original line number Diff line number Diff line
@@ -150,7 +150,7 @@ public class NotificationPanelView extends PanelView implements
        mMoreCardNotificationAmount =
                (float) getResources().getDimensionPixelSize(R.dimen.notification_summary_height) /
                        getResources().getDimensionPixelSize(R.dimen.notification_min_height);
        mFlingAnimationUtils = new FlingAnimationUtils(getContext());
        mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.4f);
        mStatusBarMinHeight = getResources().getDimensionPixelSize(
                com.android.internal.R.dimen.status_bar_height);
    }
@@ -618,17 +618,15 @@ public class NotificationPanelView extends PanelView implements

    @Override
    protected int getMaxPanelHeight() {
        if (!isInSettings()) {
        // TODO: Figure out transition for collapsing when QS is open, adjust height here.
        int maxPanelHeight = super.getMaxPanelHeight();
            int notificationMarginBottom = mStackScrollerContainer.getPaddingBottom();
            int emptyBottomMargin = notificationMarginBottom
        int emptyBottomMargin = mStackScrollerContainer.getHeight()
                - mNotificationStackScroller.getHeight()
                + mNotificationStackScroller.getEmptyBottomMargin();
        int maxHeight = maxPanelHeight - emptyBottomMargin;
        maxHeight = Math.max(maxHeight, mStatusBarMinHeight);
        return maxHeight;
    }
        return super.getMaxPanelHeight();
    }

    private boolean isInSettings() {
        return mQsExpanded;
@@ -639,11 +637,6 @@ public class NotificationPanelView extends PanelView implements
        mNotificationStackScroller.setStackHeight(expandedHeight);
    }

    @Override
    protected int getDesiredMeasureHeight() {
        return mMaxPanelHeight;
    }

    @Override
    protected void onExpandingStarted() {
        super.onExpandingStarted();
+62 −257

File changed.

Preview size limit exceeded, changes collapsed.

+6 −8
Original line number Diff line number Diff line
@@ -84,7 +84,6 @@ public class NotificationStackScrollLayout extends ViewGroup
    private int mCollapsedSize;
    private int mBottomStackSlowDownHeight;
    private int mBottomStackPeekSize;
    private int mEmptyMarginBottom;
    private int mPaddingBetweenElements;
    private int mPaddingBetweenElementsDimmed;
    private int mPaddingBetweenElementsNormal;
@@ -178,6 +177,8 @@ public class NotificationStackScrollLayout extends ViewGroup
            canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
            y = (int) getLayoutHeight();
            canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
            y = getHeight() - getEmptyBottomMargin();
            canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
        }
    }

@@ -201,8 +202,6 @@ public class NotificationStackScrollLayout extends ViewGroup
                .getDimensionPixelSize(R.dimen.notification_min_height);
        mBottomStackPeekSize = context.getResources()
                .getDimensionPixelSize(R.dimen.bottom_stack_peek_amount);
        mEmptyMarginBottom = context.getResources().getDimensionPixelSize(
                R.dimen.notification_stack_margin_bottom);
        mStackScrollAlgorithm = new StackScrollAlgorithm(context);
        mPaddingBetweenElementsDimmed = context.getResources()
                .getDimensionPixelSize(R.dimen.notification_padding_dimmed);
@@ -242,7 +241,7 @@ public class NotificationStackScrollLayout extends ViewGroup
                    (int) (centerX + width / 2.0f),
                    (int) height);
        }
        setMaxLayoutHeight(getHeight() - mEmptyMarginBottom);
        setMaxLayoutHeight(getHeight());
        updateContentHeight();
        updateScrollPositionIfNecessary();
        requestChildrenUpdate();
@@ -297,10 +296,7 @@ public class NotificationStackScrollLayout extends ViewGroup
     *         last child is not in the bottom stack.
     */
    private boolean needsHeightAdaption() {
        View lastChild = getLastChildNotGone();
        View firstChild = getFirstChildNotGone();
        boolean isLastChildExpanded = isViewExpanded(lastChild);
        return isLastChildExpanded && lastChild != firstChild;
        return getNotGoneChildCount() > 1;
    }

    private boolean isViewExpanded(View view) {
@@ -1429,6 +1425,8 @@ public class NotificationStackScrollLayout extends ViewGroup
        int emptyMargin = mMaxLayoutHeight - mContentHeight;
        if (needsHeightAdaption()) {
            emptyMargin = emptyMargin - mBottomStackSlowDownHeight - mBottomStackPeekSize;
        } else {
            emptyMargin = emptyMargin - mBottomStackPeekSize;
        }
        return Math.max(emptyMargin, 0);
    }