From 5935f559b69c24bf009b57c5b91eabe73444a9ef Mon Sep 17 00:00:00 2001 From: Jerry Chang Date: Thu, 10 Dec 2020 13:03:53 +0800 Subject: [PATCH] Add fling animation when snapping split divider bar Bug: 172704238 Test: atest WMShellUnitTests Test: manul check the fling behavior Change-Id: Iead37be86d55de2ce357165a2f6ae910f36969cb --- .../wm/shell/common/split/DividerView.java | 4 +- .../wm/shell/common/split/SplitLayout.java | 41 ++++++++++++++++--- .../shell/common/split/SplitLayoutTests.java | 23 ++++++----- 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java index 50d9fe8629ac9..e97fe0a9111c0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java @@ -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; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index e11037f55cfaf..4c70b5d32108e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -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,17 +149,23 @@ 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) { - switch(snapTarget.flag) { + public void snapToTarget(int currentPosition, DividerSnapAlgorithm.SnapTarget snapTarget) { + switch (snapTarget.flag) { case FLAG_DISMISS_START: mLayoutChangeListener.onSnappedToDismiss(false /* snappedToEnd */); break; @@ -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(); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java index d87f4c60fad43..9fdd59bee176e 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java @@ -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)); }