From fd239cafbed7b74e1abb8e56a41be5f9d17fc96a Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Wed, 6 Nov 2019 14:27:23 -0800 Subject: [PATCH] Translate recents slightly while dragging after pausing There's a lot of resistance, but feels better than nothing responding to your movement. Bug: 143361609 Change-Id: I9d7e06279ebdbaa0317909ce96d6f001dbe9699a --- ...ButtonNavbarToOverviewTouchController.java | 40 +++++++++++++++++-- .../touch/SingleAxisSwipeDetector.java | 24 ++++++----- .../touch/SingleAxisSwipeDetectorTest.java | 5 ++- 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java index a993f3f53b..2ac2d2de8e 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java @@ -21,11 +21,13 @@ import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherStateManager.ATOMIC_OVERVIEW_PEEK_COMPONENT; import static com.android.launcher3.Utilities.EDGE_NAV_BAR; +import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL; import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC; import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ValueAnimator; +import android.graphics.PointF; import android.view.MotionEvent; import com.android.launcher3.Launcher; @@ -37,6 +39,7 @@ import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.util.VibratorWrapper; import com.android.quickstep.util.StaggeredWorkspaceAnim; +import com.android.quickstep.views.RecentsView; /** * Touch controller which handles swipe and hold from the nav bar to go to Overview. Swiping above @@ -45,11 +48,22 @@ import com.android.quickstep.util.StaggeredWorkspaceAnim; */ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchController { + + // How much of the movement to use for translating overview after swipe and hold. + private static final float OVERVIEW_MOVEMENT_FACTOR = 0.25f; + private static final long TRANSLATION_ANIM_MIN_DURATION_MS = 80; + private static final float TRANSLATION_ANIM_VELOCITY_DP_PER_MS = 0.8f; + + private final RecentsView mRecentsView; + private boolean mDidTouchStartInNavBar; private boolean mReachedOverview; + // The last recorded displacement before we reached overview. + private PointF mStartDisplacement = new PointF(); public NoButtonNavbarToOverviewTouchController(Launcher l) { super(l); + mRecentsView = l.getOverviewPanel(); } @Override @@ -125,12 +139,20 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo } @Override - public boolean onDrag(float displacement, MotionEvent event) { + public boolean onDrag(float yDisplacement, float xDisplacement, MotionEvent event) { if (mMotionPauseDetector.isPaused()) { + if (!mReachedOverview) { + mStartDisplacement.set(xDisplacement, yDisplacement); + } else { + mRecentsView.setTranslationX((xDisplacement - mStartDisplacement.x) + * OVERVIEW_MOVEMENT_FACTOR); + mRecentsView.setTranslationY((yDisplacement - mStartDisplacement.y) + * OVERVIEW_MOVEMENT_FACTOR); + } // Stay in Overview. return true; } - return super.onDrag(displacement, event); + return super.onDrag(yDisplacement, xDisplacement, event); } @Override @@ -164,7 +186,19 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo anim.start(); } } else { - maybeSwipeInteractionToOverviewComplete(); + if (mReachedOverview) { + float distanceDp = dpiFromPx(Math.max( + Math.abs(mRecentsView.getTranslationX()), + Math.abs(mRecentsView.getTranslationY()))); + long duration = (long) Math.max(TRANSLATION_ANIM_MIN_DURATION_MS, + distanceDp / TRANSLATION_ANIM_VELOCITY_DP_PER_MS); + mRecentsView.animate() + .translationX(0) + .translationY(0) + .setInterpolator(ACCEL_DEACCEL) + .setDuration(duration) + .withEndAction(this::maybeSwipeInteractionToOverviewComplete); + } } } diff --git a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java index f2ebc45193..9d406f3bef 100644 --- a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java +++ b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java @@ -54,8 +54,8 @@ public class SingleAxisSwipeDetector extends BaseSwipeDetector { } @Override - boolean canScrollStart(PointF displacement, float touchSlop) { - return Math.abs(displacement.y) >= Math.max(Math.abs(displacement.x), touchSlop); + float extractOrthogonalDirection(PointF direction) { + return direction.x; } }; @@ -80,9 +80,10 @@ public class SingleAxisSwipeDetector extends BaseSwipeDetector { } @Override - boolean canScrollStart(PointF displacement, float touchSlop) { - return Math.abs(displacement.x) >= Math.max(Math.abs(displacement.y), touchSlop); + float extractOrthogonalDirection(PointF direction) { + return direction.y; } + }; private final Direction mDir; @@ -126,7 +127,9 @@ public class SingleAxisSwipeDetector extends BaseSwipeDetector { @Override protected boolean shouldScrollStart(PointF displacement) { // Reject cases where the angle or slop condition is not met. - if (!mDir.canScrollStart(displacement, mTouchSlop)) { + float minDisplacement = Math.max(mTouchSlop, + Math.abs(mDir.extractOrthogonalDirection(displacement))); + if (Math.abs(mDir.extractDirection(displacement)) < minDisplacement) { return false; } @@ -150,7 +153,8 @@ public class SingleAxisSwipeDetector extends BaseSwipeDetector { @Override protected void reportDraggingInternal(PointF displacement, MotionEvent event) { - mListener.onDrag(mDir.extractDirection(displacement), event); + mListener.onDrag(mDir.extractDirection(displacement), + mDir.extractOrthogonalDirection(displacement), event); } @Override @@ -164,13 +168,16 @@ public class SingleAxisSwipeDetector extends BaseSwipeDetector { /** @param start whether this was the original drag start, as opposed to a recatch. */ void onDragStart(boolean start); - // TODO remove boolean onDrag(float displacement); default boolean onDrag(float displacement, MotionEvent event) { return onDrag(displacement); } + default boolean onDrag(float displacement, float orthogonalDisplacement, MotionEvent ev) { + return onDrag(displacement, ev); + } + void onDragEnd(float velocity); } @@ -183,8 +190,7 @@ public class SingleAxisSwipeDetector extends BaseSwipeDetector { /** Returns the part of the given {@link PointF} that is relevant to this direction. */ abstract float extractDirection(PointF point); - /** Reject cases where the angle or slop condition is not met. */ - abstract boolean canScrollStart(PointF displacement, float touchSlop); + abstract float extractOrthogonalDirection(PointF point); } } diff --git a/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java b/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java index 6d463b5684..b0ece77c9b 100644 --- a/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java +++ b/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java @@ -22,15 +22,16 @@ import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL; import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyFloat; -import static org.mockito.Matchers.anyObject; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.util.Log; +import android.view.MotionEvent; import android.view.ViewConfiguration; import androidx.test.InstrumentationRegistry; @@ -158,7 +159,7 @@ public class SingleAxisSwipeDetectorTest { mGenerator.put(0, 100, 100); mGenerator.move(0, 100, 100 + mTouchSlop); // TODO: actually calculate the following parameters and do exact value checks. - verify(mMockListener).onDrag(anyFloat(), anyObject()); + verify(mMockListener).onDrag(anyFloat(), anyFloat(), any(MotionEvent.class)); } @Test