From 8b2e5eff9b17f61f2b0b6493c8c4a9eafbdad206 Mon Sep 17 00:00:00 2001 From: Jagrut Desai Date: Thu, 5 Dec 2024 17:01:45 -0800 Subject: [PATCH] Desktop Mode Taskbar Recreate Animation This Cl includes - addition of entry/exit callback methods in DesktopVisibilityController. - taskbar manager now listens to desktop mode changes. - TaskbarBackrgroundRedererer can now individually animation backgrounds for transient and persistent taskbars - new channel for taskbar icon alpha added to TaskbarViewController - new animated float to handle background alpha while we are recreating taskbar with animation. Solution: we use the callabck we get from DekstopVisibilty for entry/exit to first change logic of when we are considered inDesktopMode. Upon entry/exit we notify display controller for info change. we also at notify taskbar manager who is now a listener to the desktop mode change and start the recreate process. TaskbarManager first animates existing taskbar out of user view and then follows the original recreate flow. Test: Presubmit Bug: 343882478 Flag: com.android.window.flags.enable_desktop_windowing_mode Change-Id: Ib827564cacd194f499e7d9b1965e2bb13e3548ab --- .../launcher3/QuickstepTransitionManager.java | 8 +- .../DesktopVisibilityController.kt | 145 ++++++++++++++---- .../taskbar/TaskbarActivityContext.java | 47 +++++- .../taskbar/TaskbarBackgroundRenderer.kt | 11 +- .../launcher3/taskbar/TaskbarControllers.java | 7 +- .../taskbar/TaskbarDesktopModeController.kt | 4 + .../launcher3/taskbar/TaskbarDragLayer.java | 16 ++ .../taskbar/TaskbarDragLayerController.java | 59 ++++++- .../TaskbarLauncherStateController.java | 15 +- .../launcher3/taskbar/TaskbarManager.java | 116 +++++++++++--- .../launcher3/taskbar/TaskbarView.java | 1 + .../taskbar/TaskbarViewController.java | 31 +++- .../QuickstepAtomicAnimationFactory.java | 8 +- .../android/quickstep/AbsSwipeUpHandler.java | 24 ++- .../util/StaggeredWorkspaceAnim.java | 4 +- .../launcher3/taskbar/TaskbarOverflowTest.kt | 10 +- .../TaskbarRecentAppsControllerTest.kt | 2 + .../launcher3/util/DisplayController.java | 22 ++- .../launcher3/util/DisplayControllerTest.kt | 14 +- 19 files changed, 458 insertions(+), 86 deletions(-) diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index 67feb6a6b8..5b78c0ab55 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -1811,8 +1811,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener } /** Get animation duration for taskbar for going to home. */ - public static int getTaskbarToHomeDuration(boolean isPinnedTaskbar) { - return getTaskbarToHomeDuration(false, isPinnedTaskbar); + public static int getTaskbarToHomeDuration(boolean isPinnedTaskbarAndNotInDesktopMode) { + return getTaskbarToHomeDuration(false, isPinnedTaskbarAndNotInDesktopMode); } /** @@ -1821,8 +1821,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener * @param shouldOverrideToFastAnimation should overwrite scaling reveal home animation duration */ public static int getTaskbarToHomeDuration(boolean shouldOverrideToFastAnimation, - boolean isPinnedTaskbar) { - if (isPinnedTaskbar) { + boolean isPinnedTaskbarAndNotInDesktopMode) { + if (isPinnedTaskbarAndNotInDesktopMode) { return PINNED_TASKBAR_TRANSITION_DURATION; } else if (enableScalingRevealHomeAnimation() && !shouldOverrideToFastAnimation) { return TASKBAR_TO_HOME_DURATION_SLOW; diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt index 138f40a2dd..eb24df13e1 100644 --- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt +++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt @@ -32,7 +32,8 @@ import com.android.launcher3.statemanager.StatefulActivity import com.android.launcher3.uioverrides.QuickstepLauncher import com.android.launcher3.util.DaggerSingletonObject import com.android.launcher3.util.DaggerSingletonTracker -import com.android.launcher3.util.Executors +import com.android.launcher3.util.DisplayController +import com.android.launcher3.util.Executors.MAIN_EXECUTOR import com.android.launcher3.util.window.WindowManagerProxy.DesktopVisibilityListener import com.android.quickstep.GestureState.GestureEndTarget import com.android.quickstep.SystemUiProxy @@ -87,9 +88,22 @@ constructor( private val desktopVisibilityListeners: MutableSet = HashSet() private val taskbarDesktopModeListeners: MutableSet = HashSet() + // This simply indicates that user is currently in desktop mode or not. + var isInDesktopMode = false + private set + + // to track if any pending notification to be done. + var isNotifyingDesktopVisibilityPending = false + + // to let launcher hold off on notifying desktop visibility listeners. + var launcherAnimationRunning = false + // TODO: b/394387739 - Deprecate this and replace it with something that tracks the count per // desk. - /** Number of visible desktop windows in desktop mode. */ + /** + * Number of visible desktop windows in desktop mode. This can be > 0 when user goes to overview + * from desktop window mode. + */ var visibleDesktopTasksCount: Int = 0 /** * Sets the number of desktop windows that are visible and updates launcher visibility based @@ -107,13 +121,27 @@ constructor( } if (visibleTasksCount != field) { + if (visibleDesktopTasksCount == 0 && visibleTasksCount == 1) { + isInDesktopMode = true + } + if (visibleDesktopTasksCount == 1 && visibleTasksCount == 0) { + isInDesktopMode = false + } val wasVisible = field > 0 val isVisible = visibleTasksCount > 0 val wereDesktopTasksVisibleBefore = areDesktopTasksVisibleAndNotInOverview() field = visibleTasksCount val areDesktopTasksVisibleNow = areDesktopTasksVisibleAndNotInOverview() - if (wereDesktopTasksVisibleBefore != areDesktopTasksVisibleNow) { - notifyIsInDesktopModeChanged(DEFAULT_DISPLAY, areDesktopTasksVisibleNow) + + if ( + wereDesktopTasksVisibleBefore != areDesktopTasksVisibleNow || + wasVisible != isVisible + ) { + if (!launcherAnimationRunning) { + notifyIsInDesktopModeChanged(DEFAULT_DISPLAY, areDesktopTasksVisibleNow) + } else { + isNotifyingDesktopVisibilityPending = true + } } if ( @@ -169,7 +197,7 @@ constructor( /** Returns whether a desk is currently active on the display with the given [displayId]. */ fun isInDesktopMode(displayId: Int): Boolean { if (!DesktopModeStatus.enableMultipleDesktops(context)) { - return areDesktopTasksVisible() + return isInDesktopMode } val activeDeskId = getDisplayDeskConfig(displayId)?.activeDeskId ?: INACTIVE_DESK_ID @@ -195,15 +223,6 @@ constructor( return isInDesktopMode(displayId) && !inOverviewState } - /** Whether desktop tasks are visible in desktop mode. */ - private fun areDesktopTasksVisible(): Boolean { - val desktopTasksVisible: Boolean = visibleDesktopTasksCount > 0 - if (DEBUG) { - Log.d(TAG, "areDesktopTasksVisible: desktopVisible=$desktopTasksVisible") - } - return desktopTasksVisible - } - /** Whether desktop tasks are visible in desktop mode. */ private fun areDesktopTasksVisibleAndNotInOverview(): Boolean { val desktopTasksVisible: Boolean = visibleDesktopTasksCount > 0 @@ -237,6 +256,22 @@ constructor( ) } + /** + * Launcher Driven Desktop Mode changes. For example, swipe to home and quick switch from + * Desktop Windowing Mode. if there is any pending notification please notify desktop visibility + * listeners. + */ + fun onLauncherAnimationFromDesktopEnd() { + launcherAnimationRunning = false + if (isNotifyingDesktopVisibilityPending) { + isNotifyingDesktopVisibilityPending = false + notifyIsInDesktopModeChanged( + DEFAULT_DISPLAY, + isInDesktopModeAndNotInOverview(DEFAULT_DISPLAY), + ) + } + } + fun onLauncherStateChanged(state: RecentsState) { onLauncherStateChanged( state, @@ -346,6 +381,26 @@ constructor( } } + private fun notifyTaskbarDesktopModeListenersForEntry(duration: Int) { + if (DEBUG) { + Log.d(TAG, "notifyTaskbarDesktopModeListenersForEntry: duration=" + duration) + } + for (listener in taskbarDesktopModeListeners) { + listener.onEnterDesktopMode(duration) + } + DisplayController.INSTANCE.get(context).notifyConfigChange() + } + + private fun notifyTaskbarDesktopModeListenersForExit(duration: Int) { + if (DEBUG) { + Log.d(TAG, "notifyTaskbarDesktopModeListenersForExit: duration=" + duration) + } + for (listener in taskbarDesktopModeListeners) { + listener.onExitDesktopMode(duration) + } + DisplayController.INSTANCE.get(context).notifyConfigChange() + } + /** TODO: b/333533253 - Remove after flag rollout */ private fun setBackgroundStateEnabled(backgroundStateEnabled: Boolean) { if (DEBUG) { @@ -552,14 +607,14 @@ constructor( displayDeskStates: Array, canCreateDesks: Boolean, ) { - Executors.MAIN_EXECUTOR.execute { + MAIN_EXECUTOR.execute { controller.get()?.onListenerConnected(displayDeskStates, canCreateDesks) } } override fun onTasksVisibilityChanged(displayId: Int, visibleTasksCount: Int) { if (displayId != this.displayId) return - Executors.MAIN_EXECUTOR.execute { + MAIN_EXECUTOR.execute { controller.get()?.apply { if (DEBUG) { Log.d(TAG, "desktop visible tasks count changed=$visibleTasksCount") @@ -575,7 +630,7 @@ constructor( override fun onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding: Boolean) { if (!DesktopModeStatus.useRoundedCorners()) return - Executors.MAIN_EXECUTOR.execute { + MAIN_EXECUTOR.execute { controller.get()?.apply { Log.d( TAG, @@ -587,26 +642,46 @@ constructor( } } - override fun onEnterDesktopModeTransitionStarted(transitionDuration: Int) {} - - override fun onExitDesktopModeTransitionStarted(transitionDuration: Int) {} - - override fun onCanCreateDesksChanged(canCreateDesks: Boolean) { - Executors.MAIN_EXECUTOR.execute { - controller.get()?.onCanCreateDesksChanged(canCreateDesks) + override fun onEnterDesktopModeTransitionStarted(transitionDuration: Int) { + MAIN_EXECUTOR.execute { + Log.d( + TAG, + ("DesktopTaskListenerImpl: onEnterDesktopModeTransitionStarted with " + + "duration= " + + transitionDuration), + ) + controller.get()?.isInDesktopMode = true + controller.get()?.notifyTaskbarDesktopModeListenersForEntry(transitionDuration) } } + override fun onExitDesktopModeTransitionStarted(transitionDuration: Int) { + MAIN_EXECUTOR.execute { + Log.d( + TAG, + ("DesktopTaskListenerImpl: onExitDesktopModeTransitionStarted with " + + "duration= " + + transitionDuration), + ) + controller.get()?.isInDesktopMode = false + controller.get()?.notifyTaskbarDesktopModeListenersForExit(transitionDuration) + } + } + + override fun onCanCreateDesksChanged(canCreateDesks: Boolean) { + MAIN_EXECUTOR.execute { controller.get()?.onCanCreateDesksChanged(canCreateDesks) } + } + override fun onDeskAdded(displayId: Int, deskId: Int) { - Executors.MAIN_EXECUTOR.execute { controller.get()?.onDeskAdded(displayId, deskId) } + MAIN_EXECUTOR.execute { controller.get()?.onDeskAdded(displayId, deskId) } } override fun onDeskRemoved(displayId: Int, deskId: Int) { - Executors.MAIN_EXECUTOR.execute { controller.get()?.onDeskRemoved(displayId, deskId) } + MAIN_EXECUTOR.execute { controller.get()?.onDeskRemoved(displayId, deskId) } } override fun onActiveDeskChanged(displayId: Int, newActiveDesk: Int, oldActiveDesk: Int) { - Executors.MAIN_EXECUTOR.execute { + MAIN_EXECUTOR.execute { controller.get()?.onActiveDeskChanged(displayId, newActiveDesk, oldActiveDesk) } } @@ -619,7 +694,21 @@ constructor( * * @param doesAnyTaskRequireTaskbarRounding whether task requires taskbar corner roundness. */ - fun onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding: Boolean) + fun onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding: Boolean) {} + + /** + * Callback for when user is exiting desktop mode. + * + * @param duration for exit transition + */ + fun onExitDesktopMode(duration: Int) {} + + /** + * Callback for when user is entering desktop mode. + * + * @param duration for enter transition + */ + fun onEnterDesktopMode(duration: Int) {} } companion object { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 2e42e45768..57bcc14ff3 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -27,6 +27,7 @@ import static android.window.SplashScreen.SPLASH_SCREEN_STYLE_UNDEFINED; import static androidx.annotation.VisibleForTesting.PACKAGE_PRIVATE; +import static com.android.app.animation.Interpolators.LINEAR; import static com.android.launcher3.AbstractFloatingView.TYPE_ALL; import static com.android.launcher3.AbstractFloatingView.TYPE_ON_BOARD_POPUP; import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE; @@ -449,14 +450,25 @@ public class TaskbarActivityContext extends BaseTaskbarContext { mControllers.taskbarViewController.adjustTaskbarForBubbleBar(); } - public void init(@NonNull TaskbarSharedState sharedState) { + /** + * Init of taskbar activity context. + * @param duration If duration is greater than 0, it will be used to create an animation + * for the taskbar create/recreate process. + */ + public void init(@NonNull TaskbarSharedState sharedState, int duration) { mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, getResources(), false); mLastRequestedNonFullscreenSize = getDefaultTaskbarWindowSize(); mWindowLayoutParams = createAllWindowParams(); mLastUpdatedLayoutParams = new WindowManager.LayoutParams(); + + AnimatorSet recreateAnim = null; + if (duration > 0) { + recreateAnim = onRecreateAnimation(duration); + } + // Initialize controllers after all are constructed. - mControllers.init(sharedState); + mControllers.init(sharedState, recreateAnim); // This may not be necessary and can be reverted once we move towards recreating all // controllers without re-creating the window mControllers.rotationButtonController.onNavigationModeChanged(mNavMode.resValue); @@ -484,6 +496,33 @@ public class TaskbarActivityContext extends BaseTaskbarContext { } else { notifyUpdateLayoutParams(); } + + + if (recreateAnim != null) { + recreateAnim.start(); + } + } + + /** + * Create AnimatorSet for taskbar create/recreate animation. Further used in init + */ + public AnimatorSet onRecreateAnimation(int duration) { + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.setDuration(duration); + return animatorSet; + } + + /** + * Called when we want destroy current taskbar with animation as part of recreate process. + */ + public AnimatorSet onDestroyAnimation(int duration) { + mIsDestroyed = true; + AnimatorSet animatorSet = new AnimatorSet(); + mControllers.taskbarViewController.onDestroyAnimation(animatorSet); + mControllers.taskbarDragLayerController.onDestroyAnimation(animatorSet); + animatorSet.setInterpolator(LINEAR); + animatorSet.setDuration(duration); + return animatorSet; } /** @@ -1983,6 +2022,10 @@ public class TaskbarActivityContext extends BaseTaskbarContext { return mControllers.taskbarStashController.isInApp(); } + public boolean isInOverview() { + return mControllers.taskbarStashController.isInOverview(); + } + public boolean isInStashedLauncherState() { return mControllers.taskbarStashController.isInStashedLauncherState(); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt index 6d238530a4..89cc991387 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt @@ -50,6 +50,8 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) { } var isAnimatingPinning = false + var isAnimatingPersistentTaskbar = false + var isAnimatingTransientTaskbar = false val paint = Paint() private val strokePaint = Paint() @@ -144,7 +146,7 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) { /** Draws the background with the given paint and height, on the provided canvas. */ fun draw(canvas: Canvas) { if (isInSetup) return - val isTransientTaskbar = backgroundProgress == 0f + val isTransientTaskbar = DisplayController.isTransientTaskbar(context) canvas.save() if (!isTransientTaskbar || transientBackgroundBounds.isEmpty || isAnimatingPinning) { drawPersistentBackground(canvas) @@ -158,7 +160,7 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) { } private fun drawPersistentBackground(canvas: Canvas) { - if (isAnimatingPinning) { + if (isAnimatingPinning || isAnimatingPersistentTaskbar) { val persistentTaskbarHeight = maxPersistentTaskbarHeight * backgroundProgress canvas.translate(0f, canvas.height - persistentTaskbarHeight) // Draw the background behind taskbar content. @@ -181,12 +183,13 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) { private fun drawTransientBackground(canvas: Canvas) { val res = context.resources val transientTaskbarHeight = maxTransientTaskbarHeight * (1f - backgroundProgress) + val isAnimating = isAnimatingPinning || isAnimatingTransientTaskbar val heightProgressWhileAnimating = - if (isAnimatingPinning) transientTaskbarHeight else backgroundHeight + if (isAnimating) transientTaskbarHeight else backgroundHeight var progress = heightProgressWhileAnimating / maxTransientTaskbarHeight progress = Math.round(progress * 100f) / 100f - if (isAnimatingPinning) { + if (isAnimating) { var scale = transientTaskbarHeight / maxTransientTaskbarHeight scale = Math.round(scale * 100f) / 100f bottomMargin = diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java index b244be9205..6ca9385294 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java @@ -15,6 +15,7 @@ */ package com.android.launcher3.taskbar; +import android.animation.AnimatorSet; import android.content.pm.ActivityInfo.Config; import androidx.annotation.NonNull; @@ -149,15 +150,15 @@ public class TaskbarControllers { * TaskbarControllers instance, but should be careful to only access things that were created * in constructors for now, as some controllers may still be waiting for init(). */ - public void init(@NonNull TaskbarSharedState sharedState) { + public void init(@NonNull TaskbarSharedState sharedState, AnimatorSet startAnimation) { mAreAllControllersInitialized = false; mSharedState = sharedState; taskbarDragController.init(this); navbarButtonsViewController.init(this); rotationButtonController.init(); - taskbarDragLayerController.init(this); - taskbarViewController.init(this); + taskbarDragLayerController.init(this, startAnimation); + taskbarViewController.init(this, startAnimation); taskbarScrimViewController.init(this); taskbarUnfoldAnimationController.init(this); taskbarKeyguardController.init(navbarButtonsViewController); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt index f71dea9df8..ca8e4cad9f 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt @@ -30,6 +30,9 @@ class TaskbarDesktopModeController( private lateinit var taskbarControllers: TaskbarControllers private lateinit var taskbarSharedState: TaskbarSharedState + val isInDesktopMode: Boolean + get() = desktopVisibilityController.isInDesktopMode + fun init(controllers: TaskbarControllers, sharedState: TaskbarSharedState) { taskbarControllers = controllers taskbarSharedState = sharedState @@ -42,6 +45,7 @@ class TaskbarDesktopModeController( desktopVisibilityController.isInDesktopModeAndNotInOverview(displayId) override fun onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding: Boolean) { + if (taskbarControllers.taskbarActivityContext.isDestroyed) return taskbarSharedState.showCornerRadiusInDesktopMode = doesAnyTaskRequireTaskbarRounding val cornerRadius = getTaskbarCornerRoundness(doesAnyTaskRequireTaskbarRounding) taskbarControllers.taskbarCornerRoundness.animateToValue(cornerRadius).start() diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java index 59ef57773c..4dbad8c56f 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java @@ -186,6 +186,7 @@ public class TaskbarDragLayer extends BaseDragLayer { @Override protected void dispatchDraw(Canvas canvas) { + if (mContainer.isDestroyed()) return; float backgroundHeight = mControllerCallbacks.getTaskbarBackgroundHeight() * (1f - mTaskbarBackgroundOffset); mBackgroundRenderer.setBackgroundHeight(backgroundHeight); @@ -285,6 +286,21 @@ public class TaskbarDragLayer extends BaseDragLayer { return super.dispatchKeyEvent(event); } + /** + * Sets animation boolean when only animating persistent taskbar. + */ + public void setIsAnimatingPersistentTaskbarBackground(boolean animatingPersistentTaskbarBg) { + mBackgroundRenderer.setAnimatingPersistentTaskbar(animatingPersistentTaskbarBg); + } + + /** + * Sets animation boolean when only animating transient taskbar. + */ + public void setIsAnimatingTransientTaskbarBackground(boolean animatingTransientTaskbarBg) { + mBackgroundRenderer.setAnimatingTransientTaskbar(animatingTransientTaskbarBg); + } + + /** * Sets the width percentage to inset the transient taskbar's background from the left and from * the right. diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java index 68c252a592..55ecc37fb0 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java @@ -15,9 +15,12 @@ */ package com.android.launcher3.taskbar; +import static com.android.app.animation.Interpolators.EMPHASIZED; import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_PERSISTENT; import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_TRANSIENT; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Point; @@ -29,6 +32,7 @@ import android.view.ViewTreeObserver; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.launcher3.anim.AnimatedFloat; +import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.util.DimensionUtils; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.MultiPropertyFactory.MultiProperty; @@ -58,6 +62,8 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa private final AnimatedFloat mImeBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha); private final AnimatedFloat mAssistantBgTaskbar = new AnimatedFloat( this::updateBackgroundAlpha); + private final AnimatedFloat mBgTaskbarRecreate = new AnimatedFloat( + this::updateBackgroundAlpha); // Used to hide our background color when someone else (e.g. ScrimView) is handling it. private final AnimatedFloat mBgOverride = new AnimatedFloat(this::updateBackgroundAlpha); @@ -88,7 +94,10 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa mFolderMargin = resources.getDimensionPixelSize(R.dimen.taskbar_folder_margin); } - public void init(TaskbarControllers controllers) { + /** + * Init of taskbar drag layer controller + */ + public void init(TaskbarControllers controllers, AnimatorSet startAnimation) { mControllers = controllers; mTaskbarStashViaTouchController = new TaskbarStashViaTouchController(mControllers); mTaskbarDragLayer.init(new TaskbarDragLayerCallbacks()); @@ -96,15 +105,45 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa mOnBackgroundNavButtonColorIntensity = mControllers.navbarButtonsViewController .getOnTaskbarBackgroundNavButtonColorOverride(); - mTaskbarBackgroundProgress.updateValue(DisplayController.isTransientTaskbar(mActivity) - ? PINNING_TRANSIENT - : PINNING_PERSISTENT); + + if (startAnimation != null) { + // set taskbar background render animation boolean + if (DisplayController.isTransientTaskbar(mActivity)) { + mTaskbarDragLayer.setIsAnimatingTransientTaskbarBackground(true); + } else { + mTaskbarDragLayer.setIsAnimatingPersistentTaskbarBackground(true); + } + + float desiredValue = DisplayController.isTransientTaskbar(mActivity) + ? PINNING_TRANSIENT + : PINNING_PERSISTENT; + + float nonDesiredvalue = !DisplayController.isTransientTaskbar(mActivity) + ? PINNING_TRANSIENT + : PINNING_PERSISTENT; + + ObjectAnimator objectAnimator = mTaskbarBackgroundProgress.animateToValue( + nonDesiredvalue, desiredValue); + objectAnimator.setInterpolator(EMPHASIZED); + startAnimation.play(objectAnimator); + startAnimation.addListener(AnimatorListeners.forEndCallback(()-> { + // reset taskbar background render animation boolean + mTaskbarDragLayer.setIsAnimatingPersistentTaskbarBackground(false); + mTaskbarDragLayer.setIsAnimatingTransientTaskbarBackground(false); + })); + + } else { + mTaskbarBackgroundProgress.updateValue(DisplayController.isTransientTaskbar(mActivity) + ? PINNING_TRANSIENT + : PINNING_PERSISTENT); + } mBgTaskbar.value = 1; mKeyguardBgTaskbar.value = 1; mNotificationShadeBgTaskbar.value = 1; mImeBgTaskbar.value = 1; mAssistantBgTaskbar.value = 1; + mBgTaskbarRecreate.value = 1; mBgOverride.value = 1; updateBackgroundAlpha(); @@ -112,6 +151,13 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa updateTaskbarAlpha(); } + /** + * Called when destroying Taskbar with animation. + */ + public void onDestroyAnimation(AnimatorSet animatorSet) { + animatorSet.play(mBgTaskbarRecreate.animateToValue(0f)); + } + public void onDestroy() { mTaskbarDragLayer.onDestroy(); } @@ -172,14 +218,14 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa } private void updateBackgroundAlpha() { - if (mActivity.isPhoneMode()) { + if (mActivity.isPhoneMode() || mActivity.isDestroyed()) { return; } final float bgNavbar = mBgNavbar.value; final float bgTaskbar = mBgTaskbar.value * mKeyguardBgTaskbar.value * mNotificationShadeBgTaskbar.value * mImeBgTaskbar.value - * mAssistantBgTaskbar.value; + * mAssistantBgTaskbar.value * mBgTaskbarRecreate.value; mLastSetBackgroundAlpha = mBgOverride.value * Math.max(bgNavbar, bgTaskbar); mBackgroundRendererAlpha.setValue(mLastSetBackgroundAlpha); @@ -266,6 +312,7 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa pw.println(prefix + "\t\tmNotificationShadeBgTaskbar=" + mNotificationShadeBgTaskbar.value); pw.println(prefix + "\t\tmImeBgTaskbar=" + mImeBgTaskbar.value); pw.println(prefix + "\t\tmAssistantBgTaskbar=" + mAssistantBgTaskbar.value); + pw.println(prefix + "\t\tmBgTaskbarRecreate=" + mBgTaskbarRecreate.value); } /** diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index dd9f61e5ef..10eb64a44a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -223,9 +223,13 @@ public class TaskbarLauncherStateController { updateStateForFlag(FLAG_LAUNCHER_IN_STATE_TRANSITION, true); if (!mShouldDelayLauncherStateAnim) { if (toState == LauncherState.NORMAL) { - applyState(QuickstepTransitionManager.getTaskbarToHomeDuration( + boolean isPinnedTaskbarAndNotInDesktopMode = DisplayController.isPinnedTaskbar( - mControllers.taskbarActivityContext))); + mControllers.taskbarActivityContext) + && !DisplayController.isInDesktopMode( + mControllers.taskbarActivityContext); + applyState(QuickstepTransitionManager.getTaskbarToHomeDuration( + isPinnedTaskbarAndNotInDesktopMode)); } else { applyState(); } @@ -680,8 +684,11 @@ public class TaskbarLauncherStateController { } else if (mIconAlignment.isAnimatingToValue(toAlignment) || mIconAlignment.isSettledOnValue(toAlignment)) { // Already at desired value, but make sure we run the callback at the end. - animatorSet.addListener(AnimatorListeners.forEndCallback( - this::onIconAlignmentRatioChanged)); + animatorSet.addListener(AnimatorListeners.forEndCallback(() -> { + if (!mIconAlignment.isAnimating()) { + onIconAlignmentRatioChanged(); + } + })); } else { mIconAlignment.cancelAnimation(); ObjectAnimator iconAlignAnim = mIconAlignment diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java index 34bb6e0a25..5155ffcdd3 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java @@ -26,6 +26,7 @@ import static com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate; import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY; import static com.android.launcher3.util.DisplayController.CHANGE_DESKTOP_MODE; import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE; +import static com.android.launcher3.util.DisplayController.CHANGE_SHOW_LOCKED_TASKBAR; import static com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING; import static com.android.launcher3.util.DisplayController.TASKBAR_NOT_DESTROYED_TAG; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; @@ -33,6 +34,7 @@ import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange; import static com.android.quickstep.util.SystemActionConstants.ACTION_SHOW_TASKBAR; import static com.android.quickstep.util.SystemActionConstants.SYSTEM_ACTION_ID_TASKBAR; +import android.animation.AnimatorSet; import android.annotation.SuppressLint; import android.app.PendingIntent; import android.content.ComponentCallbacks; @@ -62,7 +64,9 @@ import androidx.annotation.VisibleForTesting; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.anim.AnimatorPlaybackController; +import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks; import com.android.launcher3.taskbar.unfold.NonDestroyableScopedUnfoldTransitionProgressProvider; @@ -101,6 +105,7 @@ public class TaskbarManager { // TODO(b/382378283) remove all logs with this tag public static final String NULL_TASKBAR_ROOT_LAYOUT_TAG = "b/382378283"; public static final String ILLEGAL_ARGUMENT_WM_ADD_VIEW = "b/391653300"; + private static final int TASKBAR_DESTROY_DURATION = 100; /** * All the configurations which do not initiate taskbar recreation. @@ -189,13 +194,28 @@ public class TaskbarManager { } if ((flags & (CHANGE_DENSITY | CHANGE_NAVIGATION_MODE | CHANGE_DESKTOP_MODE - | CHANGE_TASKBAR_PINNING)) != 0) { + | CHANGE_TASKBAR_PINNING | CHANGE_SHOW_LOCKED_TASKBAR)) != 0) { debugTaskbarManager("onDisplayInfoChanged - Recreating Taskbar!", context.getDisplayId()); - recreateTaskbar(); + TaskbarActivityContext taskbarActivityContext = getCurrentActivityContext(); + if ((flags & CHANGE_SHOW_LOCKED_TASKBAR) != 0) { + recreateTaskbar(); + } else if ((flags & CHANGE_DESKTOP_MODE) != 0) { + // Only Handles Special Exit Cases for Desktop Mode Taskbar Recreation. + if (taskbarActivityContext != null + && !DesktopVisibilityController.INSTANCE.get(taskbarActivityContext) + .isInDesktopMode() + && !DisplayController.showLockedTaskbarOnHome(context)) { + recreateTaskbar(); + } + } else { + recreateTaskbar(); + } + } } } + private final SettingsCache.OnChangeListener mOnSettingsChangeListener = c -> { debugTaskbarManager("Settings changed! Recreating Taskbar!"); recreateTaskbar(); @@ -258,7 +278,52 @@ public class TaskbarManager { public void onTaskRemoved(int taskId) { mPerceptibleTasks.remove(taskId); } - }; + } + + ; + + private final DesktopVisibilityController.TaskbarDesktopModeListener + mTaskbarDesktopModeListener = + new DesktopVisibilityController.TaskbarDesktopModeListener() { + @Override + public void onExitDesktopMode(int duration) { + for (int taskbarIndex = 0; taskbarIndex < mTaskbars.size(); taskbarIndex++) { + int displayId = mTaskbars.keyAt(taskbarIndex); + TaskbarActivityContext taskbarActivityContext = getTaskbarForDisplay( + displayId); + if (taskbarActivityContext != null + && !taskbarActivityContext.isInOverview()) { + AnimatorSet animatorSet = taskbarActivityContext.onDestroyAnimation( + TASKBAR_DESTROY_DURATION); + animatorSet.addListener(AnimatorListeners.forEndCallback( + () -> recreateTaskbarForDisplay(getDefaultDisplayId(), + duration))); + animatorSet.start(); + } + } + } + + @Override + public void onEnterDesktopMode(int duration) { + for (int taskbarIndex = 0; taskbarIndex < mTaskbars.size(); taskbarIndex++) { + int displayId = mTaskbars.keyAt(taskbarIndex); + TaskbarActivityContext taskbarActivityContext = getTaskbarForDisplay( + displayId); + AnimatorSet animatorSet = taskbarActivityContext.onDestroyAnimation( + TASKBAR_DESTROY_DURATION); + animatorSet.addListener(AnimatorListeners.forEndCallback( + () -> recreateTaskbarForDisplay(getDefaultDisplayId(), duration))); + animatorSet.start(); + } + } + + @Override + public void onTaskbarCornerRoundingUpdate( + boolean doesAnyTaskRequireTaskbarRounding) { + //NO-OP + } + }; + private boolean mUserUnlocked = false; @@ -337,6 +402,9 @@ public class TaskbarManager { debugTaskbarManager("TaskbarManager constructor", primaryDisplayId); mPrimaryWindowContext = createWindowContext(primaryDisplayId); mPrimaryWindowManager = mPrimaryWindowContext.getSystemService(WindowManager.class); + DesktopVisibilityController.INSTANCE.get( + mPrimaryWindowContext).registerTaskbarDesktopModeListener( + mTaskbarDesktopModeListener); createTaskbarRootLayout(primaryDisplayId); createNavButtonController(primaryDisplayId); createAndRegisterComponentCallbacks(primaryDisplayId); @@ -550,13 +618,13 @@ public class TaskbarManager { public synchronized void recreateTaskbar() { // Handles initial creation case. if (mTaskbars.size() == 0) { - recreateTaskbarForDisplay(getDefaultDisplayId()); + recreateTaskbarForDisplay(getDefaultDisplayId(), 0); return; } for (int i = 0; i < mTaskbars.size(); i++) { int displayId = mTaskbars.keyAt(i); - recreateTaskbarForDisplay(displayId); + recreateTaskbarForDisplay(displayId, 0); } } @@ -565,7 +633,7 @@ public class TaskbarManager { * we fully want to destroy an existing taskbar for a specified display and create a new one. * In other case (folding/unfolding) we don't need to remove and add window. */ - private void recreateTaskbarForDisplay(int displayId) { + private void recreateTaskbarForDisplay(int displayId, int duration) { Trace.beginSection("recreateTaskbarForDisplay"); try { Log.d(ILLEGAL_ARGUMENT_WM_ADD_VIEW, "recreateTaskbarForDisplay: " + displayId); @@ -582,13 +650,13 @@ public class TaskbarManager { boolean displayExists = getDisplay(displayId) != null; boolean isTaskbarEnabled = dp != null && isTaskbarEnabled(dp); debugTaskbarManager("recreateTaskbarForDisplay: isTaskbarEnabled=" + isTaskbarEnabled - + " [dp != null (i.e. mUserUnlocked)]=" + (dp != null) - + " FLAG_HIDE_NAVBAR_WINDOW=" + ENABLE_TASKBAR_NAVBAR_UNIFICATION + + " [dp != null (i.e. mUserUnlocked)]=" + (dp != null) + + " FLAG_HIDE_NAVBAR_WINDOW=" + ENABLE_TASKBAR_NAVBAR_UNIFICATION + " dp.isTaskbarPresent=" + (dp == null ? "null" : dp.isTaskbarPresent) + " displayExists=" + displayExists); if (!isTaskbarEnabled || !isLargeScreenTaskbar || !displayExists) { SystemUiProxy.INSTANCE.get(mBaseContext) - .notifyTaskbarStatus(/* visible */ false, /* stashed */ false); + .notifyTaskbarStatus(/* visible */ false, /* stashed */ false); if (!isTaskbarEnabled || !displayExists) { return; } @@ -608,7 +676,7 @@ public class TaskbarManager { mSharedState.startTaskbarVariantIsTransient = DisplayController.isTransientTaskbar(taskbar); mSharedState.allAppsVisible = mSharedState.allAppsVisible && isLargeScreenTaskbar; - taskbar.init(mSharedState); + taskbar.init(mSharedState, duration); // Non default displays should not use LauncherTaskbarUIController as they shouldn't // have access to the Launcher activity. @@ -792,7 +860,7 @@ public class TaskbarManager { createTaskbarRootLayout(displayId); createNavButtonController(displayId); createAndRegisterComponentCallbacks(displayId); - recreateTaskbarForDisplay(displayId); + recreateTaskbarForDisplay(displayId, 0); } } @@ -845,6 +913,9 @@ public class TaskbarManager { public void destroy() { mRecentsViewContainer = null; debugTaskbarManager("TaskbarManager#destroy()"); + DesktopVisibilityController.INSTANCE.get( + mPrimaryWindowContext).unregisterTaskbarDesktopModeListener( + mTaskbarDesktopModeListener); removeActivityCallbacksAndListeners(); mTaskbarBroadcastReceiver.unregisterReceiverSafely(); @@ -860,7 +931,7 @@ public class TaskbarManager { removeAndUnregisterComponentCallbacks(getDefaultDisplayId()); mShutdownReceiver.unregisterReceiverSafely(); if (ActivityManagerWrapper.usePerceptibleTasks(getPrimaryWindowContext())) { - for (Integer taskId: mTaskStackListener.mPerceptibleTasks) { + for (Integer taskId : mTaskStackListener.mPerceptibleTasks) { ActivityManagerWrapper.getInstance().setTaskIsPerceptible(taskId, false); } } @@ -940,7 +1011,7 @@ public class TaskbarManager { * * @param displayId The ID of the display to retrieve the taskbar for. * @return The {@link TaskbarUIController} for the specified display, or - * {@code null} if no taskbar is associated with that display. + * {@code null} if no taskbar is associated with that display. */ @Nullable public TaskbarUIController getUIControllerForDisplay(int displayId) { @@ -967,7 +1038,7 @@ public class TaskbarManager { * * @param displayId The ID of the display to retrieve the taskbar for. * @return The {@link TaskbarActivityContext} for the specified display, or - * {@code null} if no taskbar is associated with that display. + * {@code null} if no taskbar is associated with that display. */ private TaskbarActivityContext getTaskbarForDisplay(int displayId) { return mTaskbars.get(displayId); @@ -976,7 +1047,8 @@ public class TaskbarManager { /** * Creates a {@link TaskbarActivityContext} for the given display and adds it to the map. - * @param dp The {@link DeviceProfile} for the display. + * + * @param dp The {@link DeviceProfile} for the display. * @param displayId The ID of the display. */ private @Nullable TaskbarActivityContext createTaskbarActivityContext(DeviceProfile dp, @@ -1008,6 +1080,7 @@ public class TaskbarManager { /** * Create {@link ComponentCallbacks} for the given display and register it to the relevant * WindowContext. For external displays, populate maps. + * * @param displayId The ID of the display. */ private void createAndRegisterComponentCallbacks(int displayId) { @@ -1065,7 +1138,8 @@ public class TaskbarManager { } @Override - public void onLowMemory() { } + public void onLowMemory() { + } }; if (isDefaultDisplay(displayId) || !DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue()) { @@ -1080,6 +1154,7 @@ public class TaskbarManager { /** * Unregister {@link ComponentCallbacks} for the given display from its WindowContext. For * external displays, remove from the map. + * * @param displayId The ID of the display. */ private void removeAndUnregisterComponentCallbacks(int displayId) { @@ -1096,6 +1171,7 @@ public class TaskbarManager { /** * Creates a {@link TaskbarNavButtonController} for the given display and adds it to the map * if it doesn't already exist. + * * @param displayId The ID of the display */ private void createNavButtonController(int displayId) { @@ -1137,7 +1213,7 @@ public class TaskbarManager { * Adds the {@link TaskbarActivityContext} associated with the given display ID to taskbar * map if there is not already a taskbar mapped to that displayId. * - * @param displayId The ID of the display to retrieve the taskbar for. + * @param displayId The ID of the display to retrieve the taskbar for. * @param newTaskbar The new {@link TaskbarActivityContext} to add to the map. */ private void addTaskbarToMap(int displayId, TaskbarActivityContext newTaskbar) { @@ -1157,6 +1233,7 @@ public class TaskbarManager { /** * Creates {@link FrameLayout} for the taskbar on the specified display and adds it to map. + * * @param displayId The ID of the display for which to create the taskbar root layout. */ private void createTaskbarRootLayout(int displayId) { @@ -1206,7 +1283,7 @@ public class TaskbarManager { /** * Adds the taskbar root layout {@link FrameLayout} to taskbar map, mapped to display ID. * - * @param displayId The ID of the display to associate with the taskbar root layout. + * @param displayId The ID of the display to associate with the taskbar root layout. * @param rootLayout The taskbar root layout {@link FrameLayout} to add to the map. */ private void addTaskbarRootLayoutToMap(int displayId, FrameLayout rootLayout) { @@ -1233,6 +1310,7 @@ public class TaskbarManager { /** * Creates {@link Context} for the taskbar on the specified display. + * * @param displayId The ID of the display for which to create the window context. */ private @Nullable Context createWindowContext(int displayId) { @@ -1312,7 +1390,7 @@ public class TaskbarManager { /** * Adds the window context {@link Context} to taskbar map, mapped to display ID. * - * @param displayId The ID of the display to associate with the taskbar root layout. + * @param displayId The ID of the display to associate with the taskbar root layout. * @param windowContext The window context {@link Context} to add to the map. */ private void addWindowContextToMap(int displayId, @NonNull Context windowContext) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index a59c9e3fa3..c92f20b283 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -392,6 +392,7 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar /** Inflates/binds the hotseat items and recent tasks to the view. */ protected void updateItems(ItemInfo[] hotseatItemInfos, List recentTasks) { + if (mActivityContext.isDestroyed()) return; // Filter out unsupported items. hotseatItemInfos = Arrays.stream(hotseatItemInfos) .filter(Objects::nonNull) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index cbc5d3d63b..384468c9fc 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -121,9 +121,10 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar public static final int ALPHA_INDEX_NOTIFICATION_EXPANDED = 4; public static final int ALPHA_INDEX_ASSISTANT_INVOKED = 5; public static final int ALPHA_INDEX_SMALL_SCREEN = 6; - public static final int ALPHA_INDEX_BUBBLE_BAR = 7; - private static final int NUM_ALPHA_CHANNELS = 8; + public static final int ALPHA_INDEX_RECREATE = 8; + + private static final int NUM_ALPHA_CHANNELS = 9; /** Only used for animation purposes, to position the divider between two item indices. */ public static final float DIVIDER_VIEW_POSITION_OFFSET = 0.5f; @@ -238,9 +239,22 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar R.dimen.transient_taskbar_padding); } - public void init(TaskbarControllers controllers) { + /** + * Init of taskbar view controller. + */ + public void init(TaskbarControllers controllers, AnimatorSet startAnimation) { mControllers = controllers; controllers.bubbleControllers.ifPresent(bc -> mBubbleControllers = bc); + + if (startAnimation != null) { + MultiPropertyFactory.MultiProperty multiProperty = + mTaskbarIconAlpha.get(ALPHA_INDEX_RECREATE); + multiProperty.setValue(0f); + Animator animator = multiProperty.animateToValue(1f); + animator.setInterpolator(EMPHASIZED); + startAnimation.play(animator); + } + mTaskbarView.init(TaskbarViewCallbacksFactory.newInstance(mActivity).create( mActivity, mControllers, mTaskbarView)); mTaskbarView.getLayoutParams().height = mActivity.isPhoneMode() @@ -362,6 +376,15 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar mTaskbarView.announceAccessibilityChanges(); } + /** + * Called with destroying Taskbar with animation. + */ + public void onDestroyAnimation(AnimatorSet animatorSet) { + animatorSet.play( + mTaskbarIconAlpha.get(TaskbarViewController.ALPHA_INDEX_RECREATE).animateToValue( + 0f)); + } + public void onDestroy() { if (enableTaskbarPinning()) { mTaskbarView.removeOnLayoutChangeListener(mTaskbarViewLayoutChangeListener); @@ -1299,7 +1322,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar ObjectAnimator animator = mIconsTranslationXForNavbar.animateToValue(translationX); animator.setStartDelay(FADE_OUT_ANIM_POSITION_DURATION_MS); animator.setDuration(FADE_IN_ANIM_ALPHA_DURATION_MS); - animator.setInterpolator(Interpolators.EMPHASIZED); + animator.setInterpolator(EMPHASIZED); return animator; } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java index 1907b4efd7..44f8bf1e07 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java @@ -109,8 +109,11 @@ 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. + boolean isPinnedTaskbarAndNotInDesktopMode = + isPinnedTaskbar && !DisplayController.isInDesktopMode(mContainer); float scrimUpperBoundFromSplit = - QuickstepTransitionManager.getTaskbarToHomeDuration(isPinnedTaskbar) + QuickstepTransitionManager.getTaskbarToHomeDuration( + isPinnedTaskbarAndNotInDesktopMode) / (float) config.duration; scrimUpperBoundFromSplit = Math.min(scrimUpperBoundFromSplit, 1f); config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, clampToProgress(LINEAR, 0, 0.25f)); @@ -142,7 +145,8 @@ public class QuickstepAtomicAnimationFactory extends if (mContainer.getDeviceProfile().isTaskbarPresent) { config.duration = Math.min( config.duration, - QuickstepTransitionManager.getTaskbarToHomeDuration(isPinnedTaskbar)); + QuickstepTransitionManager.getTaskbarToHomeDuration( + isPinnedTaskbarAndNotInDesktopMode)); } overview.snapToPage(DEFAULT_PAGE, Math.toIntExact(config.duration)); } else { diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 67a54e6c44..c51f65942d 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -120,6 +120,7 @@ import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.logging.StatsLogManager.StatsLogger; +import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.statemanager.BaseState; import com.android.launcher3.statemanager.StatefulContainer; import com.android.launcher3.taskbar.TaskbarThresholdUtils; @@ -1421,8 +1422,10 @@ public abstract class AbsSwipeUpHandler< } if (endTarget == HOME) { boolean isPinnedTaskbar = DisplayController.isPinnedTaskbar(mContext); + boolean isNotInDesktop = !DisplayController.isInDesktopMode(mContext); duration = mContainer != null && mContainer.getDeviceProfile().isTaskbarPresent - ? QuickstepTransitionManager.getTaskbarToHomeDuration(isPinnedTaskbar) + ? QuickstepTransitionManager.getTaskbarToHomeDuration( + isPinnedTaskbar && isNotInDesktop) : StaggeredWorkspaceAnim.DURATION_MS; SystemUiProxy.INSTANCE.get(mContext).updateContextualEduStats( mGestureState.isTrackpadGesture(), GestureType.HOME); @@ -1601,10 +1604,28 @@ public abstract class AbsSwipeUpHandler< mTaskAnimationManager.getCurrentCallbacks()); if (mParallelRunningAnim != null) { mParallelRunningAnim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + if (DisplayController.isInDesktopMode(mContext) + && mGestureState.getEndTarget() == HOME) { + // Set launcher animation started, so we don't notify from + // desktop visibility controller + DesktopVisibilityController.INSTANCE.get( + mContext).setLauncherAnimationRunning(true); + } + } + @Override public void onAnimationEnd(Animator animation) { mParallelRunningAnim = null; mStateCallback.setStateOnUiThread(STATE_PARALLEL_ANIM_FINISHED); + // Swipe to home animation finished, notify DesktopVisibilityController + // to recreate Taskbar + if (DisplayController.isInDesktopMode(mContext) + && mGestureState.getEndTarget() == HOME) { + DesktopVisibilityController.INSTANCE.get( + mContext).onLauncherAnimationFromDesktopEnd(); + } } }); mParallelRunningAnim.start(); @@ -1691,7 +1712,6 @@ public abstract class AbsSwipeUpHandler< if (mHandOffAnimationToHome) { handOffAnimation(velocityPxPerMs); } - windowAnim[0].addAnimatorListener(new AnimationSuccessListener() { @Override public void onAnimationSuccess(Animator animator) { diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java index 12ca25702e..a2856a6012 100644 --- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java +++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java @@ -81,8 +81,10 @@ public class StaggeredWorkspaceAnim { public StaggeredWorkspaceAnim(QuickstepLauncher launcher, float velocity, boolean animateOverviewScrim, @Nullable View ignoredView, boolean staggerWorkspace) { + boolean isPinnedTaskbarAndNotInDesktopMode = DisplayController.isPinnedTaskbar(launcher) + && !DisplayController.isInDesktopMode(launcher); mTaskbarDurationInMs = QuickstepTransitionManager.getTaskbarToHomeDuration( - DisplayController.isPinnedTaskbar(launcher)); + isPinnedTaskbarAndNotInDesktopMode); prepareToAnimate(launcher, animateOverviewScrim); mIgnoredView = ignoredView; diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt index 2cd09cc4a1..3a27bb1683 100644 --- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt @@ -333,10 +333,12 @@ class TaskbarOverflowTest { Task(Task.TaskKey(it, 0, Intent(), ComponentName("", ""), 0, 2000)) } recentsModel.updateRecentTasks(listOf(DesktopTask(deskId = 0, tasks))) - desktopTaskListener?.onTasksVisibilityChanged( - context.virtualDisplay.display.displayId, - tasksToAdd, - ) + for (task in 1..tasksToAdd) { + desktopTaskListener?.onTasksVisibilityChanged( + context.virtualDisplay.display.displayId, + task, + ) + } runOnMainSync { recentsModel.resolvePendingTaskRequests() } } diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt index 002c988736..8376bc183c 100644 --- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt @@ -959,6 +959,8 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { private fun setInDesktopMode(inDesktopMode: Boolean) { whenever(taskbarControllers.taskbarDesktopModeController.shouldShowDesktopTasksInTaskbar()) .thenReturn(inDesktopMode) + whenever(taskbarControllers.taskbarDesktopModeController.isInDesktopMode) + .thenReturn(inDesktopMode) } private fun createItemInfo( diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java index 376a61e12c..ceece4d5ce 100644 --- a/src/com/android/launcher3/util/DisplayController.java +++ b/src/com/android/launcher3/util/DisplayController.java @@ -99,10 +99,11 @@ public class DisplayController implements ComponentCallbacks, public static final int CHANGE_NAVIGATION_MODE = 1 << 4; public static final int CHANGE_TASKBAR_PINNING = 1 << 5; public static final int CHANGE_DESKTOP_MODE = 1 << 6; + public static final int CHANGE_SHOW_LOCKED_TASKBAR = 1 << 7; public static final int CHANGE_ALL = CHANGE_ACTIVE_SCREEN | CHANGE_ROTATION | CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS | CHANGE_NAVIGATION_MODE - | CHANGE_TASKBAR_PINNING | CHANGE_DESKTOP_MODE; + | CHANGE_TASKBAR_PINNING | CHANGE_DESKTOP_MODE | CHANGE_SHOW_LOCKED_TASKBAR; private static final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED"; private static final String TARGET_OVERLAY_PACKAGE = "android"; @@ -211,6 +212,13 @@ public class DisplayController implements ComponentCallbacks, return INSTANCE.get(context).getInfo().isPinnedTaskbar(); } + /** + * Returns whether the taskbar is pinned in gesture navigation mode. + */ + public static boolean isInDesktopMode(Context context) { + return INSTANCE.get(context).getInfo().isInDesktopMode(); + } + /** * Returns whether the taskbar is forced to be pinned when home is visible. */ @@ -335,6 +343,9 @@ public class DisplayController implements ComponentCallbacks, if (newInfo.mIsInDesktopMode != oldInfo.mIsInDesktopMode) { change |= CHANGE_DESKTOP_MODE; } + if (newInfo.mShowLockedTaskbarOnHome != oldInfo.mShowLockedTaskbarOnHome) { + change |= CHANGE_SHOW_LOCKED_TASKBAR; + } if (DEBUG) { Log.d(TAG, "handleInfoChange - change: " + getChangeFlagsString(change)); @@ -493,6 +504,13 @@ public class DisplayController implements ComponentCallbacks, return navigationMode == NavigationMode.NO_BUTTON && !isTransientTaskbar(); } + /** + * Returns whether the taskbar is in desktop mode. + */ + public boolean isInDesktopMode() { + return mIsInDesktopMode; + } + /** * Returns {@code true} if the bounds represent a tablet. */ @@ -575,6 +593,7 @@ public class DisplayController implements ComponentCallbacks, appendFlag(result, change, CHANGE_NAVIGATION_MODE, "CHANGE_NAVIGATION_MODE"); appendFlag(result, change, CHANGE_TASKBAR_PINNING, "CHANGE_TASKBAR_VARIANT"); appendFlag(result, change, CHANGE_DESKTOP_MODE, "CHANGE_DESKTOP_MODE"); + appendFlag(result, change, CHANGE_SHOW_LOCKED_TASKBAR, "CHANGE_SHOW_LOCKED_TASKBAR"); return result.toString(); } @@ -592,6 +611,7 @@ public class DisplayController implements ComponentCallbacks, pw.println(" isTaskbarPinned=" + info.mIsTaskbarPinned); pw.println(" isTaskbarPinnedInDesktopMode=" + info.mIsTaskbarPinnedInDesktopMode); pw.println(" isInDesktopMode=" + info.mIsInDesktopMode); + pw.println(" showLockedTaskbarOnHome=" + info.showLockedTaskbarOnHome()); pw.println(" currentSize=" + info.currentSize); info.mPerDisplayBounds.forEach((key, value) -> pw.println( " perDisplayBounds - " + key + ": " + value)); diff --git a/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt index aa1451b53a..0ecb38eb0f 100644 --- a/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt +++ b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt @@ -34,6 +34,7 @@ import com.android.launcher3.dagger.LauncherAppSingleton import com.android.launcher3.util.DisplayController.CHANGE_DENSITY import com.android.launcher3.util.DisplayController.CHANGE_DESKTOP_MODE import com.android.launcher3.util.DisplayController.CHANGE_ROTATION +import com.android.launcher3.util.DisplayController.CHANGE_SHOW_LOCKED_TASKBAR import com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext @@ -209,8 +210,13 @@ class DisplayControllerTest { assertTrue(displayController.getInfo().isTransientTaskbar()) displayController.notifyConfigChange() + verify(displayInfoChangeListener) - .onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING)) + .onDisplayInfoChanged( + any(), + any(), + eq(CHANGE_TASKBAR_PINNING or CHANGE_SHOW_LOCKED_TASKBAR), + ) assertFalse(displayController.getInfo().isTransientTaskbar()) } @@ -227,7 +233,11 @@ class DisplayControllerTest { displayController.onConfigurationChanged(configuration) verify(displayInfoChangeListener) - .onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING)) + .onDisplayInfoChanged( + any(), + any(), + eq(CHANGE_TASKBAR_PINNING or CHANGE_SHOW_LOCKED_TASKBAR), + ) assertFalse(displayController.getInfo().isTransientTaskbar()) }