From cd76ac24b682575410a07a26939ea22a8dd904b7 Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Tue, 8 Nov 2022 15:43:29 +0000 Subject: [PATCH] Fade in/out taskbar when launching apps from or back to AllApps/-1 - Added isHotseatIconTopWhenAligned to control both iconAlignment and stash animation to just fade in if hotseat icon isn't on top of the screen in the aligned state Fix: 257355864 Fix: 213455090 Test: Launch apps from/back to home, taskbar animate from/to hotseat Test: Launch apps from/back to AllApps/-1, taskbar fade in/out Test: Repeat aboth with transient or persistent taskbar Change-Id: I6bdae615ff9e199d23cbfe2d26c8d46a08fbc436 --- .../launcher3/QuickstepTransitionManager.java | 4 + .../taskbar/LauncherTaskbarUIController.java | 6 ++ .../TaskbarLauncherStateController.java | 15 +++- .../taskbar/TaskbarStashController.java | 27 +++++- .../taskbar/TaskbarUIController.java | 7 ++ .../taskbar/TaskbarViewController.java | 88 ++++++++++++------- 6 files changed, 110 insertions(+), 37 deletions(-) diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index 59dbd4b9e5..2aa0af4113 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -482,6 +482,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener final View appsView = mLauncher.getAppsView(); final float startAlpha = appsView.getAlpha(); final float startScale = SCALE_PROPERTY.get(appsView); + if (mDeviceProfile.isTablet) { + // AllApps should not fade at all in tablets. + alphas = new float[]{1, 1}; + } appsView.setAlpha(alphas[0]); ObjectAnimator alpha = ObjectAnimator.ofFloat(appsView, View.ALPHA, alphas); diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index 87753594fe..02206cea74 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -355,6 +355,12 @@ public class LauncherTaskbarUIController extends TaskbarUIController { return mTaskbarLauncherStateController.isIconAlignedWithHotseat(); } + @Override + public boolean isHotseatIconOnTopWhenAligned() { + return mTaskbarLauncherStateController.isInHotseatOnTopStates() + && getInAppDisplayProgress(MINUS_ONE_PAGE_PROGRESS_INDEX) == 0; + } + @Override public void dumpLogs(String prefix, PrintWriter pw) { super.dumpLogs(prefix, pw); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index d790b4b663..b74dd21d03 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -385,6 +385,13 @@ import java.util.StringJoiner; } } + /** + * Returns if the current Launcher state has hotseat on top of other elemnets. + */ + public boolean isInHotseatOnTopStates() { + return mLauncherState != LauncherState.ALL_APPS; + } + private void playStateTransitionAnim(AnimatorSet animatorSet, long duration, boolean committed) { boolean isInStashedState = mLauncherState.isTaskbarStashed(mLauncher); @@ -438,14 +445,16 @@ import java.util.StringJoiner; private void updateIconAlphaForHome(float alpha) { mIconAlphaForHome.setValue(alpha); - + boolean hotseatVisible = alpha == 0 + || (!mControllers.uiController.isHotseatIconOnTopWhenAligned() + && mIconAlignment.value > 0); /* * Hide Launcher Hotseat icons when Taskbar icons have opacity. Both icon sets * should not be visible at the same time. */ - mLauncher.getHotseat().setIconsAlpha(alpha > 0 ? 0 : 1); + mLauncher.getHotseat().setIconsAlpha(hotseatVisible ? 1 : 0); mLauncher.getHotseat().setQsbAlpha( - mLauncher.getDeviceProfile().isQsbInline && alpha > 0 ? 0 : 1); + mLauncher.getDeviceProfile().isQsbInline && !hotseatVisible ? 0 : 1); } private final class TaskBarRecentsAnimationListener implements diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index e62e533fc1..a7e45d1623 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -17,6 +17,8 @@ package com.android.launcher3.taskbar; import static android.view.HapticFeedbackConstants.LONG_PRESS; +import static com.android.launcher3.anim.Interpolators.FINAL_FRAME; +import static com.android.launcher3.anim.Interpolators.INSTANT; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_HIDE; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_SHOW; import static com.android.launcher3.taskbar.Utilities.appendFlag; @@ -535,6 +537,8 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba final float firstHalfDurationScale; final float secondHalfDurationScale; + boolean isHotseatIconOnTopWhenAligned = + mControllers.uiController.isHotseatIconOnTopWhenAligned(); if (isStashed) { firstHalfDurationScale = 0.75f; secondHalfDurationScale = 0.5f; @@ -555,6 +559,12 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba secondHalfAnimatorSet.playTogether( mTaskbarStashedHandleAlpha.animateToValue(1) ); + + // If Hotseat is not the top element, an already stashed Taskbar should fade in. + if (!isHotseatIconOnTopWhenAligned) { + fullLengthAnimatorSet.setInterpolator(INSTANT); + firstHalfAnimatorSet.setInterpolator(INSTANT); + } } else { firstHalfDurationScale = 0.5f; secondHalfDurationScale = 0.75f; @@ -575,6 +585,13 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba secondHalfAnimatorSet.playTogether( mIconAlphaForStash.animateToValue(1) ); + + // If Hotseat is not the top element, the stashed Taskbar should fade out without + // unstashing. + if (!isHotseatIconOnTopWhenAligned) { + fullLengthAnimatorSet.setInterpolator(FINAL_FRAME); + secondHalfAnimatorSet.setInterpolator(FINAL_FRAME); + } } fullLengthAnimatorSet.play(mControllers.stashedHandleViewController @@ -916,6 +933,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba private final IntPredicate mStashCondition; private boolean mIsStashed; + private boolean mIsHotseatIconOnTopWhenAligned; private int mPrevFlags; StatePropertyHolder(IntPredicate stashCondition) { @@ -945,7 +963,13 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba mPrevFlags = flags; } boolean isStashed = mStashCondition.test(flags); - if (mIsStashed != isStashed) { + boolean isHotseatIconOnTopWhenAligned = + mControllers.uiController.isHotseatIconOnTopWhenAligned(); + // If an animation has started and mIsHotseatIconOnTopWhenAligned is changed, we need + // to restart the animation with new parameters. + if (mIsStashed != isStashed + || (mIsHotseatIconOnTopWhenAligned != isHotseatIconOnTopWhenAligned + && mAnimator != null && mAnimator.isStarted())) { if (TestProtocol.sDebugTracing) { Log.d(TestProtocol.TASKBAR_IN_APP_STATE, String.format( "setState: mIsStashed=%b, isStashed=%b, duration=%d, start=:%b", @@ -955,6 +979,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba start)); } mIsStashed = isStashed; + mIsHotseatIconOnTopWhenAligned = isHotseatIconOnTopWhenAligned; // This sets mAnimator. createAnimToIsStashed(mIsStashed, duration, startDelay, /* animateBg= */ true); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java index 6c6b002959..a059295bfc 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java @@ -128,6 +128,13 @@ public class TaskbarUIController { return false; } + /** + * Returns true if hotseat icons are on top of view hierarchy when aligned in the current state. + */ + public boolean isHotseatIconOnTopWhenAligned() { + return true; + } + @CallSuper protected void dumpLogs(String prefix, PrintWriter pw) { pw.println(String.format( diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index b5e6fac5bb..d14eeab295 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -19,6 +19,7 @@ import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA; import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y; import static com.android.launcher3.Utilities.squaredHypot; +import static com.android.launcher3.anim.Interpolators.FINAL_FRAME; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP; import static com.android.launcher3.taskbar.TaskbarManager.isPhoneMode; @@ -32,6 +33,7 @@ import android.util.FloatProperty; import android.util.Log; import android.view.MotionEvent; import android.view.View; +import android.view.animation.Interpolator; import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; @@ -112,6 +114,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar private Runnable mOnControllerPreCreateCallback = NO_OP; private int mThemeIconsColor; + private boolean mIsHotseatIconOnTopWhenAligned; private final DeviceProfile.OnDeviceProfileChangeListener mDeviceProfileChangeListener = dp -> commitRunningAppsToUI(); @@ -293,7 +296,12 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar * 1 => fully aligned */ public void setLauncherIconAlignment(float alignmentRatio, DeviceProfile launcherDp) { - if (mIconAlignControllerLazy == null) { + boolean isHotseatIconOnTopWhenAligned = + mControllers.uiController.isHotseatIconOnTopWhenAligned(); + // When mIsHotseatIconOnTopWhenAligned changes, animation needs to be re-created. + if (mIconAlignControllerLazy == null + || mIsHotseatIconOnTopWhenAligned != isHotseatIconOnTopWhenAligned) { + mIsHotseatIconOnTopWhenAligned = isHotseatIconOnTopWhenAligned; mIconAlignControllerLazy = createIconAlignmentController(launcherDp); } mIconAlignControllerLazy.setPlayFraction(alignmentRatio); @@ -318,10 +326,15 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar borderSpacing, launcherDp.numShownHotseatIcons); + boolean isToHome = mControllers.uiController.isIconAlignedWithHotseat(); + // If Hotseat is not the top element, Taskbar should maintain in-app state as it fades out, + // or fade in while already in in-app state. + Interpolator interpolator = mIsHotseatIconOnTopWhenAligned ? LINEAR : FINAL_FRAME; + int offsetY = launcherDp.getTaskbarOffsetY(); - setter.setFloat(mTaskbarIconTranslationYForHome, VALUE, -offsetY, LINEAR); - setter.setFloat(mTaskbarNavButtonTranslationY, VALUE, -offsetY, LINEAR); - setter.setFloat(mTaskbarNavButtonTranslationYForInAppDisplay, VALUE, offsetY, LINEAR); + setter.setFloat(mTaskbarIconTranslationYForHome, VALUE, -offsetY, interpolator); + setter.setFloat(mTaskbarNavButtonTranslationY, VALUE, -offsetY, interpolator); + setter.setFloat(mTaskbarNavButtonTranslationYForInAppDisplay, VALUE, offsetY, interpolator); if (Utilities.isDarkTheme(mTaskbarView.getContext())) { setter.addFloat(mThemeIconsBackground, VALUE, 0f, 1f, LINEAR); @@ -332,27 +345,24 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar setter.addOnFrameListener(anim -> mActivity.setTaskbarWindowHeight( anim.getAnimatedFraction() > 0 ? expandedHeight : collapsedHeight)); - boolean isToHome = mControllers.uiController.isIconAlignedWithHotseat(); for (int i = 0; i < mTaskbarView.getChildCount(); i++) { View child = mTaskbarView.getChildAt(i); int positionInHotseat; - if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get() - && child == mTaskbarView.getAllAppsButtonView()) { - // Note that there is no All Apps button in the hotseat, this position is only used - // as its convenient for animation purposes. - positionInHotseat = Utilities.isRtl(child.getResources()) - ? -1 - : taskbarDp.numShownHotseatIcons; + boolean isAllAppsButton = FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get() + && child == mTaskbarView.getAllAppsButtonView(); + if (!mIsHotseatIconOnTopWhenAligned) { + // When going to home, the EMPHASIZED interpolator in TaskbarLauncherStateController + // plays iconAlignment to 1 really fast, therefore moving the fading towards the end + // to avoid icons disappearing rather than fading out visually. + setter.setViewAlpha(child, 0, Interpolators.clampToProgress(LINEAR, 0.8f, 1f)); + } else if ((isAllAppsButton && !FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get())) { + setter.setViewAlpha(child, 0, + isToHome + ? Interpolators.clampToProgress(LINEAR, 0f, 0.17f) + : Interpolators.clampToProgress(LINEAR, 0.72f, 0.84f)); + } - if (!FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) { - setter.setViewAlpha(child, 0, - isToHome - ? Interpolators.clampToProgress(LINEAR, 0f, 0.17f) - : Interpolators.clampToProgress(LINEAR, 0.72f, 0.84f)); - } - } else if (child.getTag() instanceof ItemInfo) { - positionInHotseat = ((ItemInfo) child.getTag()).screenId; - } else if (child == mTaskbarView.getQsb()) { + if (child == mTaskbarView.getQsb()) { boolean isRtl = Utilities.isRtl(child.getResources()); float hotseatIconCenter = isRtl ? launcherDp.widthPx - hotseatPadding.right + borderSpacing @@ -363,26 +373,38 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar (launcherDp.hotseatQsbWidth - taskbarDp.iconSizePx) / 2f; setter.addFloat(child, ICON_TRANSLATE_X, isRtl ? -halfQsbIconWidthDiff : halfQsbIconWidthDiff, - hotseatIconCenter - childCenter, LINEAR); + hotseatIconCenter - childCenter, interpolator); float scale = ((float) taskbarDp.iconSizePx) / launcherDp.hotseatQsbVisualHeight; - setter.addFloat(child, SCALE_PROPERTY, scale, 1f, LINEAR); + setter.addFloat(child, SCALE_PROPERTY, scale, 1f, interpolator); - setter.setFloat(child, VIEW_TRANSLATE_Y, mTaskbarBottomMargin, LINEAR); + setter.setFloat(child, VIEW_TRANSLATE_Y, mTaskbarBottomMargin, interpolator); - setter.addFloat(child, VIEW_ALPHA, 0f, 1f, - isToHome - ? Interpolators.clampToProgress(LINEAR, 0f, 0.35f) - : Interpolators.clampToProgress(LINEAR, 0.84f, 1f)); + if (mIsHotseatIconOnTopWhenAligned) { + setter.addFloat(child, VIEW_ALPHA, 0f, 1f, + isToHome + ? Interpolators.clampToProgress(LINEAR, 0f, 0.35f) + : Interpolators.clampToProgress(LINEAR, 0.84f, 1f)); + } setter.addOnFrameListener(animator -> AlphaUpdateListener.updateVisibility(child)); float qsbInsetFraction = halfQsbIconWidthDiff / launcherDp.hotseatQsbWidth; - if (child instanceof HorizontalInsettableView) { + if (child instanceof HorizontalInsettableView) { setter.addFloat((HorizontalInsettableView) child, HorizontalInsettableView.HORIZONTAL_INSETS, qsbInsetFraction, 0, - LINEAR); + interpolator); } continue; + } + + if (isAllAppsButton) { + // Note that there is no All Apps button in the hotseat, this position is only used + // as its convenient for animation purposes. + positionInHotseat = Utilities.isRtl(child.getResources()) + ? -1 + : taskbarDp.numShownHotseatIcons; + } else if (child.getTag() instanceof ItemInfo) { + positionInHotseat = ((ItemInfo) child.getTag()).screenId; } else { Log.w(TAG, "Unsupported view found in createIconAlignmentController, v=" + child); continue; @@ -393,11 +415,11 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar + hotseatCellSize / 2f; float childCenter = (child.getLeft() + child.getRight()) / 2f; - setter.setFloat(child, ICON_TRANSLATE_X, hotseatIconCenter - childCenter, LINEAR); + setter.setFloat(child, ICON_TRANSLATE_X, hotseatIconCenter - childCenter, interpolator); - setter.setFloat(child, VIEW_TRANSLATE_Y, mTaskbarBottomMargin, LINEAR); + setter.setFloat(child, VIEW_TRANSLATE_Y, mTaskbarBottomMargin, interpolator); - setter.setFloat(child, SCALE_PROPERTY, scaleUp, LINEAR); + setter.setFloat(child, SCALE_PROPERTY, scaleUp, interpolator); } AnimatorPlaybackController controller = setter.createPlaybackController();