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

Commit bbea105b authored by Tony's avatar Tony Committed by Tony Wickham
Browse files

Move logic that overrides MotionPauseDetector to callers

There are 2 conditions that we force the MotionPauseDetector to treat
the motion as not paused:
1. If we haven't passed a small displacement (48dp before, 36dp now)
2. If we have moved mostly orthogonally

These existed soley for the OtherActivityInputConsumer case, because
1. We only need the displacement requirement to make room for the
   peeking shelf, which doesn't exist in other cases (it's already there on
   home for example)
2. We can only move orthogonally for quick switch, which again doesn't
   exist for other users of MotionPauseDetector.

So now instead of checking min displacement and orthogonal distance
inside MotionPauseDetector, we let callers setDisallowPause()
before adding positions to their MotionPauseDetector.

The only user visible change is that you no longer have to swipe up 48dp
before we allow pause to overview from home. This also paves the way to
using the same logic that determines to disallowPause to also detach
recents from the window while swiping up from an app.

Bug: 129985827
Change-Id: Ie690aa314da3260aff2209341a29638604f9501c
parent b0c81fc0
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.ViewConfiguration;

import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
@@ -44,12 +45,14 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
    private static final long PEEK_ANIM_DURATION = 100;

    private final MotionPauseDetector mMotionPauseDetector;
    private final float mMotionPauseMinDisplacement;

    private AnimatorSet mPeekAnim;

    public FlingAndHoldTouchController(Launcher l) {
        super(l, false /* allowDragToOverview */);
        mMotionPauseDetector = new MotionPauseDetector(l);
        mMotionPauseMinDisplacement = ViewConfiguration.get(l).getScaledTouchSlop();
    }

    @Override
