Merge "Translate recents when attaching to app window instead of fading" into ub-launcher3-qt-dev
am: 0234edeb08
Change-Id: I0d4d559518d8202a40957a3c5c1e90ed72745a66
This commit is contained in:
+81
-17
@@ -16,16 +16,23 @@
|
||||
package com.android.quickstep;
|
||||
|
||||
import static android.view.View.TRANSLATION_Y;
|
||||
|
||||
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
|
||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.LauncherStateManager.ANIM_ALL;
|
||||
import static com.android.launcher3.allapps.AllAppsTransitionController.SPRING_DAMPING_RATIO;
|
||||
import static com.android.launcher3.allapps.AllAppsTransitionController.SPRING_STIFFNESS;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.INSTANT;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.quickstep.WindowTransformSwipeHandler.RECENTS_ATTACH_DURATION;
|
||||
|
||||
import static androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY;
|
||||
import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
@@ -44,14 +51,18 @@ import android.view.animation.Interpolator;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.dynamicanimation.animation.SpringAnimation;
|
||||
import androidx.dynamicanimation.animation.SpringForce;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherInitListenerEx;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.LauncherStateManager;
|
||||
import com.android.launcher3.allapps.DiscoveryBounce;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.AnimatorSetBuilder;
|
||||
import com.android.launcher3.anim.SpringObjectAnimator;
|
||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
@@ -99,6 +110,13 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
DiscoveryBounce.showForOverviewIfNeeded(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwipeUpToHomeComplete(Launcher activity) {
|
||||
// Ensure recents is at the correct position for NORMAL state. For example, when we detach
|
||||
// recents, we assume the first task is invisible, making translation off by one task.
|
||||
activity.getStateManager().reapplyState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAssistantVisibilityChanged(float visibility) {
|
||||
Launcher launcher = getCreatedActivity();
|
||||
@@ -156,18 +174,23 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
public AnimatorPlaybackController createActivityAnimationToHome() {
|
||||
// Return an empty APC here since we have an non-user controlled animation to home.
|
||||
long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
|
||||
AnimatorSet as = new AnimatorSet();
|
||||
as.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
activity.getStateManager().goToState(NORMAL, false);
|
||||
}
|
||||
});
|
||||
return AnimatorPlaybackController.wrap(as, accuracy);
|
||||
return activity.getStateManager().createAnimationToNewWorkspace(NORMAL, accuracy,
|
||||
0 /* animComponents */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playAtomicAnimation(float velocity) {
|
||||
// Setup workspace with 0 duration to prepare for our staggered animation.
|
||||
LauncherStateManager stateManager = activity.getStateManager();
|
||||
AnimatorSetBuilder builder = new AnimatorSetBuilder();
|
||||
// setRecentsAttachedToAppWindow() will animate recents out.
|
||||
builder.addFlag(AnimatorSetBuilder.FLAG_DONT_ANIMATE_OVERVIEW);
|
||||
stateManager.createAtomicAnimation(BACKGROUND_APP, NORMAL, builder, ANIM_ALL, 0);
|
||||
builder.build().start();
|
||||
|
||||
// Stop scrolling so that it doesn't interfere with the translation offscreen.
|
||||
recentsView.getScroller().forceFinished(true);
|
||||
|
||||
new StaggeredWorkspaceAnim(activity, workspaceView, velocity).start();
|
||||
}
|
||||
};
|
||||
@@ -201,7 +224,8 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
return new AnimationFactory() {
|
||||
private Animator mShelfAnim;
|
||||
private ShelfAnimState mShelfState;
|
||||
private Animator mAttachToWindowAnim;
|
||||
private Animator mAttachToWindowFadeAnim;
|
||||
private SpringAnimation mAttachToWindowTranslationXAnim;
|
||||
private boolean mIsAttachedToWindow;
|
||||
|
||||
@Override
|
||||
@@ -267,20 +291,60 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
return;
|
||||
}
|
||||
mIsAttachedToWindow = attached;
|
||||
if (mAttachToWindowAnim != null) {
|
||||
mAttachToWindowAnim.cancel();
|
||||
if (mAttachToWindowFadeAnim != null) {
|
||||
mAttachToWindowFadeAnim.cancel();
|
||||
}
|
||||
mAttachToWindowAnim = ObjectAnimator.ofFloat(activity.getOverviewPanel(),
|
||||
RecentsView recentsView = activity.getOverviewPanel();
|
||||
mAttachToWindowFadeAnim = ObjectAnimator.ofFloat(recentsView,
|
||||
RecentsView.CONTENT_ALPHA, attached ? 1 : 0);
|
||||
mAttachToWindowAnim.addListener(new AnimatorListenerAdapter() {
|
||||
|
||||
int runningTaskIndex = recentsView.getRunningTaskIndex();
|
||||
if (runningTaskIndex == 0) {
|
||||
// If we are on the first task (we haven't quick switched), translate recents in
|
||||
// from the side. Calculate the start translation based on current scale/scroll.
|
||||
float currScale = recentsView.getScaleX();
|
||||
float scrollOffsetX = recentsView.getScrollOffset();
|
||||
|
||||
float offscreenX = NORMAL.getOverviewScaleAndTranslation(activity).translationX;
|
||||
// The first task is hidden, so offset by its width.
|
||||
int firstTaskWidth = recentsView.getTaskViewAt(0).getWidth();
|
||||
offscreenX -= (firstTaskWidth + recentsView.getPageSpacing()) * currScale;
|
||||
// Offset since scale pushes tasks outwards.
|
||||
offscreenX += firstTaskWidth * (currScale - 1) / 2;
|
||||
offscreenX = Math.max(0, offscreenX);
|
||||
if (recentsView.isRtl()) {
|
||||
offscreenX = -offscreenX;
|
||||
}
|
||||
|
||||
float fromTranslationX = attached ? offscreenX - scrollOffsetX : 0;
|
||||
float toTranslationX = attached ? 0 : offscreenX - scrollOffsetX;
|
||||
if (mAttachToWindowTranslationXAnim == null) {
|
||||
mAttachToWindowTranslationXAnim = new SpringAnimation(recentsView,
|
||||
SpringAnimation.TRANSLATION_X).setSpring(new SpringForce()
|
||||
.setDampingRatio(DAMPING_RATIO_LOW_BOUNCY)
|
||||
.setStiffness(STIFFNESS_LOW));
|
||||
}
|
||||
if (!recentsView.isShown() && animate) {
|
||||
recentsView.setTranslationX(fromTranslationX);
|
||||
mAttachToWindowTranslationXAnim.setStartValue(fromTranslationX);
|
||||
}
|
||||
mAttachToWindowTranslationXAnim.animateToFinalPosition(toTranslationX);
|
||||
if (!animate && mAttachToWindowTranslationXAnim.canSkipToEnd()) {
|
||||
mAttachToWindowTranslationXAnim.skipToEnd();
|
||||
}
|
||||
|
||||
mAttachToWindowFadeAnim.setInterpolator(attached ? INSTANT : ACCEL_2);
|
||||
} else {
|
||||
mAttachToWindowFadeAnim.setInterpolator(ACCEL_DEACCEL);
|
||||
}
|
||||
mAttachToWindowFadeAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mAttachToWindowAnim = null;
|
||||
mAttachToWindowFadeAnim = null;
|
||||
}
|
||||
});
|
||||
mAttachToWindowAnim.setInterpolator(ACCEL_DEACCEL);
|
||||
mAttachToWindowAnim.setDuration(animate ? RECENTS_ATTACH_DURATION : 0);
|
||||
mAttachToWindowAnim.start();
|
||||
mAttachToWindowFadeAnim.setDuration(animate ? RECENTS_ATTACH_DURATION : 0);
|
||||
mAttachToWindowFadeAnim.start();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+14
-16
@@ -21,7 +21,6 @@ import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
|
||||
import static com.android.launcher3.Utilities.postAsyncCallback;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
@@ -218,7 +217,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
Math.min(1 / MIN_PROGRESS_FOR_OVERVIEW, 1 / (1 - MIN_PROGRESS_FOR_OVERVIEW));
|
||||
private static final String SCREENSHOT_CAPTURED_EVT = "ScreenshotCaptured";
|
||||
|
||||
private static final long SHELF_ANIM_DURATION = 120;
|
||||
private static final long SHELF_ANIM_DURATION = 240;
|
||||
public static final long RECENTS_ATTACH_DURATION = 300;
|
||||
|
||||
// Start resisting when swiping past this factor of mTransitionDragLength.
|
||||
@@ -602,7 +601,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
}
|
||||
|
||||
public void onMotionPauseChanged(boolean isPaused) {
|
||||
setShelfState(isPaused ? PEEK : HIDE, FAST_OUT_SLOW_IN, SHELF_ANIM_DURATION);
|
||||
setShelfState(isPaused ? PEEK : HIDE, OVERSHOOT_1_2, SHELF_ANIM_DURATION);
|
||||
}
|
||||
|
||||
public void maybeUpdateRecentsAttachedState() {
|
||||
@@ -625,7 +624,10 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
: mRecentsAnimationWrapper.targetSet.findTask(mRunningTaskId);
|
||||
final boolean recentsAttachedToAppWindow;
|
||||
int runningTaskIndex = mRecentsView.getRunningTaskIndex();
|
||||
if (mContinuingLastGesture) {
|
||||
if (mGestureEndTarget != null) {
|
||||
recentsAttachedToAppWindow = mGestureEndTarget.recentsAttachedToAppWindow;
|
||||
} else if (mContinuingLastGesture
|
||||
&& mRecentsView.getRunningTaskIndex() != mRecentsView.getNextPage()) {
|
||||
recentsAttachedToAppWindow = true;
|
||||
animate = false;
|
||||
} else if (runningTaskTarget != null && isNotInRecents(runningTaskTarget)) {
|
||||
@@ -633,17 +635,16 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
recentsAttachedToAppWindow = true;
|
||||
animate = false;
|
||||
} else {
|
||||
if (mGestureEndTarget != null) {
|
||||
recentsAttachedToAppWindow = mGestureEndTarget.recentsAttachedToAppWindow;
|
||||
} else {
|
||||
recentsAttachedToAppWindow = mIsShelfPeeking || mIsLikelyToStartNewTask;
|
||||
}
|
||||
recentsAttachedToAppWindow = mIsShelfPeeking || mIsLikelyToStartNewTask;
|
||||
if (animate) {
|
||||
// Only animate if an adjacent task view is visible on screen.
|
||||
TaskView adjacentTask1 = mRecentsView.getTaskViewAt(runningTaskIndex + 1);
|
||||
TaskView adjacentTask2 = mRecentsView.getTaskViewAt(runningTaskIndex - 1);
|
||||
float prevTranslationX = mRecentsView.getTranslationX();
|
||||
mRecentsView.setTranslationX(0);
|
||||
animate = (adjacentTask1 != null && adjacentTask1.getGlobalVisibleRect(TEMP_RECT))
|
||||
|| (adjacentTask2 != null && adjacentTask2.getGlobalVisibleRect(TEMP_RECT));
|
||||
mRecentsView.setTranslationX(prevTranslationX);
|
||||
}
|
||||
}
|
||||
mAnimationFactory.setRecentsAttachedToAppWindow(recentsAttachedToAppWindow, animate);
|
||||
@@ -701,13 +702,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
|
||||
SwipeAnimationTargetSet controller = mRecentsAnimationWrapper.getController();
|
||||
if (controller != null) {
|
||||
float offsetX = 0;
|
||||
if (mRecentsView != null) {
|
||||
int startScroll = mRecentsView.getScrollForPage(mRecentsView.indexOfChild(
|
||||
mRecentsView.getRunningTaskView()));
|
||||
offsetX = startScroll - mRecentsView.getScrollX();
|
||||
offsetX *= mRecentsView.getScaleX();
|
||||
}
|
||||
float offsetX = mRecentsView == null ? 0 : mRecentsView.getScrollOffset();
|
||||
float offsetScale = getTaskCurveScaleForOffsetX(offsetX,
|
||||
mClipAnimationHelper.getTargetRect().width());
|
||||
mTransformParams.setProgress(shift).setOffsetX(offsetX).setOffsetScale(offsetScale);
|
||||
@@ -1217,6 +1212,9 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
if (mRecentsView != null) {
|
||||
mRecentsView.post(mRecentsView::resetTaskVisuals);
|
||||
}
|
||||
// Make sure recents is in its final state
|
||||
maybeUpdateRecentsAttachedState(false);
|
||||
mActivityControlHelper.onSwipeUpToHomeComplete(mActivity);
|
||||
}
|
||||
});
|
||||
return anim;
|
||||
|
||||
@@ -1676,6 +1676,16 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
return mClearAllButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return How many pixels the running task is offset on the x-axis due to the current scrollX.
|
||||
*/
|
||||
public float getScrollOffset() {
|
||||
int startScroll = getScrollForPage(getRunningTaskIndex());
|
||||
int offsetX = startScroll - getScrollX();
|
||||
offsetX *= getScaleX();
|
||||
return offsetX;
|
||||
}
|
||||
|
||||
public Consumer<MotionEvent> getEventDispatcher(RotationMode rotationMode) {
|
||||
if (rotationMode.isTransposed) {
|
||||
Matrix transform = new Matrix();
|
||||
|
||||
@@ -53,6 +53,7 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
|
||||
|
||||
void onSwipeUpToRecentsComplete(T activity);
|
||||
|
||||
default void onSwipeUpToHomeComplete(T activity) { }
|
||||
void onAssistantVisibilityChanged(float visibility);
|
||||
|
||||
@NonNull HomeAnimationFactory prepareHomeUI(T activity);
|
||||
|
||||
Reference in New Issue
Block a user