Merge changes I37a9dd3e,I6a386626 into ub-launcher3-master
* changes:
Don't start task from quickswitch until scrolling finishes
Fix flicker near end of quick switch
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
index ea5561b..da73bc0 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -166,6 +166,7 @@
super.onActivityInit(alreadyOnHome);
mActivity = mActivityInterface.getCreatedActivity();
mRecentsView = mActivity.getOverviewPanel();
+ mRecentsView.setOnPageTransitionEndCallback(null);
linkRecentsViewScroll();
mRecentsView.setDisallowScrollToClearAll(true);
mRecentsView.getClearAllButton().setVisibilityAlpha(0);
@@ -434,7 +435,12 @@
@Override
public void onAnimationSuccess(Animator animator) {
- finishAnimationTargetSetAnimationComplete();
+ if (mRecentsView != null) {
+ mRecentsView.setOnPageTransitionEndCallback(FallbackSwipeHandler.this
+ ::finishAnimationTargetSetAnimationComplete);
+ } else {
+ finishAnimationTargetSetAnimationComplete();
+ }
mFinishAnimation = null;
}
};
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
index 5bac844..804bc95 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
@@ -29,6 +29,7 @@
import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK;
import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINISHED;
+import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.HIDE;
@@ -244,7 +245,11 @@
| STATE_GESTURE_STARTED,
this::setupLauncherUiAfterSwipeUpToRecentsAnimation);
- mGestureState.runOnceAtState(STATE_END_TARGET_ANIMATION_FINISHED, this::onEndTargetSet);
+ mGestureState.runOnceAtState(STATE_END_TARGET_ANIMATION_FINISHED,
+ this::continueComputingRecentsScrollIfNecessary);
+ mGestureState.runOnceAtState(STATE_END_TARGET_ANIMATION_FINISHED
+ | STATE_RECENTS_SCROLLING_FINISHED,
+ this::onSettledOnEndTarget);
mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED, this::invalidateHandler);
mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
@@ -283,6 +288,7 @@
}
mRecentsView = activity.getOverviewPanel();
+ mRecentsView.setOnPageTransitionEndCallback(null);
linkRecentsViewScroll();
addLiveTileOverlay();
@@ -505,16 +511,22 @@
}
private void buildAnimationController() {
- if (mGestureState.getEndTarget() == HOME || mHasLauncherTransitionControllerStarted) {
- // We don't want a new mLauncherTransitionController if
- // mGestureState.getEndTarget() == HOME (it has its own animation) or if we're already
- // animating the current controller.
+ if (!canCreateNewOrUpdateExistingLauncherTransitionController()) {
return;
}
initTransitionEndpoints(mActivity.getDeviceProfile());
mAnimationFactory.createActivityInterface(mTransitionDragLength);
}
+ /**
+ * We don't want to change mLauncherTransitionController if mGestureState.getEndTarget() == HOME
+ * (it has its own animation) or if we're already animating the current controller.
+ * @return Whether we can create the launcher controller or update its progress.
+ */
+ private boolean canCreateNewOrUpdateExistingLauncherTransitionController() {
+ return mGestureState.getEndTarget() != HOME && !mHasLauncherTransitionControllerStarted;
+ }
+
@Override
public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
WindowInsets result = view.onApplyWindowInsets(windowInsets);
@@ -558,15 +570,12 @@
}
}
- if (mLauncherTransitionController == null || mLauncherTransitionController
- .getAnimationPlayer().isStarted()) {
- return;
- }
updateLauncherTransitionProgress();
}
private void updateLauncherTransitionProgress() {
- if (mGestureState.getEndTarget() == HOME) {
+ if (mLauncherTransitionController == null
+ || !canCreateNewOrUpdateExistingLauncherTransitionController()) {
return;
}
// Normalize the progress to 0 to 1, as the animation controller will clamp it to that
@@ -696,7 +705,7 @@
}
}
- private void onEndTargetSet() {
+ private void onSettledOnEndTarget() {
switch (mGestureState.getEndTarget()) {
case HOME:
mStateCallback.setState(STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT);
@@ -859,13 +868,17 @@
if (mDeviceState.isFullyGesturalNavMode()) {
setShelfState(ShelfAnimState.OVERVIEW, interpolator, duration);
}
- } else if (endTarget == NEW_TASK || endTarget == LAST_TASK) {
- // Let RecentsView handle the scrolling to the task, which we launch in startNewTask()
- // or resumeLastTask().
- if (mRecentsView != null) {
- duration = Math.max(duration, mRecentsView.getScroller().getDuration());
- }
}
+
+ // Let RecentsView handle the scrolling to the task, which we launch in startNewTask()
+ // or resumeLastTask().
+ if (mRecentsView != null) {
+ mRecentsView.setOnPageTransitionEndCallback(
+ () -> mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED));
+ } else {
+ mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED);
+ }
+
animateToProgress(startShift, endShift, duration, interpolator, endTarget, velocityPxPerMs);
}
@@ -949,11 +962,7 @@
ValueAnimator windowAnim = mCurrentShift.animateToValue(start, end);
windowAnim.setDuration(duration).setInterpolator(interpolator);
windowAnim.addUpdateListener(valueAnimator -> {
- if (mRecentsView != null && mRecentsView.getVisibility() != View.VISIBLE) {
- // Views typically don't compute scroll when invisible as an optimization,
- // but in our case we need to since the window offset depends on the scroll.
- mRecentsView.computeScroll();
- }
+ computeRecentsScrollIfInvisible();
});
windowAnim.addListener(new AnimationSuccessListener() {
@Override
@@ -1005,6 +1014,21 @@
mHasLauncherTransitionControllerStarted = true;
}
+ private void computeRecentsScrollIfInvisible() {
+ if (mRecentsView != null && mRecentsView.getVisibility() != View.VISIBLE) {
+ // Views typically don't compute scroll when invisible as an optimization,
+ // but in our case we need to since the window offset depends on the scroll.
+ mRecentsView.computeScroll();
+ }
+ }
+
+ private void continueComputingRecentsScrollIfNecessary() {
+ if (!mGestureState.hasState(STATE_RECENTS_SCROLLING_FINISHED)) {
+ computeRecentsScrollIfInvisible();
+ mRecentsView.post(this::continueComputingRecentsScrollIfNecessary);
+ }
+ }
+
/**
* Creates an animation that transforms the current app window into the home app.
* @param startProgress The progress of {@link #mCurrentShift} to start the window from.
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index f7e40ca..631df4c 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -105,6 +105,10 @@
public static final int STATE_RECENTS_ANIMATION_ENDED =
getFlagForIndex("STATE_RECENTS_ANIMATION_ENDED");
+ // Called when RecentsView stops scrolling and settles on a TaskView.
+ public static final int STATE_RECENTS_SCROLLING_FINISHED =
+ getFlagForIndex("STATE_RECENTS_SCROLLING_FINISHED");
+
// Needed to interact with the current activity
private final Intent mHomeIntent;
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index e38631d..7d7739e 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -50,6 +50,8 @@
import static com.android.launcher3.touch.PagedOrientationHandler.VIEW_SCROLL_BY;
import static com.android.launcher3.touch.PagedOrientationHandler.VIEW_SCROLL_TO;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
@@ -133,6 +135,7 @@
protected int mActivePointerId = INVALID_POINTER;
protected boolean mIsPageInTransition = false;
+ private Runnable mOnPageTransitionEndCallback;
protected float mSpringOverScroll;
@@ -391,6 +394,22 @@
AccessibilityManagerCompat.sendScrollFinishedEventToTest(getContext());
AccessibilityManagerCompat.sendCustomAccessibilityEvent(getPageAt(mCurrentPage),
AccessibilityEvent.TYPE_VIEW_FOCUSED, null);
+ if (mOnPageTransitionEndCallback != null) {
+ mOnPageTransitionEndCallback.run();
+ mOnPageTransitionEndCallback = null;
+ }
+ }
+
+ /**
+ * Sets a callback to run once when the scrolling finishes. If there is currently
+ * no page in transition, then the callback is called immediately.
+ */
+ public void setOnPageTransitionEndCallback(@Nullable Runnable callback) {
+ if (mIsPageInTransition || callback == null) {
+ mOnPageTransitionEndCallback = callback;
+ } else {
+ callback.run();
+ }
}
protected int getUnboundedScroll() {
diff --git a/src/com/android/launcher3/util/OverScroller.java b/src/com/android/launcher3/util/OverScroller.java
index 3c398b8..34efb12 100644
--- a/src/com/android/launcher3/util/OverScroller.java
+++ b/src/com/android/launcher3/util/OverScroller.java
@@ -165,6 +165,9 @@
/**
* Returns how long the scroll event will take, in milliseconds.
*
+ * Note that if mScroller.mState == SPRING, this duration is ignored, so can only
+ * serve as an estimate for how long the spring-controlled scroll will take.
+ *
* @return The duration of the scroll in milliseconds.
*/
public final int getDuration() {