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

Commit e435e982 authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Implement parallax when dismissing docked/fullscreen stack

When moving the docked or the fullscreen task close to the side,
we add a nice parallax to indicate that this task will be dismissed.

Change-Id: Ide195876942c1614c186fd5f3ff3e86f6fdfec61
parent 5098159a
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -118,6 +118,22 @@ public class DividerSnapAlgorithm {
        }
    }

    public SnapTarget getFirstSplitTarget() {
        return mFirstSplitTarget;
    }

    public SnapTarget getLastSplitTarget() {
        return mLastSplitTarget;
    }

    public SnapTarget getDismissStartTarget() {
        return mDismissStartTarget;
    }

    public SnapTarget getDismissEndTarget() {
        return mDismissEndTarget;
    }

    private SnapTarget snap(int position) {
        int minIndex = -1;
        int minDistance = Integer.MAX_VALUE;
+114 −6
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.graphics.Rect;
import android.graphics.Region.Op;
import android.hardware.display.DisplayManager;
import android.util.AttributeSet;
import android.util.MathUtils;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.MotionEvent;
@@ -37,6 +38,7 @@ import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewTreeObserver.InternalInsetsInfo;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.animation.AnimationUtils;
@@ -64,6 +66,9 @@ public class DividerView extends FrameLayout implements OnTouchListener,
    private static final float DIM_START_FRACTION = 0.5f;
    private static final float DIM_DAMP_FACTOR = 1.7f;

    private static final PathInterpolator SLOWDOWN_INTERPOLATOR =
            new PathInterpolator(0.5f, 1f, 0.5f, 1f);

    private ImageButton mHandle;
    private View mBackground;
    private int mStartX;
@@ -202,7 +207,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
                    int position = calculatePosition(x, y);
                    SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position,
                            0 /* velocity */);
                    resizeStack(calculatePosition(x, y), snapTarget.position);
                    resizeStack(calculatePosition(x, y), snapTarget.position, snapTarget);
                }
                break;
            case MotionEvent.ACTION_UP:
