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:
+37
-3
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user