Fix launching app animation from launcher all apps.

This cl includes
	- making pinned taskbar animate slide in/out animation from bottom of screen.
        - no icon aligment with hotseat when taksbar is pinned

The solution
	- upon state change applied on TaskbarLauncherStateController. offset taskbar background and icons to bottom of screeen and animate with slide in/out effects.

Test: manual, presubmit
Bug: 314279101
Flag: EXEMPT bugfix

Change-Id: Ife336ebd57eb2f60c2bc33ed6a4527c42111808f
This commit is contained in:
Jagrut Desai
2024-11-14 15:51:50 -08:00
parent 6f10fb57a4
commit 596594c684
9 changed files with 130 additions and 27 deletions
@@ -214,6 +214,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
public static final int CONTENT_ALPHA_DURATION = 217;
public static final int TRANSIENT_TASKBAR_TRANSITION_DURATION = 417;
public static final int PINNED_TASKBAR_TRANSITION_DURATION = 600;
public static final int TASKBAR_TO_APP_DURATION = 600;
// TODO(b/236145847): Tune TASKBAR_TO_HOME_DURATION to 383 after conflict with unlock animation
// is solved.
@@ -1726,8 +1727,21 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
return new AnimatorBackState(rectFSpringAnim, anim);
}
public static int getTaskbarToHomeDuration() {
if (enableScalingRevealHomeAnimation()) {
/** Get animation duration for taskbar for going to home. */
public static int getTaskbarToHomeDuration(boolean isPinnedTaskbar) {
return getTaskbarToHomeDuration(false, isPinnedTaskbar);
}
/**
* Get animation duration for taskbar for going to home.
*
* @param shouldOverrideToFastAnimation should overwrite scaling reveal home animation duration
*/
public static int getTaskbarToHomeDuration(boolean shouldOverrideToFastAnimation,
boolean isPinnedTaskbar) {
if (isPinnedTaskbar) {
return PINNED_TASKBAR_TRANSITION_DURATION;
} else if (enableScalingRevealHomeAnimation() && !shouldOverrideToFastAnimation) {
return TASKBAR_TO_HOME_DURATION_SLOW;
} else {
return TASKBAR_TO_HOME_DURATION_FAST;
@@ -210,8 +210,12 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
}
private int getTaskbarAnimationDuration(boolean isVisible) {
if (isVisible && !mLauncher.getPredictiveBackToHomeInProgress()) {
return getTaskbarToHomeDuration();
// fast animation duration since we will not be playing workspace reveal animation.
boolean shouldOverrideToFastAnimation =
!isHotseatIconOnTopWhenAligned() || mLauncher.getPredictiveBackToHomeInProgress();
boolean isPinnedTaskbar = DisplayController.isPinnedTaskbar(mLauncher);
if (isVisible || isPinnedTaskbar) {
return getTaskbarToHomeDuration(shouldOverrideToFastAnimation, isPinnedTaskbar);
} else {
return DisplayController.isTransientTaskbar(mLauncher)
? TRANSIENT_TASKBAR_TRANSITION_DURATION
@@ -17,6 +17,7 @@ package com.android.launcher3.taskbar;
import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.app.animation.Interpolators.FINAL_FRAME;
import static com.android.app.animation.Interpolators.INSTANT;
import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.Hotseat.ALPHA_CHANNEL_TASKBAR_ALIGNMENT;
import static com.android.launcher3.Hotseat.ALPHA_CHANNEL_TASKBAR_STASH;
@@ -222,7 +223,9 @@ public class TaskbarLauncherStateController {
updateStateForFlag(FLAG_LAUNCHER_IN_STATE_TRANSITION, true);
if (!mShouldDelayLauncherStateAnim) {
if (toState == LauncherState.NORMAL) {
applyState(QuickstepTransitionManager.getTaskbarToHomeDuration());
applyState(QuickstepTransitionManager.getTaskbarToHomeDuration(
DisplayController.isPinnedTaskbar(
mControllers.taskbarActivityContext)));
} else {
applyState();
}
@@ -459,9 +462,12 @@ public class TaskbarLauncherStateController {
private Animator onStateChangeApplied(int changedFlags, long duration, boolean start) {
final boolean isInLauncher = isInLauncher();
final boolean isInOverview = mControllers.uiController.isInOverviewUi();
final boolean isIconAlignedWithHotseat = isIconAlignedWithHotseat();
final float toAlignment = isIconAlignedWithHotseat ? 1 : 0;
boolean handleOpenFloatingViews = false;
boolean isPinnedTaskbar = DisplayController.isPinnedTaskbar(
mControllers.taskbarActivityContext);
if (DEBUG) {
Log.d(TAG, "onStateChangeApplied - isInLauncher: " + isInLauncher
+ ", mLauncherState: " + mLauncherState
@@ -573,10 +579,17 @@ public class TaskbarLauncherStateController {
}
float backgroundAlpha = isInLauncher && isTaskbarAlignedWithHotseat() ? 0 : 1;
AnimatedFloat taskbarBgOffset =
mControllers.taskbarDragLayerController.getTaskbarBackgroundOffset();
boolean showTaskbar = !isInLauncher || isInOverview;
float taskbarBgOffsetEnd = showTaskbar ? 0f : 1f;
float taskbarBgOffsetStart = showTaskbar ? 1f : 0f;
// Don't animate if background has reached desired value.
if (mTaskbarBackgroundAlpha.isAnimating()
|| mTaskbarBackgroundAlpha.value != backgroundAlpha) {
|| mTaskbarBackgroundAlpha.value != backgroundAlpha
|| taskbarBgOffset.isAnimatingToValue(taskbarBgOffsetStart)
|| taskbarBgOffset.value != taskbarBgOffsetEnd) {
mTaskbarBackgroundAlpha.cancelAnimation();
if (DEBUG) {
Log.d(TAG, "onStateChangeApplied - taskbarBackgroundAlpha - "
@@ -587,25 +600,35 @@ public class TaskbarLauncherStateController {
boolean isInLauncherIconNotAligned = isInLauncher && !isIconAlignedWithHotseat;
boolean notInLauncherIconNotAligned = !isInLauncher && !isIconAlignedWithHotseat;
boolean isInLauncherIconIsAligned = isInLauncher && isIconAlignedWithHotseat;
// When Hotseat icons are not on top don't change duration or add start delay.
// This will keep the duration in sync for icon alignment and background fade in/out.
// For example, launching app from launcher all apps.
boolean isHotseatIconOnTopWhenAligned =
mControllers.uiController.isHotseatIconOnTopWhenAligned();
float startDelay = 0;
// We want to delay the background from fading in so that the icons have time to move
// into the bounds of the background before it appears.
if (isInLauncherIconNotAligned) {
startDelay = duration * TASKBAR_BG_ALPHA_LAUNCHER_NOT_ALIGNED_DELAY_MULT;
} else if (notInLauncherIconNotAligned) {
} else if (notInLauncherIconNotAligned && isHotseatIconOnTopWhenAligned) {
startDelay = duration * TASKBAR_BG_ALPHA_NOT_LAUNCHER_NOT_ALIGNED_DELAY_MULT;
}
float newDuration = duration - startDelay;
if (isInLauncherIconIsAligned) {
if (isInLauncherIconIsAligned && isHotseatIconOnTopWhenAligned) {
// Make the background fade out faster so that it is gone by the time the
// icons move outside of the bounds of the background.
newDuration = duration * TASKBAR_BG_ALPHA_LAUNCHER_IS_ALIGNED_DURATION_MULT;
}
Animator taskbarBackgroundAlpha = mTaskbarBackgroundAlpha
.animateToValue(backgroundAlpha)
.setDuration((long) newDuration);
taskbarBackgroundAlpha.setStartDelay((long) startDelay);
Animator taskbarBackgroundAlpha = mTaskbarBackgroundAlpha.animateToValue(
backgroundAlpha);
if (isPinnedTaskbar) {
setupPinnedTaskbarAnimation(animatorSet, showTaskbar, taskbarBgOffset,
taskbarBgOffsetStart, taskbarBgOffsetEnd, duration, taskbarBackgroundAlpha);
} else {
taskbarBackgroundAlpha.setDuration((long) newDuration);
taskbarBackgroundAlpha.setStartDelay((long) startDelay);
}
animatorSet.play(taskbarBackgroundAlpha);
}
@@ -671,15 +694,18 @@ public class TaskbarLauncherStateController {
+ mIconAlignment.value
+ " -> " + toAlignment + ": " + duration);
}
if (hasAnyFlag(FLAG_TASKBAR_HIDDEN)) {
iconAlignAnim.setInterpolator(FINAL_FRAME);
} else {
animatorSet.play(iconAlignAnim);
if (!isPinnedTaskbar) {
if (hasAnyFlag(FLAG_TASKBAR_HIDDEN)) {
iconAlignAnim.setInterpolator(FINAL_FRAME);
} else {
animatorSet.play(iconAlignAnim);
}
}
}
Interpolator interpolator = enableScalingRevealHomeAnimation()
Interpolator interpolator = enableScalingRevealHomeAnimation() && !isPinnedTaskbar
? ScalingWorkspaceRevealAnim.SCALE_INTERPOLATOR : EMPHASIZED;
animatorSet.setInterpolator(interpolator);
if (start) {
@@ -688,6 +714,49 @@ public class TaskbarLauncherStateController {
return animatorSet;
}
private void setupPinnedTaskbarAnimation(AnimatorSet animatorSet, boolean showTaskbar,
AnimatedFloat taskbarBgOffset, float taskbarBgOffsetStart, float taskbarBgOffsetEnd,
long duration, Animator taskbarBackgroundAlpha) {
float targetAlpha = !showTaskbar ? 1 : 0;
mLauncher.getHotseat().setIconsAlpha(targetAlpha, ALPHA_CHANNEL_TASKBAR_ALIGNMENT);
if (mIsQsbInline) {
mLauncher.getHotseat().setQsbAlpha(targetAlpha,
ALPHA_CHANNEL_TASKBAR_ALIGNMENT);
}
if ((taskbarBgOffset.value != taskbarBgOffsetEnd && !taskbarBgOffset.isAnimating())
|| taskbarBgOffset.isAnimatingToValue(taskbarBgOffsetStart)) {
taskbarBgOffset.cancelAnimation();
Animator taskbarIconAlpha = mTaskbarAlphaForHome.animateToValue(
showTaskbar ? 1f : 0f);
AnimatedFloat taskbarIconTranslationYForHome =
mControllers.taskbarViewController.mTaskbarIconTranslationYForHome;
ObjectAnimator taskbarBackgroundOffset = taskbarBgOffset.animateToValue(
taskbarBgOffsetStart,
taskbarBgOffsetEnd);
ObjectAnimator taskbarIconsYTranslation = null;
float taskbarHeight =
mControllers.taskbarActivityContext.getDeviceProfile().taskbarHeight;
if (showTaskbar) {
taskbarIconsYTranslation = taskbarIconTranslationYForHome.animateToValue(
taskbarHeight, 0);
} else {
taskbarIconsYTranslation = taskbarIconTranslationYForHome.animateToValue(0,
taskbarHeight);
}
taskbarIconAlpha.setDuration(duration);
taskbarIconsYTranslation.setDuration(duration);
taskbarBackgroundOffset.setDuration(duration);
animatorSet.play(taskbarIconAlpha);
animatorSet.play(taskbarIconsYTranslation);
animatorSet.play(taskbarBackgroundOffset);
}
taskbarBackgroundAlpha.setInterpolator(showTaskbar ? INSTANT : FINAL_FRAME);
taskbarBackgroundAlpha.setDuration(duration);
}
/**
* Whether the taskbar is aligned with the hotseat in the current/target launcher state.
*
@@ -950,8 +1019,9 @@ public class TaskbarLauncherStateController {
*
* @param finishedToApp {@code true} if the recents animation finished to showing an app and
* not workspace or overview
* @param canceled {@code true} if the recents animation was canceled instead of finishing
* to completion
* @param canceled {@code true} if the recents animation was canceled instead of
* finishing
* to completion
*/
private void endGestureStateOverride(boolean finishedToApp, boolean canceled) {
mCallbacks.removeListener(this);
@@ -968,6 +1038,7 @@ public class TaskbarLauncherStateController {
/**
* Updates the visible state immediately to ensure a seamless handoff.
*
* @param finishedToApp True iff user is in an app.
*/
private void updateStateForUserFinishedToApp(boolean finishedToApp) {
@@ -23,6 +23,7 @@ import static com.android.app.animation.Interpolators.INSTANT;
import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.internal.jank.InteractionJankMonitor.Configuration;
import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.QuickstepTransitionManager.PINNED_TASKBAR_TRANSITION_DURATION;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TRANSIENT_TASKBAR_HIDE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TRANSIENT_TASKBAR_SHOW;
@@ -398,6 +399,9 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
* Returns how long the stash/unstash animation should play.
*/
public long getStashDuration() {
if (DisplayController.isPinnedTaskbar(mActivity)) {
return PINNED_TASKBAR_TRANSITION_DURATION;
}
return DisplayController.isTransientTaskbar(mActivity)
? TRANSIENT_TASKBAR_STASH_DURATION
: TASKBAR_STASH_DURATION;
@@ -120,7 +120,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
private final TaskbarView mTaskbarView;
private final MultiValueAlpha mTaskbarIconAlpha;
private final AnimatedFloat mTaskbarIconScaleForStash = new AnimatedFloat(this::updateScale);
private final AnimatedFloat mTaskbarIconTranslationYForHome = new AnimatedFloat(
public final AnimatedFloat mTaskbarIconTranslationYForHome = new AnimatedFloat(
this::updateTranslationY);
private final AnimatedFloat mTaskbarIconTranslationYForStash = new AnimatedFloat(
this::updateTranslationY);
@@ -796,6 +796,8 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
*/
private AnimatorPlaybackController createIconAlignmentController(DeviceProfile launcherDp) {
PendingAnimation setter = new PendingAnimation(100);
// icon alignment not needed for pinned taskbar.
if (DisplayController.isPinnedTaskbar(mActivity)) return setter.createPlaybackController();
mOnControllerPreCreateCallback.run();
DeviceProfile taskbarDp = mActivity.getDeviceProfile();
Rect hotseatPadding = launcherDp.getHotseatLayoutPadding(mActivity);
@@ -95,6 +95,7 @@ public class QuickstepAtomicAnimationFactory extends
public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toState,
StateAnimationConfig config) {
RecentsView overview = mContainer.getOverviewPanel();
boolean isPinnedTaskbar = DisplayController.isPinnedTaskbar(mContainer);
if ((fromState == OVERVIEW || fromState == OVERVIEW_SPLIT_SELECT) && toState == NORMAL) {
overview.switchToScreenshot(() ->
overview.finishRecentsAnimation(true /* toRecents */, null));
@@ -109,7 +110,8 @@ public class QuickstepAtomicAnimationFactory extends
// We sync the scrim fade with the taskbar animation duration to avoid any flickers for
// taskbar icons disappearing before hotseat icons show up.
float scrimUpperBoundFromSplit =
QuickstepTransitionManager.getTaskbarToHomeDuration() / (float) config.duration;
QuickstepTransitionManager.getTaskbarToHomeDuration(isPinnedTaskbar)
/ (float) config.duration;
scrimUpperBoundFromSplit = Math.min(scrimUpperBoundFromSplit, 1f);
config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, clampToProgress(LINEAR, 0, 0.25f));
config.setInterpolator(ANIM_SCRIM_FADE,
@@ -139,7 +141,8 @@ public class QuickstepAtomicAnimationFactory extends
// Sync scroll so that it ends before or at the same time as the taskbar animation.
if (mContainer.getDeviceProfile().isTaskbarPresent) {
config.duration = Math.min(
config.duration, QuickstepTransitionManager.getTaskbarToHomeDuration());
config.duration,
QuickstepTransitionManager.getTaskbarToHomeDuration(isPinnedTaskbar));
}
overview.snapToPage(DEFAULT_PAGE, Math.toIntExact(config.duration));
} else {
@@ -100,6 +100,7 @@ import com.android.internal.jank.Cuj;
import com.android.internal.util.LatencyTracker;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
@@ -1373,8 +1374,9 @@ public abstract class AbsSwipeUpHandler<
mInputConsumerProxy.enable();
}
if (endTarget == HOME) {
boolean isPinnedTaskbar = DisplayController.isPinnedTaskbar(mContext);
duration = mContainer != null && mContainer.getDeviceProfile().isTaskbarPresent
? StaggeredWorkspaceAnim.DURATION_TASKBAR_MS
? QuickstepTransitionManager.getTaskbarToHomeDuration(isPinnedTaskbar)
: StaggeredWorkspaceAnim.DURATION_MS;
ContextualEduStatsManager.INSTANCE.get(mContext).updateEduStats(
mGestureState.isTrackpadGesture(), GestureType.HOME);
@@ -49,6 +49,7 @@ import com.android.launcher3.celllayout.CellLayoutLayoutParams;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DynamicResource;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.plugins.ResourceProvider;
@@ -63,8 +64,7 @@ public class StaggeredWorkspaceAnim {
private static final int APP_CLOSE_ROW_START_DELAY_MS = 10;
// Should be used for animations running alongside this StaggeredWorkspaceAnim.
public static final int DURATION_MS = 250;
public static final int DURATION_TASKBAR_MS =
QuickstepTransitionManager.getTaskbarToHomeDuration();
private final int mTaskbarDurationInMs;
private static final float MAX_VELOCITY_PX_PER_S = 22f;
@@ -81,6 +81,8 @@ public class StaggeredWorkspaceAnim {
public StaggeredWorkspaceAnim(QuickstepLauncher launcher, float velocity,
boolean animateOverviewScrim, @Nullable View ignoredView, boolean staggerWorkspace) {
mTaskbarDurationInMs = QuickstepTransitionManager.getTaskbarToHomeDuration(
DisplayController.isPinnedTaskbar(launcher));
prepareToAnimate(launcher, animateOverviewScrim);
mIgnoredView = ignoredView;
@@ -93,7 +95,7 @@ public class StaggeredWorkspaceAnim {
.getDimensionPixelSize(R.dimen.swipe_up_max_workspace_trans_y);
DeviceProfile grid = launcher.getDeviceProfile();
long duration = grid.isTaskbarPresent ? DURATION_TASKBAR_MS : DURATION_MS;
long duration = grid.isTaskbarPresent ? mTaskbarDurationInMs : DURATION_MS;
if (staggerWorkspace) {
Workspace<?> workspace = launcher.getWorkspace();
Hotseat hotseat = launcher.getHotseat();
@@ -21,6 +21,7 @@ import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
import com.android.launcher3.QuickstepTransitionManager.PINNED_TASKBAR_TRANSITION_DURATION
import com.android.launcher3.R
import com.android.launcher3.taskbar.StashedHandleViewController.ALPHA_INDEX_STASHED
import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_EDU_OPEN
@@ -158,7 +159,7 @@ class TaskbarStashControllerTest {
@Test
@TaskbarMode(PINNED)
fun testGetStashDuration_pinnedMode() {
assertThat(stashController.stashDuration).isEqualTo(TASKBAR_STASH_DURATION)
assertThat(stashController.stashDuration).isEqualTo(PINNED_TASKBAR_TRANSITION_DURATION)
}
@Test