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

Commit 5935f559 authored by Jerry Chang's avatar Jerry Chang
Browse files

Add fling animation when snapping split divider bar

Bug: 172704238
Test: atest WMShellUnitTests
Test: manul check the fling behavior
Change-Id: Iead37be86d55de2ce357165a2f6ae910f36969cb
parent 9547fb5f
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -112,7 +112,7 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
                }
                if (mMoving) {
                    final int position = mSplitLayout.getDividePosition() + touchPos - mStartPos;
                    mSplitLayout.updateDividePosition(position);
                    mSplitLayout.updateDivideBounds(position);
                }
                break;
            case MotionEvent.ACTION_UP:
@@ -131,7 +131,7 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
                final int position = mSplitLayout.getDividePosition() + touchPos - mStartPos;
                final DividerSnapAlgorithm.SnapTarget snapTarget =
                        mSplitLayout.findSnapTarget(position, velocity);
                mSplitLayout.setSnapTarget(snapTarget);
                mSplitLayout.snapToTarget(position, snapTarget);
                break;
        }
        return true;
+35 −6
Original line number Diff line number Diff line
@@ -22,6 +22,9 @@ import static android.view.WindowManager.DOCKED_TOP;
import static com.android.internal.policy.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END;
import static com.android.internal.policy.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -31,6 +34,7 @@ import android.view.SurfaceControl;
import androidx.annotation.Nullable;

import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.wm.shell.animation.Interpolators;

/**
 * Records and handles layout of splits. Helps to calculate proper bounds when configuration or
@@ -145,16 +149,22 @@ public class SplitLayout {
     * Updates bounds with the passing position. Usually used to update recording bounds while
     * performing animation or dragging divider bar to resize the splits.
     */
    public void updateDividePosition(int position) {
    void updateDivideBounds(int position) {
        updateBounds(position);
        mLayoutChangeListener.onBoundsChanging(this);
    }

    void setDividePosition(int position) {
        mDividePosition = position;
        updateBounds(mDividePosition);
        mLayoutChangeListener.onBoundsChanged(this);
    }

    /**
     * Sets new divide position and updates bounds correspondingly. Notifies listener if the new
     * target indicates dismissing split.
     */
    public void setSnapTarget(DividerSnapAlgorithm.SnapTarget snapTarget) {
    public void snapToTarget(int currentPosition, DividerSnapAlgorithm.SnapTarget snapTarget) {
        switch (snapTarget.flag) {
            case FLAG_DISMISS_START:
                mLayoutChangeListener.onSnappedToDismiss(false /* snappedToEnd */);
@@ -163,9 +173,7 @@ public class SplitLayout {
                mLayoutChangeListener.onSnappedToDismiss(true /* snappedToEnd */);
                break;
            default:
                mDividePosition = snapTarget.position;
                updateBounds(mDividePosition);
                mLayoutChangeListener.onBoundsChanged(this);
                flingDividePosition(currentPosition, snapTarget.position);
                break;
        }
    }
@@ -189,6 +197,27 @@ public class SplitLayout {
                isLandscape ? DOCKED_LEFT : DOCKED_TOP /* dockSide */);
    }

    private void flingDividePosition(int from, int to) {
        ValueAnimator animator = ValueAnimator
                .ofInt(from, to)
                .setDuration(250);
        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
        animator.addUpdateListener(
                animation -> updateDivideBounds((int) animation.getAnimatedValue()));
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                setDividePosition(to);
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                setDividePosition(to);
            }
        });
        animator.start();
    }

    private static boolean isLandscape(Rect bounds) {
        return bounds.width() > bounds.height();
    }
+13 −10
Original line number Diff line number Diff line
@@ -69,24 +69,27 @@ public class SplitLayoutTests extends ShellTestCase {
    }

    @Test
    public void testUpdateDividePosition() {
        mSplitLayout.updateDividePosition(anyInt());
    public void testUpdateDivideBounds() {
        mSplitLayout.updateDivideBounds(anyInt());
        verify(mLayoutChangeListener).onBoundsChanging(any(SplitLayout.class));
    }

    @Test
    public void testSetSnapTarget() {
        DividerSnapAlgorithm.SnapTarget snapTarget = getSnapTarget(0,
    @UiThreadTest
    public void testSnapToTarget() {
        DividerSnapAlgorithm.SnapTarget snapTarget = getSnapTarget(0 /* position */,
                DividerSnapAlgorithm.SnapTarget.FLAG_NONE);
        mSplitLayout.setSnapTarget(snapTarget);
        verify(mLayoutChangeListener).onBoundsChanged(any(SplitLayout.class));
        mSplitLayout.snapToTarget(0 /* currentPosition */, snapTarget);
        verify(mLayoutChangeListener).onBoundsChanging(any(SplitLayout.class));

        // verify it callbacks properly when the snap target indicates dismissing split.
        snapTarget = getSnapTarget(0, DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START);
        mSplitLayout.setSnapTarget(snapTarget);
        snapTarget = getSnapTarget(0 /* position */,
                DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START);
        mSplitLayout.snapToTarget(0 /* currentPosition */, snapTarget);
        verify(mLayoutChangeListener).onSnappedToDismiss(eq(false));
        snapTarget = getSnapTarget(0, DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END);
        mSplitLayout.setSnapTarget(snapTarget);
        snapTarget = getSnapTarget(0 /* position */,
                DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END);
        mSplitLayout.snapToTarget(0 /* currentPosition */, snapTarget);
        verify(mLayoutChangeListener).onSnappedToDismiss(eq(true));
    }