Loading quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/FlingAndHoldTouchController.java +1 −1 Original line number Diff line number Diff line Loading @@ -57,7 +57,7 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { @Override public boolean onDrag(float displacement) { mMotionPauseDetector.addPosition(displacement); mMotionPauseDetector.addPosition(displacement, 0); return super.onDrag(displacement); } Loading quickstep/res/values/dimens.xml +1 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ <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_max_orthogonal_displacement">48dp</dimen> <!-- Launcher app transition --> <dimen name="content_trans_y">50dp</dimen> Loading quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java +5 −1 Original line number Diff line number Diff line Loading @@ -201,7 +201,11 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC dispatchMotion(ev, displacement - mStartDisplacement, null); if (FeatureFlags.SWIPE_HOME.get()) { mMotionPauseDetector.addPosition(displacement); boolean isLandscape = isNavBarOnLeft() || isNavBarOnRight(); float orthogonalDisplacement = !isLandscape ? ev.getX() - mDownPos.x : ev.getY() - mDownPos.y; mMotionPauseDetector.addPosition(displacement, orthogonalDisplacement); } } break; Loading quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +21 −18 Original line number Diff line number Diff line Loading @@ -478,6 +478,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { SyncRtSurfaceTransactionApplierCompat.create(mRecentsView, (applier) -> { mSyncTransactionApplier = applier; }); mRecentsView.setEnableFreeScroll(false); mRecentsView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> { if (!mBgLongSwipeMode && !mIsGoingToHome) { updateFinalShift(); Loading Loading @@ -910,7 +911,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { Interpolator interpolator = DEACCEL; final int nextPage = mRecentsView != null ? mRecentsView.getNextPage() : -1; final int runningTaskIndex = mRecentsView != null ? mRecentsView.getRunningTaskIndex() : -1; boolean goingToNewTask = mRecentsView != null && nextPage != runningTaskIndex; boolean goingToNewTask = mRecentsView != null && nextPage != runningTaskIndex && mRecentsView.getTaskViewAt(nextPage) != null; final boolean reachedOverviewThreshold = currentShift >= MIN_PROGRESS_FOR_OVERVIEW; if (!isFling) { if (SWIPE_HOME.get()) { Loading @@ -922,7 +924,11 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { endTarget = currentShift < MIN_PROGRESS_FOR_OVERVIEW ? LAST_TASK : HOME; } } else { endTarget = reachedOverviewThreshold && mGestureStarted ? RECENTS : LAST_TASK; endTarget = reachedOverviewThreshold && mGestureStarted ? RECENTS : goingToNewTask ? NEW_TASK : LAST_TASK; } endShift = endTarget.endShift; long expectedDuration = Math.abs(Math.round((endShift - currentShift) Loading @@ -932,7 +938,9 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { interpolator = endTarget == RECENTS ? OVERSHOOT_1_2 : DEACCEL; } else { if (SWIPE_HOME.get() && endVelocity < 0 && !mIsShelfPeeking) { endTarget = HOME; // If swiping at a diagonal, base end target on the faster velocity. endTarget = goingToNewTask && Math.abs(velocityX) > Math.abs(endVelocity) ? NEW_TASK : HOME; } else if (endVelocity < 0 && (!goingToNewTask || reachedOverviewThreshold)) { // If user scrolled to a new task, only go to recents if they already passed // the overview threshold. Otherwise, we'll snap to the new task and launch it. Loading Loading @@ -970,27 +978,21 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { duration = Math.max(MIN_OVERSHOOT_DURATION, duration); } else if (endTarget == RECENTS) { mRecentsAnimationWrapper.enableTouchProxy(); if (mRecentsView != null) { duration = Math.max(duration, mRecentsView.getScroller().getDuration()); } if (SWIPE_HOME.get()) { setShelfState(ShelfAnimState.OVERVIEW, interpolator, duration); } } else if (endTarget == NEW_TASK) { // We aren't goingToRecents, and user scrolled/flung to a new task; snap to the closest // task in that direction and launch it (in startNewTask()). int taskToLaunch = runningTaskIndex + (nextPage > runningTaskIndex ? 1 : -1); if (taskToLaunch >= mRecentsView.getTaskViewCount()) { // Let RecentsView handle the scrolling to the task, which we launch in startNewTask(). if (mRecentsView != null) { duration = Math.max(duration, mRecentsView.getScroller().getDuration()); } } else if (endTarget == LAST_TASK) { if (mRecentsView != null && nextPage != runningTaskIndex) { // Scrolled to Clear all button, snap back to current task and resume it. mRecentsView.snapToPage(runningTaskIndex, Math.toIntExact(duration)); goingToNewTask = false; } else { float distance = Math.abs(mRecentsView.getScrollForPage(taskToLaunch) - mRecentsView.getScrollX()); int durationX = (int) Math.abs(distance / velocityXPxPerMs); if (durationX > MAX_SWIPE_DURATION) { durationX = Math.toIntExact(MAX_SWIPE_DURATION); } interpolator = Interpolators.scrollInterpolatorForVelocity(velocityXPxPerMs); mRecentsView.snapToPage(taskToLaunch, durationX, interpolator); duration = Math.max(duration, durationX); } } animateToProgress(startShift, endShift, duration, interpolator, endTarget, velocityPxPerMs); Loading Loading @@ -1195,6 +1197,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { mLayoutListener.finish(); mActivityControlHelper.getAlphaProperty(mActivity).setValue(1); mRecentsView.setEnableFreeScroll(true); mRecentsView.setRunningTaskIconScaledDown(false); mRecentsView.setOnScrollChangeListener(null); mQuickScrubController.cancelActiveQuickscrub(); Loading quickstep/src/com/android/quickstep/util/MotionPauseDetector.java +35 −5 Original line number Diff line number Diff line Loading @@ -36,12 +36,15 @@ public class MotionPauseDetector { private final float mSpeedSomewhatFast; private final float mSpeedFast; private final float mMinDisplacementForPause; private final float mMaxOrthogonalDisplacementForPause; 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; Loading @@ -54,6 +57,8 @@ public class MotionPauseDetector { 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); mMaxOrthogonalDisplacementForPause = res.getDimension( R.dimen.motion_pause_detector_max_orthogonal_displacement); } /** Loading @@ -70,20 +75,26 @@ public class MotionPauseDetector { /** * 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) { public void addPosition(float position, float orthogonalPosition) { if (mFirstPosition == null) { mFirstPosition = position; } if (mFirstOrthogonalPosition == null) { mFirstOrthogonalPosition = orthogonalPosition; } long time = SystemClock.uptimeMillis(); if (mPreviousTime != null && mPreviousPosition != null) { long changeInTime = Math.max(1, time - mPreviousTime); float changeInPosition = position - mPreviousPosition; float velocity = changeInPosition / changeInTime; if (mPreviousVelocity != null) { checkMotionPaused(velocity, mPreviousVelocity, Math.abs(position - mFirstPosition)); mTotalDisplacement.set(Math.abs(position - mFirstPosition), Math.abs(orthogonalPosition - mFirstOrthogonalPosition)); checkMotionPaused(velocity, mPreviousVelocity, mTotalDisplacement); } mPreviousVelocity = velocity; } Loading @@ -91,7 +102,8 @@ public class MotionPauseDetector { mPreviousPosition = position; } private void checkMotionPaused(float velocity, float prevVelocity, float totalDisplacement) { private void checkMotionPaused(float velocity, float prevVelocity, TotalDisplacement totalDisplacement) { float speed = Math.abs(velocity); float previousSpeed = Math.abs(prevVelocity); boolean isPaused; Loading @@ -113,8 +125,10 @@ public class MotionPauseDetector { } } } boolean passedMinDisplacement = totalDisplacement >= mMinDisplacementForPause; isPaused &= passedMinDisplacement; boolean passedMinDisplacement = totalDisplacement.primary >= mMinDisplacementForPause; boolean passedMaxOrthogonalDisplacement = totalDisplacement.orthogonal >= mMaxOrthogonalDisplacementForPause; isPaused &= passedMinDisplacement && !passedMaxOrthogonalDisplacement; if (mIsPaused != isPaused) { mIsPaused = isPaused; if (mIsPaused) { Loading @@ -131,6 +145,8 @@ public class MotionPauseDetector { mPreviousPosition = null; mPreviousVelocity = null; mFirstPosition = null; mFirstOrthogonalPosition = null; mTotalDisplacement.set(0, 0); setOnMotionPauseListener(null); mIsPaused = mHasEverBeenPaused = false; } Loading @@ -142,4 +158,18 @@ 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; } } } Loading
quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/FlingAndHoldTouchController.java +1 −1 Original line number Diff line number Diff line Loading @@ -57,7 +57,7 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { @Override public boolean onDrag(float displacement) { mMotionPauseDetector.addPosition(displacement); mMotionPauseDetector.addPosition(displacement, 0); return super.onDrag(displacement); } Loading
quickstep/res/values/dimens.xml +1 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ <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_max_orthogonal_displacement">48dp</dimen> <!-- Launcher app transition --> <dimen name="content_trans_y">50dp</dimen> Loading
quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java +5 −1 Original line number Diff line number Diff line Loading @@ -201,7 +201,11 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC dispatchMotion(ev, displacement - mStartDisplacement, null); if (FeatureFlags.SWIPE_HOME.get()) { mMotionPauseDetector.addPosition(displacement); boolean isLandscape = isNavBarOnLeft() || isNavBarOnRight(); float orthogonalDisplacement = !isLandscape ? ev.getX() - mDownPos.x : ev.getY() - mDownPos.y; mMotionPauseDetector.addPosition(displacement, orthogonalDisplacement); } } break; Loading
quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +21 −18 Original line number Diff line number Diff line Loading @@ -478,6 +478,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { SyncRtSurfaceTransactionApplierCompat.create(mRecentsView, (applier) -> { mSyncTransactionApplier = applier; }); mRecentsView.setEnableFreeScroll(false); mRecentsView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> { if (!mBgLongSwipeMode && !mIsGoingToHome) { updateFinalShift(); Loading Loading @@ -910,7 +911,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { Interpolator interpolator = DEACCEL; final int nextPage = mRecentsView != null ? mRecentsView.getNextPage() : -1; final int runningTaskIndex = mRecentsView != null ? mRecentsView.getRunningTaskIndex() : -1; boolean goingToNewTask = mRecentsView != null && nextPage != runningTaskIndex; boolean goingToNewTask = mRecentsView != null && nextPage != runningTaskIndex && mRecentsView.getTaskViewAt(nextPage) != null; final boolean reachedOverviewThreshold = currentShift >= MIN_PROGRESS_FOR_OVERVIEW; if (!isFling) { if (SWIPE_HOME.get()) { Loading @@ -922,7 +924,11 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { endTarget = currentShift < MIN_PROGRESS_FOR_OVERVIEW ? LAST_TASK : HOME; } } else { endTarget = reachedOverviewThreshold && mGestureStarted ? RECENTS : LAST_TASK; endTarget = reachedOverviewThreshold && mGestureStarted ? RECENTS : goingToNewTask ? NEW_TASK : LAST_TASK; } endShift = endTarget.endShift; long expectedDuration = Math.abs(Math.round((endShift - currentShift) Loading @@ -932,7 +938,9 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { interpolator = endTarget == RECENTS ? OVERSHOOT_1_2 : DEACCEL; } else { if (SWIPE_HOME.get() && endVelocity < 0 && !mIsShelfPeeking) { endTarget = HOME; // If swiping at a diagonal, base end target on the faster velocity. endTarget = goingToNewTask && Math.abs(velocityX) > Math.abs(endVelocity) ? NEW_TASK : HOME; } else if (endVelocity < 0 && (!goingToNewTask || reachedOverviewThreshold)) { // If user scrolled to a new task, only go to recents if they already passed // the overview threshold. Otherwise, we'll snap to the new task and launch it. Loading Loading @@ -970,27 +978,21 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { duration = Math.max(MIN_OVERSHOOT_DURATION, duration); } else if (endTarget == RECENTS) { mRecentsAnimationWrapper.enableTouchProxy(); if (mRecentsView != null) { duration = Math.max(duration, mRecentsView.getScroller().getDuration()); } if (SWIPE_HOME.get()) { setShelfState(ShelfAnimState.OVERVIEW, interpolator, duration); } } else if (endTarget == NEW_TASK) { // We aren't goingToRecents, and user scrolled/flung to a new task; snap to the closest // task in that direction and launch it (in startNewTask()). int taskToLaunch = runningTaskIndex + (nextPage > runningTaskIndex ? 1 : -1); if (taskToLaunch >= mRecentsView.getTaskViewCount()) { // Let RecentsView handle the scrolling to the task, which we launch in startNewTask(). if (mRecentsView != null) { duration = Math.max(duration, mRecentsView.getScroller().getDuration()); } } else if (endTarget == LAST_TASK) { if (mRecentsView != null && nextPage != runningTaskIndex) { // Scrolled to Clear all button, snap back to current task and resume it. mRecentsView.snapToPage(runningTaskIndex, Math.toIntExact(duration)); goingToNewTask = false; } else { float distance = Math.abs(mRecentsView.getScrollForPage(taskToLaunch) - mRecentsView.getScrollX()); int durationX = (int) Math.abs(distance / velocityXPxPerMs); if (durationX > MAX_SWIPE_DURATION) { durationX = Math.toIntExact(MAX_SWIPE_DURATION); } interpolator = Interpolators.scrollInterpolatorForVelocity(velocityXPxPerMs); mRecentsView.snapToPage(taskToLaunch, durationX, interpolator); duration = Math.max(duration, durationX); } } animateToProgress(startShift, endShift, duration, interpolator, endTarget, velocityPxPerMs); Loading Loading @@ -1195,6 +1197,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { mLayoutListener.finish(); mActivityControlHelper.getAlphaProperty(mActivity).setValue(1); mRecentsView.setEnableFreeScroll(true); mRecentsView.setRunningTaskIconScaledDown(false); mRecentsView.setOnScrollChangeListener(null); mQuickScrubController.cancelActiveQuickscrub(); Loading
quickstep/src/com/android/quickstep/util/MotionPauseDetector.java +35 −5 Original line number Diff line number Diff line Loading @@ -36,12 +36,15 @@ public class MotionPauseDetector { private final float mSpeedSomewhatFast; private final float mSpeedFast; private final float mMinDisplacementForPause; private final float mMaxOrthogonalDisplacementForPause; 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; Loading @@ -54,6 +57,8 @@ public class MotionPauseDetector { 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); mMaxOrthogonalDisplacementForPause = res.getDimension( R.dimen.motion_pause_detector_max_orthogonal_displacement); } /** Loading @@ -70,20 +75,26 @@ public class MotionPauseDetector { /** * 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) { public void addPosition(float position, float orthogonalPosition) { if (mFirstPosition == null) { mFirstPosition = position; } if (mFirstOrthogonalPosition == null) { mFirstOrthogonalPosition = orthogonalPosition; } long time = SystemClock.uptimeMillis(); if (mPreviousTime != null && mPreviousPosition != null) { long changeInTime = Math.max(1, time - mPreviousTime); float changeInPosition = position - mPreviousPosition; float velocity = changeInPosition / changeInTime; if (mPreviousVelocity != null) { checkMotionPaused(velocity, mPreviousVelocity, Math.abs(position - mFirstPosition)); mTotalDisplacement.set(Math.abs(position - mFirstPosition), Math.abs(orthogonalPosition - mFirstOrthogonalPosition)); checkMotionPaused(velocity, mPreviousVelocity, mTotalDisplacement); } mPreviousVelocity = velocity; } Loading @@ -91,7 +102,8 @@ public class MotionPauseDetector { mPreviousPosition = position; } private void checkMotionPaused(float velocity, float prevVelocity, float totalDisplacement) { private void checkMotionPaused(float velocity, float prevVelocity, TotalDisplacement totalDisplacement) { float speed = Math.abs(velocity); float previousSpeed = Math.abs(prevVelocity); boolean isPaused; Loading @@ -113,8 +125,10 @@ public class MotionPauseDetector { } } } boolean passedMinDisplacement = totalDisplacement >= mMinDisplacementForPause; isPaused &= passedMinDisplacement; boolean passedMinDisplacement = totalDisplacement.primary >= mMinDisplacementForPause; boolean passedMaxOrthogonalDisplacement = totalDisplacement.orthogonal >= mMaxOrthogonalDisplacementForPause; isPaused &= passedMinDisplacement && !passedMaxOrthogonalDisplacement; if (mIsPaused != isPaused) { mIsPaused = isPaused; if (mIsPaused) { Loading @@ -131,6 +145,8 @@ public class MotionPauseDetector { mPreviousPosition = null; mPreviousVelocity = null; mFirstPosition = null; mFirstOrthogonalPosition = null; mTotalDisplacement.set(0, 0); setOnMotionPauseListener(null); mIsPaused = mHasEverBeenPaused = false; } Loading @@ -142,4 +158,18 @@ 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; } } }