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

Commit fd239caf authored by Tony Wickham's avatar Tony Wickham
Browse files

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
parent 4fdba14c
Loading
Loading
Loading
Loading
+37 −3
Original line number Diff line number Diff line
@@ -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);
            }
        }
    }

+15 −9
Original line number Diff line number Diff line
@@ -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);

    }
}
+3 −2
Original line number Diff line number Diff line
@@ -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