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
This commit is contained in:
Tony Wickham
2019-11-06 14:27:23 -08:00
parent 4fdba14cfb
commit fd239cafbe
3 changed files with 55 additions and 14 deletions
@@ -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);
}
}
}
@@ -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);
}
}
@@ -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