@@ -98,7 +101,8 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {

    @Override
    public boolean onDrag(float displacement, MotionEvent event) {
        mMotionPauseDetector.addPosition(displacement, 0, event.getEventTime());
        mMotionPauseDetector.setDisallowPause(-displacement < mMotionPauseMinDisplacement);
        mMotionPauseDetector.addPosition(displacement, event.getEventTime());
        return super.onDrag(displacement, event);
    }

+4 −4
Original line number Diff line number Diff line
@@ -21,14 +21,14 @@ import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.SWIPE;
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.SWIPE_NOOP;

import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction.UPLEFT;
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction.UPRIGHT;
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.SWIPE;
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.SWIPE_NOOP;
import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType.NAVBAR;

import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PointF;
@@ -40,10 +40,10 @@ import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;

import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.launcher3.R;
import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.NavigationBarCompat;

+19 −12
Original line number Diff line number Diff line
@@ -21,9 +21,9 @@ import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.INVALID_POINTER_ID;
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
import static com.android.launcher3.util.RaceConditionTracker.ENTER;
import static com.android.launcher3.util.RaceConditionTracker.EXIT;
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
@@ -45,6 +45,9 @@ import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import android.view.WindowManager;

import androidx.annotation.UiThread;

import com.android.launcher3.R;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.RaceConditionTracker;
import com.android.launcher3.util.TraceHelper;
@@ -62,8 +65,6 @@ import com.android.systemui.shared.system.WindowManagerWrapper;

import java.util.function.Consumer;

import androidx.annotation.UiThread;

/**
 * Input consumer for handling events originating from an activity other than Launcher
 */
@@ -90,6 +91,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC

    private final Consumer<OtherActivityInputConsumer> mOnCompleteCallback;
    private final MotionPauseDetector mMotionPauseDetector;
    private final float mMotionPauseMinDisplacement;
    private VelocityTracker mVelocityTracker;

    private WindowTransformSwipeHandler mInteractionHandler;
@@ -107,8 +109,9 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
    // Slop used to determine when we say that the gesture has started.
    private boolean mPassedTouchSlop;

    // TODO: Start displacement should have both x and y
    // Might be displacement in X or Y, depending on the direction we are swiping from the nav bar.
    private float mStartDisplacement;
    private float mStartDisplacementX;

    private Handler mMainThreadHandler;
    private Runnable mCancelRecentsAnimationRunnable = () -> {
@@ -131,6 +134,8 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
        mMode = SysUINavigationMode.getMode(base);

        mMotionPauseDetector = new MotionPauseDetector(base);
        mMotionPauseMinDisplacement = base.getResources().getDimension(
                R.dimen.motion_pause_detector_min_displacement_from_app);
        mOnCompleteCallback = onCompleteCallback;
        mVelocityTracker = VelocityTracker.obtain();
        mInputMonitorCompat = inputMonitorCompat;
@@ -219,6 +224,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
                }
                mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
                float displacement = getDisplacement(ev);
                float displacementX = mLastPos.x - mDownPos.x;

                if (!mPassedDragSlop) {
                    if (!mIsDeferredDownTarget) {
@@ -227,13 +233,13 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
                        if (Math.abs(displacement) > mDragSlop) {
                            mPassedDragSlop = true;
                            mStartDisplacement = displacement;
                            mStartDisplacementX = displacementX;
                        }
                    }
                }

                if (!mPassedTouchSlop) {
                    if (Math.hypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y) >=
                            mTouchSlop) {
                    if (Math.hypot(displacementX, mLastPos.y - mDownPos.y) >= mTouchSlop) {
                        mPassedTouchSlop = true;

                        if (mIsDeferredDownTarget) {
@@ -244,6 +250,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
                        if (!mPassedDragSlop) {
                            mPassedDragSlop = true;
                            mStartDisplacement = displacement;
                            mStartDisplacementX = displacementX;
                        }
                        notifyGestureStarted();
                    }
@@ -254,12 +261,12 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
                    mInteractionHandler.updateDisplacement(displacement - mStartDisplacement);

                    if (mMode == Mode.NO_BUTTON) {
                        boolean isLandscape = isNavBarOnLeft() || isNavBarOnRight();
                        float orthogonalDisplacement = !isLandscape
                                ? ev.getX() - mDownPos.x
                                : ev.getY() - mDownPos.y;
                        mMotionPauseDetector.addPosition(displacement, orthogonalDisplacement,
                                ev.getEventTime());
                        float horizontalDist = Math.abs(displacementX - mStartDisplacementX);
                        float upDist = -(displacement - mStartDisplacement);
                        boolean isLikelyToStartNewTask = horizontalDist > upDist;
                        mMotionPauseDetector.setDisallowPause(upDist < mMotionPauseMinDisplacement
                                || isLikelyToStartNewTask);
                        mMotionPauseDetector.addPosition(displacement, ev.getEventTime());
                    }
                }
                break;
+1 −1
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@
    <dimen name="motion_pause_detector_speed_very_slow">0.0285dp</dimen>
    <dimen name="motion_pause_detector_speed_somewhat_fast">0.285dp</dimen>
    <dimen name="motion_pause_detector_speed_fast">0.5dp</dimen>
    <dimen name="motion_pause_detector_min_displacement">48dp</dimen>
    <dimen name="motion_pause_detector_min_displacement_from_app">36dp</dimen>

    <!-- Launcher app transition -->
    <dimen name="content_trans_y">50dp</dimen>
+16 −36
Original line number Diff line number Diff line
@@ -38,28 +38,26 @@ public class MotionPauseDetector {
    private final float mSpeedVerySlow;
    private final float mSpeedSomewhatFast;
    private final float mSpeedFast;
    private final float mMinDisplacementForPause;
    private final Alarm mForcePauseTimeout;

    private Long mPreviousTime = null;
    private Float mPreviousPosition = null;
    private Float mPreviousVelocity = null;

    private TotalDisplacement mTotalDisplacement = new TotalDisplacement();
    private Float mFirstPosition = null;
    private Float mFirstOrthogonalPosition = null;

    private OnMotionPauseListener mOnMotionPauseListener;
    private boolean mIsPaused;
    // Bias more for the first pause to make it feel extra responsive.
    private boolean mHasEverBeenPaused;
    /** @see #setDisallowPause(boolean) */
    private boolean mDisallowPause;

    public MotionPauseDetector(Context context) {
        Resources res = context.getResources();
        mSpeedVerySlow = res.getDimension(R.dimen.motion_pause_detector_speed_very_slow);
        mSpeedSomewhatFast = res.getDimension(R.dimen.motion_pause_detector_speed_somewhat_fast);
        mSpeedFast = res.getDimension(R.dimen.motion_pause_detector_speed_fast);
        mMinDisplacementForPause = res.getDimension(R.dimen.motion_pause_detector_min_displacement);
        mForcePauseTimeout = new Alarm();
        mForcePauseTimeout.setOnAlarmListener(alarm -> updatePaused(true /* isPaused */));
    }
@@ -72,29 +70,31 @@ public class MotionPauseDetector {
        mOnMotionPauseListener = listener;
    }

    /**
     * @param disallowPause If true, we will not detect any pauses until this is set to false again.
     */
    public void setDisallowPause(boolean disallowPause) {
        mDisallowPause = disallowPause;
        updatePaused(false);
    }

    /**
     * Computes velocity and acceleration to determine whether the motion is paused.
     * @param position The x or y component of the motion being tracked.
     * @param orthogonalPosition The x or y component (opposite of {@param position}) of the motion.
     *
     * TODO: Use historical positions as well, e.g. {@link MotionEvent#getHistoricalY(int, int)}.
     */
    public void addPosition(float position, float orthogonalPosition, long time) {
    public void addPosition(float position, long time) {
        if (mFirstPosition == null) {
            mFirstPosition = position;
        }
        if (mFirstOrthogonalPosition == null) {
            mFirstOrthogonalPosition = orthogonalPosition;
        }
        mForcePauseTimeout.setAlarm(FORCE_PAUSE_TIMEOUT);
        if (mPreviousTime != null && mPreviousPosition != null) {
            long changeInTime = Math.max(1, time - mPreviousTime);
            float changeInPosition = position - mPreviousPosition;
            float velocity = changeInPosition / changeInTime;
            if (mPreviousVelocity != null) {
                mTotalDisplacement.set(Math.abs(position - mFirstPosition),
                        Math.abs(orthogonalPosition - mFirstOrthogonalPosition));
                checkMotionPaused(velocity, mPreviousVelocity, mTotalDisplacement);
                checkMotionPaused(velocity, mPreviousVelocity);
            }
            mPreviousVelocity = velocity;
        }
@@ -102,8 +102,7 @@ public class MotionPauseDetector {
        mPreviousPosition = position;
    }

    private void checkMotionPaused(float velocity, float prevVelocity,
            TotalDisplacement totalDisplacement) {
    private void checkMotionPaused(float velocity, float prevVelocity) {
        float speed = Math.abs(velocity);
        float previousSpeed = Math.abs(prevVelocity);
        boolean isPaused;
@@ -125,16 +124,13 @@ public class MotionPauseDetector {
                }
            }
        }
        boolean passedMinDisplacement = totalDisplacement.primary >= mMinDisplacementForPause;
        boolean isDisplacementOrthogonal = totalDisplacement.orthogonal > totalDisplacement.primary;
        if (!passedMinDisplacement || isDisplacementOrthogonal) {
            mForcePauseTimeout.cancelAlarm();
            isPaused = false;
        }
        updatePaused(isPaused);
    }

    private void updatePaused(boolean isPaused) {
        if (mDisallowPause) {
            isPaused = false;
        }
        if (mIsPaused != isPaused) {
            mIsPaused = isPaused;
            if (mIsPaused) {
@@ -151,8 +147,6 @@ public class MotionPauseDetector {
        mPreviousPosition = null;
        mPreviousVelocity = null;
        mFirstPosition = null;
        mFirstOrthogonalPosition = null;
        mTotalDisplacement.set(0, 0);
        setOnMotionPauseListener(null);
        mIsPaused = mHasEverBeenPaused = false;
        mForcePauseTimeout.cancelAlarm();
@@ -165,18 +159,4 @@ public class MotionPauseDetector {
    public interface OnMotionPauseListener {
        void onMotionPauseChanged(boolean isPaused);
    }

    /**
     * Contains the displacement from the first tracked position,
     * along both the primary and orthogonal axes.
     */
    private class TotalDisplacement {
        public float primary;
        public float orthogonal;

        public void set(float primaryDisplacement, float orthogonalDisplacement) {
            this.primary = primaryDisplacement;
            this.orthogonal = orthogonalDisplacement;
        }
    }
}