diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java index 644705b292..e31b1d4075 100644 --- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java +++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java @@ -36,10 +36,10 @@ import com.android.launcher3.util.DisplayController; import com.android.quickstep.GestureState; import com.android.quickstep.SystemUiProxy; import com.android.wm.shell.desktopmode.IDesktopTaskListener; +import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import java.util.HashSet; import java.util.Set; -import java.util.concurrent.Executor; /** * Controls the visibility of the workspace and the resumed / paused state when desktop mode @@ -51,6 +51,7 @@ public class DesktopVisibilityController { private static final boolean DEBUG = false; private final Launcher mLauncher; private final Set mDesktopVisibilityListeners = new HashSet<>(); + private final Set mTaskbarDesktopModeListeners = new HashSet<>(); private int mVisibleDesktopTasksCount; private boolean mInOverviewState; @@ -110,6 +111,16 @@ public class DesktopVisibilityController { mDesktopVisibilityListeners.remove(listener); } + /** Registers a listener for Taskbar changes in Desktop Mode. */ + public void registerTaskbarDesktopModeListener(TaskbarDesktopModeListener listener) { + mTaskbarDesktopModeListeners.add(listener); + } + + /** Removes a previously registered listener for Taskbar changes in Desktop Mode. */ + public void unregisterTaskbarDesktopModeListener(TaskbarDesktopModeListener listener) { + mTaskbarDesktopModeListeners.remove(listener); + } + /** * Sets the number of desktop windows that are visible and updates launcher visibility based on * it. @@ -201,6 +212,16 @@ public class DesktopVisibilityController { DisplayController.handleInfoChangeForDesktopMode(mLauncher); } + private void notifyTaskbarDesktopModeListeners(boolean doesAnyTaskRequireTaskbarRounding) { + if (DEBUG) { + Log.d(TAG, "notifyTaskbarDesktopModeListeners: doesAnyTaskRequireTaskbarRounding=" + + doesAnyTaskRequireTaskbarRounding); + } + for (TaskbarDesktopModeListener listener : mTaskbarDesktopModeListeners) { + listener.onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding); + } + } + /** * TODO: b/333533253 - Remove after flag rollout */ @@ -377,7 +398,29 @@ public class DesktopVisibilityController { @Override public void onStashedChanged(int displayId, boolean stashed) { - Log.w(TAG, "IDesktopTaskListener: onStashedChanged is deprecated"); + Log.w(TAG, "DesktopTaskListenerImpl: onStashedChanged is deprecated"); + } + + @Override + public void onTaskbarCornerRoundingUpdate(boolean doesAnyTaskRequireTaskbarRounding) { + MAIN_EXECUTOR.execute(() -> { + if (mController != null && DesktopModeStatus.useRoundedCorners()) { + Log.d(TAG, "DesktopTaskListenerImpl: doesAnyTaskRequireTaskbarRounding= " + + doesAnyTaskRequireTaskbarRounding); + mController.notifyTaskbarDesktopModeListeners( + doesAnyTaskRequireTaskbarRounding); + } + }); } } + + /** A listener for Taskbar in Desktop Mode. */ + public interface TaskbarDesktopModeListener { + /** + * Callback for when task is resized in desktop mode. + * + * @param doesAnyTaskRequireTaskbarRounding whether task requires taskbar corner roundness. + */ + void onTaskbarCornerRoundingUpdate(boolean doesAnyTaskRequireTaskbarRounding); + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index cd1eea2f0a..02f4bdc86f 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -347,8 +347,9 @@ public class TaskbarActivityContext extends BaseTaskbarContext { new KeyboardQuickSwitchController(), new TaskbarPinningController(this, () -> DisplayController.isInDesktopMode(this)), - bubbleControllersOptional); - + bubbleControllersOptional, + new TaskbarDesktopModeController( + LauncherActivityInterface.INSTANCE::getDesktopVisibilityController)); mLauncherPrefs = LauncherPrefs.get(this); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt index ee64060e3e..4ac7514f2f 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt @@ -24,6 +24,7 @@ import android.graphics.Path import android.graphics.Rect import android.graphics.RectF import com.android.app.animation.Interpolators +import com.android.internal.policy.ScreenDecorationsUtils import com.android.launcher3.R import com.android.launcher3.Utilities import com.android.launcher3.Utilities.mapRange @@ -70,8 +71,8 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) { private var keyShadowDistance = 0f private var bottomMargin = 0 - private val fullCornerRadius = context.cornerRadius.toFloat() - private var cornerRadius = fullCornerRadius + private val fullCornerRadius: Float + private var cornerRadius = 0f private var widthInsetPercentage = 0f private val square = Path() private val circle = Path() @@ -101,7 +102,14 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) { shadowAlpha = LIGHT_THEME_SHADOW_ALPHA } - setCornerRoundness(DEFAULT_ROUNDNESS) + if (DisplayController.isInDesktopMode(context)) { + fullCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context) + cornerRadius = fullCornerRadius + } else { + fullCornerRadius = context.cornerRadius.toFloat() + cornerRadius = fullCornerRadius + setCornerRoundness(MAX_ROUNDNESS) + } } fun updateStashedHandleWidth(context: TaskbarActivityContext, res: Resources) { @@ -273,7 +281,7 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) { } companion object { - const val DEFAULT_ROUNDNESS = 1f + const val MAX_ROUNDNESS = 1f private const val DARK_THEME_STROKE_ALPHA = 51 private const val LIGHT_THEME_STROKE_ALPHA = 41 private const val DARK_THEME_SHADOW_ALPHA = 51f diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java index d94d917579..34ab9f0d67 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java @@ -25,6 +25,7 @@ import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController; import com.android.launcher3.taskbar.bubbles.BubbleControllers; import com.android.launcher3.taskbar.overlay.TaskbarOverlayController; +import com.android.launcher3.util.DisplayController; import com.android.systemui.shared.rotation.RotationButtonController; import java.io.PrintWriter; @@ -64,6 +65,7 @@ public class TaskbarControllers { public final KeyboardQuickSwitchController keyboardQuickSwitchController; public final TaskbarPinningController taskbarPinningController; public final Optional bubbleControllers; + public final TaskbarDesktopModeController taskbarDesktopModeController; @Nullable private LoggableTaskbarController[] mControllersToLog = null; @Nullable private BackgroundRendererController[] mBackgroundRendererControllers = null; @@ -111,7 +113,8 @@ public class TaskbarControllers { TaskbarEduTooltipController taskbarEduTooltipController, KeyboardQuickSwitchController keyboardQuickSwitchController, TaskbarPinningController taskbarPinningController, - Optional bubbleControllers) { + Optional bubbleControllers, + TaskbarDesktopModeController taskbarDesktopModeController) { this.taskbarActivityContext = taskbarActivityContext; this.taskbarDragController = taskbarDragController; this.navButtonController = navButtonController; @@ -138,6 +141,7 @@ public class TaskbarControllers { this.keyboardQuickSwitchController = keyboardQuickSwitchController; this.taskbarPinningController = taskbarPinningController; this.bubbleControllers = bubbleControllers; + this.taskbarDesktopModeController = taskbarDesktopModeController; } /** @@ -173,6 +177,7 @@ public class TaskbarControllers { taskbarEduTooltipController.init(this); keyboardQuickSwitchController.init(this); taskbarPinningController.init(this, mSharedState); + taskbarDesktopModeController.init(this, mSharedState); mControllersToLog = new LoggableTaskbarController[] { taskbarDragController, navButtonController, navbarButtonsViewController, @@ -188,7 +193,13 @@ public class TaskbarControllers { taskbarDragLayerController, taskbarScrimViewController, voiceInteractionWindowController }; - mCornerRoundness.updateValue(TaskbarBackgroundRenderer.DEFAULT_ROUNDNESS); + + if (DisplayController.isInDesktopMode(taskbarActivityContext)) { + mCornerRoundness.updateValue(taskbarDesktopModeController.getTaskbarCornerRoundness( + mSharedState.showCornerRadiusInDesktopMode)); + } else { + mCornerRoundness.updateValue(TaskbarBackgroundRenderer.MAX_ROUNDNESS); + } mAreAllControllersInitialized = true; for (Runnable postInitCallback : mPostInitCallbacks) { @@ -248,6 +259,7 @@ public class TaskbarControllers { keyboardQuickSwitchController.onDestroy(); taskbarStashController.onDestroy(); bubbleControllers.ifPresent(controllers -> controllers.onDestroy()); + taskbarDesktopModeController.onDestroy(); mControllersToLog = null; mBackgroundRendererControllers = null; diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt new file mode 100644 index 0000000000..a376531b11 --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.taskbar + +import com.android.launcher3.statehandlers.DesktopVisibilityController +import com.android.launcher3.statehandlers.DesktopVisibilityController.TaskbarDesktopModeListener +import com.android.launcher3.taskbar.TaskbarBackgroundRenderer.Companion.MAX_ROUNDNESS + +/** Handles Taskbar in Desktop Windowing mode. */ +class TaskbarDesktopModeController( + private val desktopVisibilityControllerProvider: () -> DesktopVisibilityController? +) : TaskbarDesktopModeListener { + private lateinit var taskbarControllers: TaskbarControllers + private lateinit var taskbarSharedState: TaskbarSharedState + + private val desktopVisibilityController: DesktopVisibilityController? + get() = desktopVisibilityControllerProvider() + + fun init(controllers: TaskbarControllers, sharedState: TaskbarSharedState) { + taskbarControllers = controllers + taskbarSharedState = sharedState + desktopVisibilityController?.registerTaskbarDesktopModeListener(this) + } + + override fun onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding: Boolean) { + taskbarSharedState.showCornerRadiusInDesktopMode = doesAnyTaskRequireTaskbarRounding + val cornerRadius = getTaskbarCornerRoundness(doesAnyTaskRequireTaskbarRounding) + taskbarControllers.taskbarCornerRoundness.animateToValue(cornerRadius).start() + } + + fun getTaskbarCornerRoundness(doesAnyTaskRequireTaskbarRounding: Boolean): Float { + return if (doesAnyTaskRequireTaskbarRounding) { + MAX_ROUNDNESS + } else { + 0f + } + } + + fun onDestroy() = desktopVisibilityController?.unregisterTaskbarDesktopModeListener(this) +} diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index 5c3add29a0..cc56d037b9 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -47,6 +47,7 @@ import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.statemanager.StateManager; import com.android.launcher3.uioverrides.QuickstepLauncher; +import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.MultiPropertyFactory.MultiProperty; import com.android.quickstep.RecentsAnimationCallbacks; import com.android.quickstep.RecentsAnimationController; @@ -584,6 +585,12 @@ public class TaskbarLauncherStateController { float cornerRoundness = isInLauncher ? 0 : 1; + if (DisplayController.isInDesktopMode(mLauncher) && mControllers.getSharedState() != null) { + cornerRoundness = + mControllers.taskbarDesktopModeController.getTaskbarCornerRoundness( + mControllers.getSharedState().showCornerRadiusInDesktopMode); + } + // Don't animate if corner roundness has reached desired value. if (mTaskbarCornerRoundness.isAnimating() || mTaskbarCornerRoundness.value != cornerRoundness) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java index 77bd35ffe5..729cbe951f 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java @@ -102,5 +102,8 @@ public class TaskbarSharedState { // To track if taskbar was stashed / unstashed between configuration changes (which recreates // the task bar). - public Boolean taskbarWasStashedAuto = true; + public boolean taskbarWasStashedAuto = true; + + // should show corner radius on persistent taskbar when in desktop mode. + public boolean showCornerRadiusInDesktopMode = false; } diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarDesktopModeControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarDesktopModeControllerTest.kt new file mode 100644 index 0000000000..72bbfc9496 --- /dev/null +++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarDesktopModeControllerTest.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.taskbar + +import androidx.test.platform.app.InstrumentationRegistry +import com.android.launcher3.taskbar.TaskbarBackgroundRenderer.Companion.MAX_ROUNDNESS +import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule +import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext +import com.android.launcher3.util.LauncherMultivalentJUnit +import com.google.common.truth.Truth.assertThat +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(LauncherMultivalentJUnit::class) +@LauncherMultivalentJUnit.EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"]) +class TaskbarDesktopModeControllerTest { + + private val context = + TaskbarWindowSandboxContext.create( + InstrumentationRegistry.getInstrumentation().targetContext + ) + + @get:Rule(order = 0) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context) + + @TaskbarUnitTestRule.InjectController + lateinit var taskbarDesktopModeController: TaskbarDesktopModeController + + @Test + fun whenTaskbarRequiresCornerRoundness_shouldReturnDefaultCornerRoundness() { + assertThat(taskbarDesktopModeController.getTaskbarCornerRoundness(true)) + .isEqualTo(MAX_ROUNDNESS) + } + + @Test + fun whenTaskbarRequiresCornerRoundness_shouldReturnZeroAsCornerRoundness() { + assertThat(taskbarDesktopModeController.getTaskbarCornerRoundness(false)).isEqualTo(0f) + } +} diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt index 15b1e532bd..d064f4aef7 100644 --- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt +++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt @@ -57,6 +57,7 @@ abstract class TaskbarBaseTestCase { @Mock lateinit var keyboardQuickSwitchController: KeyboardQuickSwitchController @Mock lateinit var taskbarPinningController: TaskbarPinningController @Mock lateinit var optionalBubbleControllers: Optional + @Mock lateinit var taskbarDesktopModeController: TaskbarDesktopModeController lateinit var taskbarControllers: TaskbarControllers @@ -98,6 +99,7 @@ abstract class TaskbarBaseTestCase { keyboardQuickSwitchController, taskbarPinningController, optionalBubbleControllers, + taskbarDesktopModeController ) } }