@@ -235,7 +240,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
                resizeStack((Integer) animation.getAnimatedValue(),
                        animation.getAnimatedFraction() == 1f
                                ? TASK_POSITION_SAME
                                : snapTarget.position);
                                : snapTarget.position, snapTarget);
            }
        });
        anim.addListener(new AnimatorListenerAdapter() {
@@ -393,7 +398,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
                containingRect.right, containingRect.bottom);
    }

    public void resizeStack(int position, int taskPosition) {
    public void resizeStack(int position, int taskPosition, SnapTarget taskSnapTarget) {
        calculateBoundsForPosition(position, mDockSide, mDockedRect);

        if (mDockedRect.equals(mLastResizeRect)) {
@@ -406,19 +411,28 @@ public class DividerView extends FrameLayout implements OnTouchListener,
        mLastResizeRect.set(mDockedRect);
        if (taskPosition != TASK_POSITION_SAME) {
            calculateBoundsForPosition(position, invertDockSide(mDockSide), mOtherRect);
            calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect);
            calculateBoundsForPosition(taskPosition, invertDockSide(mDockSide), mOtherTaskRect);
            int dockSideInverted = invertDockSide(mDockSide);
            int taskPositionDocked =
                    restrictDismissingTaskPosition(taskPosition, mDockSide, taskSnapTarget);
            int taskPositionOther =
                    restrictDismissingTaskPosition(taskPosition, dockSideInverted, taskSnapTarget);
            calculateBoundsForPosition(taskPositionDocked, mDockSide, mDockedTaskRect);
            calculateBoundsForPosition(taskPositionOther, dockSideInverted, mOtherTaskRect);
            alignTopLeft(mDockedRect, mDockedTaskRect);
            alignTopLeft(mOtherRect, mOtherTaskRect);
            mDockedInsetRect.set(mDockedTaskRect);
            mOtherInsetRect.set(mOtherTaskRect);
            if (mDockSide == WindowManager.DOCKED_LEFT || mDockSide == WindowManager.DOCKED_TOP) {
            if (dockSideTopLeft(mDockSide)) {
                alignTopLeft(mDockedRect, mDockedInsetRect);
                alignBottomRight(mOtherRect, mOtherInsetRect);
            } else {
                alignBottomRight(mDockedRect, mDockedInsetRect);
                alignTopLeft(mOtherRect, mOtherInsetRect);
            }
            applyDismissingParallax(mDockedTaskRect, mDockSide, taskSnapTarget, position,
                    taskPositionDocked);
            applyDismissingParallax(mOtherTaskRect, dockSideInverted, taskSnapTarget, position,
                    taskPositionOther);
            mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedInsetRect,
                    mOtherTaskRect, mOtherInsetRect);
        } else {
@@ -432,6 +446,86 @@ public class DividerView extends FrameLayout implements OnTouchListener,
                fraction);
    }

    /**
     * When the snap target is dismissing one side, make sure that the dismissing side doesn't get
     * 0 size.
     */
    private int restrictDismissingTaskPosition(int taskPosition, int dockSide,
            SnapTarget snapTarget) {
        if (snapTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(dockSide)) {
            return mSnapAlgorithm.getFirstSplitTarget().position;
        } else if (snapTarget.flag == SnapTarget.FLAG_DISMISS_END
                && dockSideBottomRight(dockSide)) {
            return mSnapAlgorithm.getLastSplitTarget().position;
        } else {
            return taskPosition;
        }
    }

    /**
     * Applies a parallax to the task when dismissing.
     */
    private void applyDismissingParallax(Rect taskRect, int dockSide, SnapTarget snapTarget,
            int position, int taskPosition) {
        float fraction = Math.min(1, Math.max(0,
                mSnapAlgorithm.calculateDismissingFraction(position)));
        SnapTarget dismissTarget = null;
        SnapTarget splitTarget = null;
        if ((snapTarget.flag == SnapTarget.FLAG_DISMISS_START
                || snapTarget == mSnapAlgorithm.getFirstSplitTarget())
                && dockSideTopLeft(dockSide)) {
            dismissTarget = mSnapAlgorithm.getDismissStartTarget();
            splitTarget = mSnapAlgorithm.getFirstSplitTarget();
        } else if ((snapTarget.flag == SnapTarget.FLAG_DISMISS_END
                || snapTarget == mSnapAlgorithm.getLastSplitTarget())
                && dockSideBottomRight(dockSide)) {
            dismissTarget = mSnapAlgorithm.getDismissEndTarget();
            splitTarget = mSnapAlgorithm.getLastSplitTarget();
        }
        if (dismissTarget != null && fraction > 0f
                && isDismissing(splitTarget, position, dockSide)) {
            fraction = calculateParallaxDismissingFraction(fraction);
            int offsetPosition = (int) (taskPosition +
                    fraction * (dismissTarget.position - splitTarget.position));
            int width = taskRect.width();
            int height = taskRect.height();
            switch (dockSide) {
                case WindowManager.DOCKED_LEFT:
                    taskRect.left = offsetPosition - width;
                    taskRect.right = offsetPosition;
                    break;
                case WindowManager.DOCKED_RIGHT:
                    taskRect.left = offsetPosition + mDividerSize;
                    taskRect.right = offsetPosition + width + mDividerSize;
                    break;
                case WindowManager.DOCKED_TOP:
                    taskRect.top = offsetPosition - height;
                    taskRect.bottom = offsetPosition;
                    break;
                case WindowManager.DOCKED_BOTTOM:
                    taskRect.top = offsetPosition + mDividerSize;
                    taskRect.bottom = offsetPosition + height + mDividerSize;
                    break;
            }
        }
    }

    /**
     * @return for a specified {@code fraction}, this returns an adjusted value that simulates a
     *         slowing down parallax effect
     */
    private static float calculateParallaxDismissingFraction(float fraction) {
        return SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;
    }

    private static boolean isDismissing(SnapTarget snapTarget, int position, int dockSide) {
        if (dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT) {
            return position < snapTarget.position;
        } else {
            return position > snapTarget.position;
        }
    }

    private int getStackIdForDismissTarget(SnapTarget dismissTarget) {
        if (dismissTarget.flag == SnapTarget.FLAG_DISMISS_START &&
                (mDockSide == WindowManager.DOCKED_LEFT || mDockSide == WindowManager.DOCKED_TOP)) {
@@ -441,6 +535,20 @@ public class DividerView extends FrameLayout implements OnTouchListener,
        }
    }

    /**
     * @return true if and only if {@code dockSide} is top or left
     */
    private static boolean dockSideTopLeft(int dockSide) {
        return dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT;
    }

    /**
     * @return true if and only if {@code dockSide} is bottom or right
     */
    private static boolean dockSideBottomRight(int dockSide) {
        return dockSide == WindowManager.DOCKED_BOTTOM || dockSide == WindowManager.DOCKED_RIGHT;
    }

    @Override
    public void onComputeInternalInsets(InternalInsetsInfo inoutInfo) {
        inoutInfo.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+4 −3
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.stackdivider.DividerSnapAlgorithm.SnapTarget;
import com.android.systemui.stackdivider.DividerView;
import com.android.systemui.tuner.TunerService;

@@ -200,9 +201,9 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL
        } else {
            if (mDragMode == DRAG_MODE_DIVIDER) {
                int position = !mIsVertical ? (int) event.getRawY() : (int) event.getRawX();
                mDivider.getView().resizeStack(
                        position, mDivider.getView().getSnapAlgorithm()
                                .calculateSnapTarget(position, 0f /* velocity */).position);
                SnapTarget snapTarget = mDivider.getView().getSnapAlgorithm()
                        .calculateSnapTarget(position, 0f /* velocity */);
                mDivider.getView().resizeStack(position, snapTarget.position, snapTarget);
            } else if (mDragMode == DRAG_MODE_RECENTS) {
                mRecentsComponent.onDraggingInRecents(event.getRawY());
            }