diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java index 61684e0188..7f9d3a183f 100644 --- a/quickstep/src/com/android/quickstep/QuickScrubController.java +++ b/quickstep/src/com/android/quickstep/QuickScrubController.java @@ -32,6 +32,7 @@ public class QuickScrubController implements OnAlarmListener { private static final int NUM_QUICK_SCRUB_SECTIONS = 5; private static final long AUTO_ADVANCE_DELAY = 500; + private static final int QUICKSCRUB_SNAP_DURATION_PER_PAGE = 325; private static final int QUICKSCRUB_END_SNAP_DURATION_PER_PAGE = 60; private Launcher mLauncher; @@ -58,18 +59,22 @@ public class QuickScrubController implements OnAlarmListener { if (mRecentsView == null) { } else { int page = mRecentsView.getNextPage(); - // Settle on the page then launch it. - int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen()) - * QUICKSCRUB_END_SNAP_DURATION_PER_PAGE; - mRecentsView.snapToPage(page, snapDuration); - // TODO: Fix this to actually wait until page-settle - mRecentsView.postDelayed(() -> { + Runnable launchTaskRunnable = () -> { if (page < mRecentsView.getFirstTaskIndex()) { mRecentsView.getPageAt(page).performClick(); } else { ((TaskView) mRecentsView.getPageAt(page)).launchTask(true); } - }, snapDuration); + }; + int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen()) + * QUICKSCRUB_END_SNAP_DURATION_PER_PAGE; + if (mRecentsView.snapToPage(page, snapDuration)) { + // Settle on the page then launch it + mRecentsView.setNextPageSwitchRunnable(launchTaskRunnable); + } else { + // No page move needed, just launch it + launchTaskRunnable.run(); + } } } @@ -93,7 +98,9 @@ public class QuickScrubController implements OnAlarmListener { private void goToPageWithHaptic(int pageToGoTo) { if (pageToGoTo != mRecentsView.getNextPage()) { - mRecentsView.snapToPage(pageToGoTo); + int duration = Math.abs(pageToGoTo - mRecentsView.getNextPage()) + * QUICKSCRUB_SNAP_DURATION_PER_PAGE; + mRecentsView.snapToPage(pageToGoTo, duration); mRecentsView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); } diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java index 26fe54eaa4..6b1f3d3bed 100644 --- a/quickstep/src/com/android/quickstep/RecentsView.java +++ b/quickstep/src/com/android/quickstep/RecentsView.java @@ -75,6 +75,7 @@ public class RecentsView extends PagedView implements Insettable { private boolean mOverviewStateEnabled; private boolean mTaskStackListenerRegistered; private LayoutTransition mLayoutTransition; + private Runnable mNextPageSwitchRunnable; /** * TODO: Call reloadIdNeeded in onTaskStackChanged. @@ -243,6 +244,19 @@ public class RecentsView extends PagedView implements Insettable { updateTaskStackListenerState(); } + public void setNextPageSwitchRunnable(Runnable r) { + mNextPageSwitchRunnable = r; + } + + @Override + protected void onPageEndTransition() { + super.onPageEndTransition(); + if (mNextPageSwitchRunnable != null) { + mNextPageSwitchRunnable.run(); + mNextPageSwitchRunnable = null; + } + } + private void applyLoadPlan(RecentsTaskLoadPlan loadPlan) { final RecentsTaskLoader loader = mModel.getRecentsTaskLoader(); TaskStack stack = loadPlan != null ? loadPlan.getTaskStack() : null; diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java index 17f0482e7c..dd0892ba33 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -41,6 +41,7 @@ import android.os.Handler; import android.os.Looper; import android.support.annotation.UiThread; import android.support.annotation.WorkerThread; +import android.util.Log; import android.view.View; import android.view.ViewTreeObserver.OnDrawListener; @@ -65,8 +66,12 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.TransactionCompat; import com.android.systemui.shared.system.WindowManagerWrapper; +import java.util.StringJoiner; + @TargetApi(Build.VERSION_CODES.O) public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { + private static final String TAG = WindowTransformSwipeHandler.class.getSimpleName(); + private static final boolean DEBUG_STATES = false; // Launcher UI related states private static final int STATE_LAUNCHER_PRESENT = 1 << 0; @@ -86,8 +91,21 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { private static final int LAUNCHER_UI_STATES = STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_ACTIVITY_MULTIPLIER_COMPLETE; + // For debugging, keep in sync with above states + private static final String[] STATES = new String[] { + "STATE_LAUNCHER_PRESENT", + "STATE_LAUNCHER_DRAWN", + "STATE_ACTIVITY_MULTIPLIER_COMPLETE", + "STATE_APP_CONTROLLER_RECEIVED", + "STATE_SCALED_CONTROLLER_RECENTS", + "STATE_SCALED_CONTROLLER_APP", + "STATE_HANDLER_INVALIDATED", + "STATE_GESTURE_STARTED" + }; + private static final long MAX_SWIPE_DURATION = 200; private static final long MIN_SWIPE_DURATION = 80; + private static final int QUICK_SWITCH_START_DURATION = 133; private static final int QUICK_SWITCH_SNAP_DURATION = 120; private static final float MIN_PROGRESS_FOR_OVERVIEW = 0.5f; @@ -154,7 +172,13 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { } private void initStateCallbacks() { - mStateCallback = new MultiStateCallback(); + mStateCallback = new MultiStateCallback() { + @Override + public void setState(int stateFlag) { + debugNewState(stateFlag); + super.setState(stateFlag); + } + }; mStateCallback.addCallback(STATE_LAUNCHER_DRAWN | STATE_GESTURE_STARTED, this::initializeLauncherAnimationController); mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN, @@ -356,7 +380,7 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { mDeferredQuickScrubEnd = false; mQuickScrubController = mRecentsView.getQuickScrubController(); mQuickScrubController.onQuickScrubStart(mStartedQuickScrubFromHome); - animateToProgress(1f, MAX_SWIPE_DURATION); + animateToProgress(1f, QUICK_SWITCH_START_DURATION); if (mStartedQuickScrubFromHome) { mLauncherLayoutListener.setVisibility(View.INVISIBLE); } @@ -599,9 +623,14 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) { TaskView taskView = (TaskView) mRecentsView.getPageAt(i); if (taskView.getTask().key.id != mRunningTaskId) { - mRecentsView.snapToPage(i, QUICK_SWITCH_SNAP_DURATION); - taskView.postDelayed(() -> {taskView.launchTask(true);}, - QUICK_SWITCH_SNAP_DURATION); + Runnable launchTaskRunnable = () -> taskView.launchTask(true); + if (mRecentsView.snapToPage(i, QUICK_SWITCH_SNAP_DURATION)) { + // Snap to the new page then launch it + mRecentsView.setNextPageSwitchRunnable(launchTaskRunnable); + } else { + // No need to move page, just launch task directly + launchTaskRunnable.run(); + } break; } } @@ -655,4 +684,24 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { // TODO: } } + + private synchronized void debugNewState(int stateFlag) { + if (!DEBUG_STATES) { + return; + } + + int state = mStateCallback.getState(); + StringJoiner currentStateStr = new StringJoiner(", ", "[", "]"); + String stateFlagStr = "Unknown-" + stateFlag; + for (int i = 0; i < STATES.length; i++) { + if ((state & (i << i)) != 0) { + currentStateStr.add(STATES[i]); + } + if (stateFlag == (1 << i)) { + stateFlagStr = STATES[i] + " (" + stateFlag + ")"; + } + } + Log.d(TAG, "[" + System.identityHashCode(this) + "] Adding " + stateFlagStr + " to " + + currentStateStr); + } } diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 0ebae81356..bb137b0d6d 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -1622,7 +1622,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc return (float) Math.sin(f); } - protected void snapToPageWithVelocity(int whichPage, int velocity) { + protected boolean snapToPageWithVelocity(int whichPage, int velocity) { whichPage = validateNewPage(whichPage); int halfScreenSize = getMeasuredWidth() / 2; @@ -1633,8 +1633,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc if (Math.abs(velocity) < mMinFlingVelocity) { // If the velocity is low enough, then treat this more as an automatic page advance // as opposed to an apparent physical response to flinging - snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION); - return; + return snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION); } // Here we compute a "distance" that will be used in the computation of the overall @@ -1653,39 +1652,39 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // interpolator at zero, ie. 5. We use 4 to make it a little slower. duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); - snapToPage(whichPage, delta, duration); + return snapToPage(whichPage, delta, duration); } - public void snapToPage(int whichPage) { - snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION); + public boolean snapToPage(int whichPage) { + return snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION); } - public void snapToPageImmediately(int whichPage) { - snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION, true, null); + public boolean snapToPageImmediately(int whichPage) { + return snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION, true, null); } - public void snapToPage(int whichPage, int duration) { - snapToPage(whichPage, duration, false, null); + public boolean snapToPage(int whichPage, int duration) { + return snapToPage(whichPage, duration, false, null); } - protected void snapToPage(int whichPage, int duration, TimeInterpolator interpolator) { - snapToPage(whichPage, duration, false, interpolator); + protected boolean snapToPage(int whichPage, int duration, TimeInterpolator interpolator) { + return snapToPage(whichPage, duration, false, interpolator); } - protected void snapToPage(int whichPage, int duration, boolean immediate, + protected boolean snapToPage(int whichPage, int duration, boolean immediate, TimeInterpolator interpolator) { whichPage = validateNewPage(whichPage); int newX = getScrollForPage(whichPage); final int delta = newX - getUnboundedScrollX(); - snapToPage(whichPage, delta, duration, immediate, interpolator); + return snapToPage(whichPage, delta, duration, immediate, interpolator); } - protected void snapToPage(int whichPage, int delta, int duration) { - snapToPage(whichPage, delta, duration, false, null); + protected boolean snapToPage(int whichPage, int delta, int duration) { + return snapToPage(whichPage, delta, duration, false, null); } - protected void snapToPage(int whichPage, int delta, int duration, boolean immediate, + protected boolean snapToPage(int whichPage, int delta, int duration, boolean immediate, TimeInterpolator interpolator) { whichPage = validateNewPage(whichPage); @@ -1723,6 +1722,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } invalidate(); + return Math.abs(delta) > 0; } public void scrollLeft() {