Make sure animation properties are applied correctly for non-gestural transitions
- In TaskViewSimulator.addAppToCarouselAnim, make sure carouselScale stays at 1f when it's atomicEvent (3 button, KEYCODE_APP_SWITCH, keybaord etc,), as we transition direclty from fullscreen to Overview without involving the carousel - Made AnimatorSet pass to onPrepareGestureEndAnimation @NonNull, to avoid diverged code path handling null AnimatorSet. - For 3-button/Keyboard interactions, pass the gesture AnimatorSet with a boolean that indicates atomic event; some float peroperties will immediately settle while it's atomic: GRID_PROGRESS, TASK_THUMBNAIL_SPLASH_ALPHA - For home gesture, pass a new AnimatorSet that will be played immediately with 0 duration - Converted onPrepareGestureEndAnimation to Kotlin, and removed the code path when animatorSet is null - updateGridProperties is now called based on displayOverviewTasksAsGrid, which is effectively the same check as endTarget == GestureState.GestureEndTarget.RECENTS; - RECENTS_GRID_PROGRESS is no longer caleld per remoteTargetHandle, which duplicates the animaton for nothing, as it's a per recents rather than per task property Fix: 405384582 Fix: 407059929 Flag: EXEMPT bug fix Test: Swipe up/KEYCODE_APP_SWITCH/Recents button with default and 3p Launcher Change-Id: I56ba9137219f6d7cb982d8e5a3534f09ba3d189d
This commit is contained in:
@@ -1767,8 +1767,10 @@ public abstract class AbsSwipeUpHandler<
|
||||
mLauncherTransitionController = null;
|
||||
|
||||
if (mRecentsView != null) {
|
||||
mRecentsView.onPrepareGestureEndAnimation(null, mGestureState.getEndTarget(),
|
||||
mRemoteTargetHandles);
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
mRecentsView.onPrepareGestureEndAnimation(animatorSet, mGestureState.getEndTarget(),
|
||||
mRemoteTargetHandles, /* isHandlingAtomicEvent= */ true);
|
||||
animatorSet.setDuration(0).start();
|
||||
}
|
||||
} else {
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
@@ -1810,9 +1812,10 @@ public abstract class AbsSwipeUpHandler<
|
||||
animatorSet.play(windowAnim);
|
||||
if (mRecentsView != null) {
|
||||
mRecentsView.onPrepareGestureEndAnimation(
|
||||
mGestureState.isHandlingAtomicEvent() ? null : animatorSet,
|
||||
animatorSet,
|
||||
mGestureState.getEndTarget(),
|
||||
mRemoteTargetHandles);
|
||||
mRemoteTargetHandles,
|
||||
mGestureState.isHandlingAtomicEvent());
|
||||
}
|
||||
animatorSet.setDuration(duration).setInterpolator(interpolator);
|
||||
animatorSet.start();
|
||||
|
||||
@@ -120,7 +120,8 @@ public abstract class SwipeUpAnimationLogic implements
|
||||
PendingAnimation pendingAnimation = new PendingAnimation(mTransitionDragLength * 2);
|
||||
TaskViewSimulator taskViewSimulator = remoteHandle.getTaskViewSimulator();
|
||||
taskViewSimulator.setDp(dp);
|
||||
taskViewSimulator.addAppToCarouselAnim(pendingAnimation, LINEAR);
|
||||
taskViewSimulator.addAppToCarouselAnim(pendingAnimation, LINEAR,
|
||||
mGestureState.isHandlingAtomicEvent());
|
||||
AnimatorPlaybackController playbackController =
|
||||
pendingAnimation.createPlaybackController();
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import static com.android.quickstep.fallback.RecentsState.DEFAULT;
|
||||
import static com.android.quickstep.fallback.RecentsState.MODAL_TASK;
|
||||
import static com.android.quickstep.fallback.RecentsState.OVERVIEW_SPLIT_SELECT;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
@@ -134,9 +133,10 @@ public class FallbackRecentsView<CONTAINER_TYPE extends Context & RecentsViewCon
|
||||
*/
|
||||
@Override
|
||||
public void onPrepareGestureEndAnimation(
|
||||
@Nullable AnimatorSet animatorSet, GestureState.GestureEndTarget endTarget,
|
||||
RemoteTargetHandle[] remoteTargetHandles) {
|
||||
super.onPrepareGestureEndAnimation(animatorSet, endTarget, remoteTargetHandles);
|
||||
AnimatorSet animatorSet, GestureState.GestureEndTarget endTarget,
|
||||
RemoteTargetHandle[] remoteTargetHandles, boolean isHandlingAtomicEvent) {
|
||||
super.onPrepareGestureEndAnimation(animatorSet, endTarget, remoteTargetHandles,
|
||||
isHandlingAtomicEvent);
|
||||
if (mHomeTask != null && endTarget == RECENTS) {
|
||||
TaskView homeTaskView = getTaskViewByTaskId(mHomeTask.key.id);
|
||||
if (homeTaskView != null) {
|
||||
@@ -147,12 +147,7 @@ public class FallbackRecentsView<CONTAINER_TYPE extends Context & RecentsViewCon
|
||||
pendingAnimation.addEndListener(e -> setCurrentTask(-1));
|
||||
AnimatorPlaybackController controller = pendingAnimation.createPlaybackController();
|
||||
controller.dispatchOnStart();
|
||||
Animator homeDismissAnimator = controller.getAnimationPlayer();
|
||||
if (animatorSet != null) {
|
||||
animatorSet.play(homeDismissAnimator);
|
||||
} else {
|
||||
homeDismissAnimator.setDuration(0).start();
|
||||
}
|
||||
animatorSet.play(controller.getAnimationPlayer());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,9 +317,10 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
|
||||
/**
|
||||
* Adds animation for all the components corresponding to transition from an app to carousel.
|
||||
*/
|
||||
public void addAppToCarouselAnim(PendingAnimation pa, Interpolator interpolator) {
|
||||
public void addAppToCarouselAnim(PendingAnimation pa, Interpolator interpolator,
|
||||
boolean isHandlingAtomicEvent) {
|
||||
pa.addFloat(fullScreenProgress, AnimatedFloat.VALUE, 1, 0, interpolator);
|
||||
if (enableGridOnlyOverview() && mDp.isTablet && mDp.isGestureMode) {
|
||||
if (enableGridOnlyOverview() && mDp.isTablet && !isHandlingAtomicEvent) {
|
||||
mIsAnimatingToCarousel = true;
|
||||
carouselScale.value = mCarouselTaskSize.width() / (float) mFullTaskSize.width();
|
||||
}
|
||||
|
||||
@@ -2969,87 +2969,10 @@ public abstract class RecentsView<
|
||||
* Called when a gesture from an app has finished, and an end target has been determined.
|
||||
*/
|
||||
public void onPrepareGestureEndAnimation(
|
||||
@Nullable AnimatorSet animatorSet, GestureState.GestureEndTarget endTarget,
|
||||
RemoteTargetHandle[] remoteTargetHandles) {
|
||||
Log.d(TAG, "onPrepareGestureEndAnimation - endTarget: " + endTarget);
|
||||
mCurrentGestureEndTarget = endTarget;
|
||||
boolean isOverviewEndTarget = endTarget == GestureState.GestureEndTarget.RECENTS;
|
||||
if (isOverviewEndTarget) {
|
||||
updateGridProperties();
|
||||
}
|
||||
|
||||
BaseState<?> endState = mSizeStrategy.stateFromGestureEndTarget(endTarget);
|
||||
// Starting the desk exploded animation when the gesture from an app is released.
|
||||
if (enableDesktopExplodedView()) {
|
||||
if (animatorSet == null) {
|
||||
mUtils.setDeskExplodeProgress(endState.showExplodedDesktopView() ? 1f : 0f);
|
||||
} else {
|
||||
animatorSet.play(
|
||||
ObjectAnimator.ofFloat(this, DESK_EXPLODE_PROGRESS,
|
||||
endState.showExplodedDesktopView() ? 1f : 0f));
|
||||
}
|
||||
|
||||
for (TaskView taskView : getTaskViews()) {
|
||||
if (taskView instanceof DesktopTaskView desktopTaskView) {
|
||||
desktopTaskView.setRemoteTargetHandles(remoteTargetHandles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (endState.displayOverviewTasksAsGrid(mContainer.getDeviceProfile())) {
|
||||
TaskView runningTaskView = getRunningTaskView();
|
||||
float runningTaskGridTranslationX = 0;
|
||||
float runningTaskGridTranslationY = 0;
|
||||
if (runningTaskView != null) {
|
||||
// Apply the grid translation to running task unless it's being snapped to
|
||||
// and removes the current translation applied to the running task.
|
||||
runningTaskGridTranslationX = runningTaskView.getGridTranslationX()
|
||||
- runningTaskView.getNonGridTranslationX();
|
||||
runningTaskGridTranslationY = runningTaskView.getGridTranslationY();
|
||||
}
|
||||
for (RemoteTargetHandle remoteTargetHandle : remoteTargetHandles) {
|
||||
TaskViewSimulator tvs = remoteTargetHandle.getTaskViewSimulator();
|
||||
if (animatorSet == null) {
|
||||
setGridProgress(1);
|
||||
if (enableGridOnlyOverview()) {
|
||||
tvs.taskGridTranslationX.value = runningTaskGridTranslationX;
|
||||
tvs.taskGridTranslationY.value = runningTaskGridTranslationY;
|
||||
} else {
|
||||
tvs.taskPrimaryTranslation.value = runningTaskGridTranslationX;
|
||||
tvs.taskSecondaryTranslation.value = runningTaskGridTranslationY;
|
||||
}
|
||||
} else {
|
||||
animatorSet.play(ObjectAnimator.ofFloat(this, RECENTS_GRID_PROGRESS, 1));
|
||||
if (enableGridOnlyOverview()) {
|
||||
animatorSet.play(tvs.carouselScale.animateToValue(1));
|
||||
animatorSet.play(tvs.taskGridTranslationX.animateToValue(
|
||||
runningTaskGridTranslationX));
|
||||
animatorSet.play(tvs.taskGridTranslationY.animateToValue(
|
||||
runningTaskGridTranslationY));
|
||||
} else {
|
||||
animatorSet.play(tvs.taskPrimaryTranslation.animateToValue(
|
||||
runningTaskGridTranslationX));
|
||||
animatorSet.play(tvs.taskSecondaryTranslation.animateToValue(
|
||||
runningTaskGridTranslationY));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int splashAlpha = endState.showTaskThumbnailSplash() ? 1 : 0;
|
||||
if (animatorSet == null) {
|
||||
setTaskThumbnailSplashAlpha(splashAlpha);
|
||||
} else {
|
||||
animatorSet.play(
|
||||
ObjectAnimator.ofFloat(this, TASK_THUMBNAIL_SPLASH_ALPHA, splashAlpha));
|
||||
}
|
||||
if (enableLargeDesktopWindowingTile()) {
|
||||
if (animatorSet != null) {
|
||||
animatorSet.play(
|
||||
ObjectAnimator.ofFloat(this, DESKTOP_CAROUSEL_DETACH_PROGRESS, 0f));
|
||||
} else {
|
||||
DESKTOP_CAROUSEL_DETACH_PROGRESS.set(this, 0f);
|
||||
}
|
||||
}
|
||||
AnimatorSet animatorSet, GestureState.GestureEndTarget endTarget,
|
||||
RemoteTargetHandle[] remoteTargetHandles, boolean isHandlingAtomicEvent) {
|
||||
mUtils.onPrepareGestureEndAnimation(animatorSet, endTarget, remoteTargetHandles,
|
||||
isHandlingAtomicEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3298,7 +3221,7 @@ public abstract class RecentsView<
|
||||
*
|
||||
* Skips rebalance.
|
||||
*/
|
||||
private void updateGridProperties() {
|
||||
protected void updateGridProperties() {
|
||||
updateGridProperties(null);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
|
||||
package com.android.quickstep.views
|
||||
|
||||
import android.animation.AnimatorSet
|
||||
import android.animation.ObjectAnimator
|
||||
import android.graphics.PointF
|
||||
import android.graphics.Rect
|
||||
import android.util.FloatProperty
|
||||
import android.util.Log
|
||||
import android.util.Property
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import android.view.View.LAYOUT_DIRECTION_LTR
|
||||
@@ -27,6 +30,7 @@ import android.view.View.LAYOUT_DIRECTION_RTL
|
||||
import androidx.core.view.children
|
||||
import com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU
|
||||
import com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType
|
||||
import com.android.launcher3.Flags.enableDesktopExplodedView
|
||||
import com.android.launcher3.Flags.enableGridOnlyOverview
|
||||
import com.android.launcher3.Flags.enableLargeDesktopWindowingTile
|
||||
import com.android.launcher3.Flags.enableOverviewIconMenu
|
||||
@@ -34,14 +38,20 @@ import com.android.launcher3.Flags.enableSeparateExternalDisplayTasks
|
||||
import com.android.launcher3.Utilities.getPivotsForScalingRectToRect
|
||||
import com.android.launcher3.statehandlers.DesktopVisibilityController
|
||||
import com.android.launcher3.statehandlers.DesktopVisibilityController.Companion.INACTIVE_DESK_ID
|
||||
import com.android.launcher3.statemanager.BaseState
|
||||
import com.android.launcher3.util.IntArray
|
||||
import com.android.launcher3.util.window.WindowManagerProxy.DesktopVisibilityListener
|
||||
import com.android.quickstep.GestureState
|
||||
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle
|
||||
import com.android.quickstep.util.DesksUtils.Companion.areMultiDesksFlagsEnabled
|
||||
import com.android.quickstep.util.DesktopTask
|
||||
import com.android.quickstep.util.GroupTask
|
||||
import com.android.quickstep.util.isExternalDisplay
|
||||
import com.android.quickstep.views.RecentsView.DESKTOP_CAROUSEL_DETACH_PROGRESS
|
||||
import com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS
|
||||
import com.android.quickstep.views.RecentsView.RUNNING_TASK_ATTACH_ALPHA
|
||||
import com.android.quickstep.views.RecentsView.TAG
|
||||
import com.android.quickstep.views.RecentsView.TASK_THUMBNAIL_SPLASH_ALPHA
|
||||
import com.android.systemui.shared.recents.model.Task
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData
|
||||
import com.android.wm.shell.shared.GroupedTaskInfo
|
||||
@@ -563,6 +573,97 @@ class RecentsViewUtils(private val recentsView: RecentsView<*, *>) : DesktopVisi
|
||||
return matchingTaskView == null
|
||||
}
|
||||
|
||||
fun onPrepareGestureEndAnimation(
|
||||
animatorSet: AnimatorSet,
|
||||
endTarget: GestureState.GestureEndTarget,
|
||||
remoteTargetHandles: Array<RemoteTargetHandle>,
|
||||
isHandlingAtomicEvent: Boolean,
|
||||
) {
|
||||
// Create ObjectAnimator that immediately settles on [endStateValue] when
|
||||
// [isHandlingAtomicEvent] is true.
|
||||
fun <T> immediateObjectAnimator(
|
||||
target: T,
|
||||
property: Property<T, Float>,
|
||||
endStateValue: Float,
|
||||
) =
|
||||
if (isHandlingAtomicEvent)
|
||||
ObjectAnimator.ofFloat(target, property, endStateValue, endStateValue)
|
||||
else ObjectAnimator.ofFloat(target, property, endStateValue)
|
||||
|
||||
with(recentsView) {
|
||||
Log.d(TAG, "onPrepareGestureEndAnimation - endTarget: $endTarget")
|
||||
mCurrentGestureEndTarget = endTarget
|
||||
val endState: BaseState<*> = mSizeStrategy.stateFromGestureEndTarget(endTarget)
|
||||
|
||||
// Starting the desk exploded animation when the gesture from an app is released.
|
||||
if (enableDesktopExplodedView()) {
|
||||
animatorSet.play(
|
||||
ObjectAnimator.ofFloat(
|
||||
this,
|
||||
DESK_EXPLODE_PROGRESS,
|
||||
if (endState.showExplodedDesktopView()) 1f else 0f,
|
||||
)
|
||||
)
|
||||
taskViews.filterIsInstance<DesktopTaskView>().forEach {
|
||||
it.remoteTargetHandles = remoteTargetHandles
|
||||
}
|
||||
}
|
||||
|
||||
if (endState.displayOverviewTasksAsGrid(getDeviceProfile())) {
|
||||
updateGridProperties()
|
||||
animatorSet.play(immediateObjectAnimator(this, RECENTS_GRID_PROGRESS, 1f))
|
||||
|
||||
val runningTaskView = runningTaskView
|
||||
var runningTaskGridTranslationX = 0f
|
||||
var runningTaskGridTranslationY = 0f
|
||||
if (runningTaskView != null) {
|
||||
// Apply the grid translation to running task unless it's being snapped to
|
||||
// and removes the current translation applied to the running task.
|
||||
runningTaskGridTranslationX =
|
||||
(runningTaskView.gridTranslationX - runningTaskView.nonGridTranslationX)
|
||||
runningTaskGridTranslationY = runningTaskView.gridTranslationY
|
||||
}
|
||||
remoteTargetHandles.forEach { remoteTargetHandle ->
|
||||
val taskViewSimulator = remoteTargetHandle.taskViewSimulator
|
||||
if (enableGridOnlyOverview()) {
|
||||
animatorSet.play(taskViewSimulator.carouselScale.animateToValue(1f))
|
||||
animatorSet.play(
|
||||
taskViewSimulator.taskGridTranslationX.animateToValue(
|
||||
runningTaskGridTranslationX
|
||||
)
|
||||
)
|
||||
animatorSet.play(
|
||||
taskViewSimulator.taskGridTranslationY.animateToValue(
|
||||
runningTaskGridTranslationY
|
||||
)
|
||||
)
|
||||
} else {
|
||||
animatorSet.play(
|
||||
taskViewSimulator.taskPrimaryTranslation.animateToValue(
|
||||
runningTaskGridTranslationX
|
||||
)
|
||||
)
|
||||
animatorSet.play(
|
||||
taskViewSimulator.taskSecondaryTranslation.animateToValue(
|
||||
runningTaskGridTranslationY
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
animatorSet.play(
|
||||
immediateObjectAnimator(
|
||||
this,
|
||||
TASK_THUMBNAIL_SPLASH_ALPHA,
|
||||
if (endState.showTaskThumbnailSplash()) 1f else 0f,
|
||||
)
|
||||
)
|
||||
if (enableLargeDesktopWindowingTile()) {
|
||||
animatorSet.play(ObjectAnimator.ofFloat(this, DESKTOP_CAROUSEL_DETACH_PROGRESS, 0f))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
class RecentsViewFloatProperty(
|
||||
private val utilsProperty: KMutableProperty1<RecentsViewUtils, Float>
|
||||
|
||||
@@ -423,7 +423,7 @@ constructor(
|
||||
}
|
||||
|
||||
// The following grid translations scales with mGridProgress.
|
||||
protected var gridTranslationX = 0f
|
||||
var gridTranslationX = 0f
|
||||
set(value) {
|
||||
field = value
|
||||
applyTranslationX()
|
||||
@@ -444,7 +444,7 @@ constructor(
|
||||
|
||||
// Applied as a complement to gridTranslation, for adjusting the carousel overview and quick
|
||||
// switch.
|
||||
protected var nonGridTranslationX = 0f
|
||||
var nonGridTranslationX = 0f
|
||||
set(value) {
|
||||
field = value
|
||||
applyTranslationX()
|
||||
|
||||
Reference in New Issue
Block a user