diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index a3e8b5ccfd..ca30e72609 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -19,6 +19,7 @@ import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_ import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR; import android.animation.Animator; +import android.animation.AnimatorSet; import android.annotation.ColorInt; import android.os.RemoteException; import android.util.Log; @@ -28,6 +29,7 @@ import android.view.TaskTransitionSpec; import android.view.WindowManagerGlobal; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.launcher3.BaseQuickstepLauncher; @@ -139,6 +141,24 @@ public class LauncherTaskbarUIController extends TaskbarUIController { mControllers.taskbarStashController.onLongPressToUnstashTaskbar(); } + /** + * Adds the Launcher resume animator to the given animator set. + * + * This should be used to run a Launcher resume animation whose progress matches a + * swipe progress. + * + * @param placeholderDuration a placeholder duration to be used to ensure all full-length + * sub-animations are properly coordinated. This duration should not + * actually be used since this animation tracks a swipe progress. + */ + protected void addLauncherResumeAnimation(AnimatorSet animation, int placeholderDuration) { + animation.play(onLauncherResumedOrPaused( + /* isResumed= */ true, + /* fromInit= */ false, + /* startAnimation= */ false, + placeholderDuration)); + } + /** * Should be called from onResume() and onPause(), and animates the Taskbar accordingly. */ @@ -147,9 +167,19 @@ public class LauncherTaskbarUIController extends TaskbarUIController { } private void onLauncherResumedOrPaused(boolean isResumed, boolean fromInit) { + onLauncherResumedOrPaused( + isResumed, + fromInit, + /* startAnimation= */ true, + QuickstepTransitionManager.CONTENT_ALPHA_DURATION); + } + + @Nullable + private Animator onLauncherResumedOrPaused( + boolean isResumed, boolean fromInit, boolean startAnimation, int duration) { if (mKeyguardController.isScreenOff()) { if (!isResumed) { - return; + return null; } else { // Resuming implicitly means device unlocked mKeyguardController.setScreenOn(); @@ -157,8 +187,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController { } mTaskbarLauncherStateController.updateStateForFlag(FLAG_RESUMED, isResumed); - mTaskbarLauncherStateController.applyState( - fromInit ? 0 : QuickstepTransitionManager.CONTENT_ALPHA_DURATION); + return mTaskbarLauncherStateController.applyState(fromInit ? 0 : duration, startAnimation); } /** diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 2f322199f3..ed1001cead 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -29,6 +29,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_N import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED; import android.animation.AnimatorSet; +import android.animation.ValueAnimator; import android.app.ActivityOptions; import android.content.ActivityNotFoundException; import android.content.Context; @@ -60,6 +61,8 @@ import com.android.launcher3.BubbleTextView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.R; +import com.android.launcher3.anim.AnimatorPlaybackController; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dot.DotInfo; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; @@ -734,6 +737,45 @@ public class TaskbarActivityContext extends BaseTaskbarContext { return mIsNavBarForceVisible; } + /** + * Displays a single frame of the Launcher start from SUW animation. + * + * This animation is a combination of the Launcher resume animation, which animates the hotseat + * icons into position, the Taskbar unstash to hotseat animation, which animates the Taskbar + * stash bar into the hotseat icons, and an override to prevent showing the Taskbar all apps + * button. + * + * This should be used to run a Taskbar unstash to hotseat animation whose progress matches a + * swipe progress. + * + * @param duration a placeholder duration to be used to ensure all full-length + * sub-animations are properly coordinated. This duration should not actually + * be used since this animation tracks a swipe progress. + */ + protected AnimatorPlaybackController createLauncherStartFromSuwAnim(int duration) { + AnimatorSet fullAnimation = new AnimatorSet(); + fullAnimation.setDuration(duration); + + TaskbarUIController uiController = mControllers.uiController; + if (uiController instanceof LauncherTaskbarUIController) { + ((LauncherTaskbarUIController) uiController).addLauncherResumeAnimation( + fullAnimation, duration); + } + mControllers.taskbarStashController.addUnstashToHotseatAnimation(fullAnimation, duration); + + if (!FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) { + ValueAnimator alphaOverride = ValueAnimator.ofFloat(0, 1); + alphaOverride.setDuration(duration); + alphaOverride.addUpdateListener(a -> { + // Override the alpha updates in the icon alignment animation. + mControllers.taskbarViewController.getAllAppsButtonView().setAlpha(0); + }); + fullAnimation.play(alphaOverride); + } + + return AnimatorPlaybackController.wrap(fullAnimation, duration); + } + /** * Called when we determine the touchable region. * diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java index 2e37170952..ef7bab9832 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java @@ -39,6 +39,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.DeviceProfile; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.taskbar.unfold.NonDestroyableScopedUnfoldTransitionProgressProvider; import com.android.launcher3.util.DisplayController; @@ -182,6 +183,17 @@ public class TaskbarManager { } } + /** + * Displays a frame of the first Launcher reveal animation. + * + * This should be used to run a first Launcher reveal animation whose progress matches a swipe + * progress. + */ + public AnimatorPlaybackController createLauncherStartFromSuwAnim(int duration) { + return mTaskbarActivityContext == null + ? null : mTaskbarActivityContext.createLauncherStartFromSuwAnim(duration); + } + /** * Called when the user is unlocked */ diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 7d95743bc9..fc9f9d002b 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -35,6 +35,8 @@ import android.view.WindowInsets; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AnimatorListeners; +import com.android.launcher3.taskbar.allapps.TaskbarAllAppsSlideInView; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.util.MultiValueAlpha.AlphaProperty; import com.android.quickstep.AnimatedFloat; @@ -367,13 +369,34 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba return false; } + /** + * Adds the Taskbar unstash to Hotseat animator to the animator set. + * + * This should be used to run a Taskbar unstash to Hotseat animation whose progress matches a + * swipe progress. + * + * @param placeholderDuration a placeholder duration to be used to ensure all full-length + * sub-animations are properly coordinated. This duration should not + * actually be used since this animation tracks a swipe progress. + */ + protected void addUnstashToHotseatAnimation(AnimatorSet animation, int placeholderDuration) { + createAnimToIsStashed( + /* isStashed= */ false, + placeholderDuration, + /* startDelay= */ 0, + /* animateBg= */ false); + animation.play(mAnimator); + } + /** * Create a stash animation and save to {@link #mAnimator}. * @param isStashed whether it's a stash animation or an unstash animation * @param duration duration of the animation * @param startDelay how many milliseconds to delay the animation after starting it. + * @param animateBg whether the taskbar's background should be animated */ - private void createAnimToIsStashed(boolean isStashed, long duration, long startDelay) { + private void createAnimToIsStashed( + boolean isStashed, long duration, long startDelay, boolean animateBg) { if (mAnimator != null) { mAnimator.cancel(); } @@ -408,10 +431,14 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba secondHalfDurationScale = 0.5f; final float stashTranslation = (mUnstashedHeight - mStashedHeight) / 2f; - fullLengthAnimatorSet.playTogether( - mTaskbarBackgroundOffset.animateToValue(1), - mIconTranslationYForStash.animateToValue(stashTranslation) - ); + fullLengthAnimatorSet.play(mIconTranslationYForStash.animateToValue(stashTranslation)); + if (animateBg) { + fullLengthAnimatorSet.play(mTaskbarBackgroundOffset.animateToValue(1)); + } else { + fullLengthAnimatorSet.addListener(AnimatorListeners.forEndCallback( + () -> mTaskbarBackgroundOffset.updateValue(1))); + } + firstHalfAnimatorSet.playTogether( mIconAlphaForStash.animateToValue(0), mIconScaleForStash.animateToValue(STASHED_TASKBAR_SCALE) @@ -424,10 +451,15 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba secondHalfDurationScale = 0.75f; fullLengthAnimatorSet.playTogether( - mTaskbarBackgroundOffset.animateToValue(0), mIconScaleForStash.animateToValue(1), - mIconTranslationYForStash.animateToValue(0) - ); + mIconTranslationYForStash.animateToValue(0)); + if (animateBg) { + fullLengthAnimatorSet.play(mTaskbarBackgroundOffset.animateToValue(0)); + } else { + fullLengthAnimatorSet.addListener(AnimatorListeners.forEndCallback( + () -> mTaskbarBackgroundOffset.updateValue(0))); + } + firstHalfAnimatorSet.playTogether( mTaskbarStashedHandleAlpha.animateToValue(0) ); @@ -728,7 +760,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba mIsStashed = isStashed; // This sets mAnimator. - createAnimToIsStashed(mIsStashed, duration, startDelay); + createAnimToIsStashed(mIsStashed, duration, startDelay, /* animateBg= */ true); if (start) { mAnimator.start(); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index 5db495db43..3dd7932a9a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -258,21 +258,21 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar setter.addOnFrameListener(anim -> mActivity.setTaskbarWindowHeight( anim.getAnimatedFraction() > 0 ? expandedHeight : collapsedHeight)); - int count = mTaskbarView.getChildCount(); - for (int i = 0; i < count; i++) { + for (int i = 0; i < mTaskbarView.getChildCount(); i++) { View child = mTaskbarView.getChildAt(i); - int positionInHotseat = -1; - boolean isRtl = Utilities.isRtl(child.getResources()); + int positionInHotseat; if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get() - && ((isRtl && i == 0) || (!isRtl && i == count - 1))) { + && 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 = isRtl + positionInHotseat = Utilities.isRtl(child.getResources()) ? -1 : mActivity.getDeviceProfile().numShownHotseatIcons; - setter.setViewAlpha(child, 0, LINEAR); + if (!FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) { + setter.setViewAlpha(child, 0, LINEAR); + } } else if (child.getTag() instanceof ItemInfo) { positionInHotseat = ((ItemInfo) child.getTag()).screenId; } else { diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java index 269b3c2268..a379aada4a 100644 --- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java +++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java @@ -17,6 +17,7 @@ package com.android.quickstep.interaction; import static com.android.launcher3.Utilities.mapBoundToRange; import static com.android.launcher3.Utilities.mapRange; +import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.LINEAR; import android.animation.Animator; @@ -54,6 +55,7 @@ import androidx.core.graphics.ColorUtils; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.util.Executors; import com.android.quickstep.AnimatedFloat; import com.android.quickstep.GestureState; @@ -78,6 +80,8 @@ public class AllSetActivity extends Activity { private static final float HINT_BOTTOM_FACTOR = 1 - .94f; + private static final int MAX_SWIPE_DURATION = 350; + private TISBindHelper mTISBindHelper; private TISBinder mBinder; @@ -90,6 +94,8 @@ public class AllSetActivity extends Activity { private LottieAnimationView mAnimatedBackground; private Animator.AnimatorListener mBackgroundAnimatorListener; + private AnimatorPlaybackController mLauncherStartAnim = null; + @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -237,11 +243,20 @@ public class AllSetActivity extends Activity { private void onSwipeProgressUpdate() { mBackground.setProgress(mSwipeProgress.value); - float alpha = Utilities.mapBoundToRange(mSwipeProgress.value, 0, HINT_BOTTOM_FACTOR, - 1, 0, LINEAR); + float alpha = Utilities.mapBoundToRange( + mSwipeProgress.value, 0, HINT_BOTTOM_FACTOR, 1, 0, LINEAR); mContentView.setAlpha(alpha); mContentView.setTranslationY((alpha - 1) * mSwipeUpShift); + if (mLauncherStartAnim == null) { + mLauncherStartAnim = mBinder.getTaskbarManager().createLauncherStartFromSuwAnim( + MAX_SWIPE_DURATION); + } + if (mLauncherStartAnim != null) { + mLauncherStartAnim.setPlayFraction(Utilities.mapBoundToRange( + mSwipeProgress.value, 0, 1, 0, 1, FAST_OUT_SLOW_IN)); + } + if (alpha == 0f) { mAnimatedBackground.pauseAnimation(); } else if (!mAnimatedBackground.isAnimating()) { diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index 54edb33080..9775b878cc 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -246,6 +246,10 @@ public final class FeatureFlags { "ENABLE_ALL_APPS_IN_TASKBAR", true, "Enables accessing All Apps from the system Taskbar."); + public static final BooleanFlag ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT = getDebugFlag( + "ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT", false, + "Enables displaying the all apps button in the hotseat."); + public static final BooleanFlag ENABLE_ALL_APPS_ONE_SEARCH_IN_TASKBAR = getDebugFlag( "ENABLE_ALL_APPS_ONE_SEARCH_IN_TASKBAR", false, "Enables One Search box in Taskbar All Apps.");