diff options
4 files changed, 167 insertions, 33 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java index dc82fc1b35dd..88949b2a5acd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java @@ -55,6 +55,26 @@ public class DesktopModeStatus { "persist.wm.debug.desktop_stashing", false); /** + * Flag to indicate whether to apply shadows to windows in desktop mode. + */ + private static final boolean USE_WINDOW_SHADOWS = SystemProperties.getBoolean( + "persist.wm.debug.desktop_use_window_shadows", true); + + /** + * Flag to indicate whether to apply shadows to the focused window in desktop mode. + * + * Note: this flag is only relevant if USE_WINDOW_SHADOWS is false. + */ + private static final boolean USE_WINDOW_SHADOWS_FOCUSED_WINDOW = SystemProperties.getBoolean( + "persist.wm.debug.desktop_use_window_shadows_focused_window", false); + + /** + * Flag to indicate whether to apply shadows to windows in desktop mode. + */ + private static final boolean USE_ROUNDED_CORNERS = SystemProperties.getBoolean( + "persist.wm.debug.desktop_use_rounded_corners", true); + + /** * Return {@code true} is desktop windowing proto 2 is enabled */ public static boolean isEnabled() { @@ -81,4 +101,21 @@ public class DesktopModeStatus { public static boolean isStashingEnabled() { return IS_STASHING_ENABLED; } + + /** + * Return whether to use window shadows. + * + * @param isFocusedWindow whether the window to apply shadows to is focused + */ + public static boolean useWindowShadow(boolean isFocusedWindow) { + return USE_WINDOW_SHADOWS + || (USE_WINDOW_SHADOWS_FOCUSED_WINDOW && isFocusedWindow); + } + + /** + * Return whether to use rounded corners for windows. + */ + public static boolean useRoundedCorners() { + return USE_ROUNDED_CORNERS; + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index 144555dd70c3..4a1bcaa7168a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -721,6 +721,9 @@ class DesktopTasksController( finishTransaction: SurfaceControl.Transaction ) { // Add rounded corners to freeform windows + if (!DesktopModeStatus.useRoundedCorners()) { + return + } val cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context) info.changes .filter { it.taskInfo?.windowingMode == WINDOWING_MODE_FREEFORM } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index 3b6be8afb9e7..2f51278e3c80 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -46,6 +46,7 @@ import android.view.ViewConfiguration; import android.widget.ImageButton; import android.window.WindowContainerTransaction; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.ScreenDecorationsUtils; import com.android.launcher3.icons.BaseIconFactory; import com.android.launcher3.icons.IconProvider; @@ -195,46 +196,16 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin void relayout(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT, boolean applyStartTransactionOnDraw) { - final int shadowRadiusID = taskInfo.isFocused - ? R.dimen.freeform_decor_shadow_focused_thickness - : R.dimen.freeform_decor_shadow_unfocused_thickness; - final boolean isFreeform = - taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM; - final boolean isDragResizeable = isFreeform && taskInfo.isResizeable; - if (isHandleMenuActive()) { mHandleMenu.relayout(startT); } + updateRelayoutParams(mRelayoutParams, mContext, taskInfo, applyStartTransactionOnDraw); + final WindowDecorLinearLayout oldRootView = mResult.mRootView; final SurfaceControl oldDecorationSurface = mDecorationContainerSurface; final WindowContainerTransaction wct = new WindowContainerTransaction(); - final int windowDecorLayoutId = getDesktopModeWindowDecorLayoutId( - taskInfo.getWindowingMode()); - mRelayoutParams.reset(); - mRelayoutParams.mRunningTaskInfo = taskInfo; - mRelayoutParams.mLayoutResId = windowDecorLayoutId; - mRelayoutParams.mCaptionHeightId = getCaptionHeightId(taskInfo.getWindowingMode()); - mRelayoutParams.mShadowRadiusId = shadowRadiusID; - mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw; - // The configuration used to lay out the window decoration. The system context's config is - // used when the task density has been overridden to a custom density so that the resources - // and views of the decoration aren't affected and match the rest of the System UI, if not - // then just use the task's configuration. A copy is made instead of using the original - // reference so that the configuration isn't mutated on config changes and diff checks can - // be made in WindowDecoration#relayout using the pre/post-relayout configuration. - // See b/301119301. - // TODO(b/301119301): consider moving the config data needed for diffs to relayout params - // instead of using a whole Configuration as a parameter. - final Configuration windowDecorConfig = new Configuration(); - windowDecorConfig.setTo(DesktopTasksController.isDesktopDensityOverrideSet() - ? mContext.getResources().getConfiguration() // Use system context. - : mTaskInfo.configuration); // Use task configuration. - mRelayoutParams.mWindowDecorConfig = windowDecorConfig; - - mRelayoutParams.mCornerRadius = - (int) ScreenDecorationsUtils.getWindowCornerRadius(mContext); relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult); // After this line, mTaskInfo is up-to-date and should be used instead of taskInfo @@ -273,6 +244,9 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin closeMaximizeMenu(); } + final boolean isFreeform = + taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM; + final boolean isDragResizeable = isFreeform && taskInfo.isResizeable; if (!isDragResizeable) { if (!mTaskInfo.positionInParent.equals(mPositionInParent)) { // We still want to track caption bar's exclusion region on a non-resizeable task. @@ -323,6 +297,45 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } } + @VisibleForTesting + static void updateRelayoutParams( + RelayoutParams relayoutParams, + Context context, + ActivityManager.RunningTaskInfo taskInfo, + boolean applyStartTransactionOnDraw) { + relayoutParams.reset(); + relayoutParams.mRunningTaskInfo = taskInfo; + relayoutParams.mLayoutResId = + getDesktopModeWindowDecorLayoutId(taskInfo.getWindowingMode()); + relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode()); + if (DesktopModeStatus.useWindowShadow(/* isFocusedWindow= */ taskInfo.isFocused)) { + relayoutParams.mShadowRadiusId = taskInfo.isFocused + ? R.dimen.freeform_decor_shadow_focused_thickness + : R.dimen.freeform_decor_shadow_unfocused_thickness; + } + relayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw; + // The configuration used to lay out the window decoration. The system context's config is + // used when the task density has been overridden to a custom density so that the resources + // and views of the decoration aren't affected and match the rest of the System UI, if not + // then just use the task's configuration. A copy is made instead of using the original + // reference so that the configuration isn't mutated on config changes and diff checks can + // be made in WindowDecoration#relayout using the pre/post-relayout configuration. + // See b/301119301. + // TODO(b/301119301): consider moving the config data needed for diffs to relayout params + // instead of using a whole Configuration as a parameter. + final Configuration windowDecorConfig = new Configuration(); + windowDecorConfig.setTo(DesktopTasksController.isDesktopDensityOverrideSet() + ? context.getResources().getConfiguration() // Use system context. + : taskInfo.configuration); // Use task configuration. + relayoutParams.mWindowDecorConfig = windowDecorConfig; + + if (DesktopModeStatus.useRoundedCorners()) { + relayoutParams.mCornerRadius = + (int) ScreenDecorationsUtils.getWindowCornerRadius(context); + } + } + + private PointF calculateMaximizeMenuPosition() { final PointF position = new PointF(); final Resources resources = mContext.getResources(); @@ -684,7 +697,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin super.close(); } - private int getDesktopModeWindowDecorLayoutId(@WindowingMode int windowingMode) { + private static int getDesktopModeWindowDecorLayoutId(@WindowingMode int windowingMode) { return windowingMode == WINDOWING_MODE_FREEFORM ? R.layout.desktop_mode_app_controls_window_decor : R.layout.desktop_mode_focused_window_decor; @@ -730,6 +743,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin @Override int getCaptionHeightId(@WindowingMode int windowingMode) { + return getCaptionHeightIdStatic(windowingMode); + } + + private static int getCaptionHeightIdStatic(@WindowingMode int windowingMode) { return windowingMode == WINDOWING_MODE_FULLSCREEN ? R.dimen.desktop_mode_fullscreen_decor_caption_height : R.dimen.desktop_mode_freeform_decor_caption_height; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java index 18fcdd00df9d..77667ca579f2 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java @@ -16,16 +16,24 @@ package com.android.wm.shell.windowdecor; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.content.ComponentName; import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; import android.os.Handler; +import android.os.SystemProperties; import android.testing.AndroidTestingRunner; +import android.testing.TestableContext; import android.view.Choreographer; import android.view.Display; import android.view.SurfaceControl; @@ -34,14 +42,17 @@ import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; +import com.android.internal.R; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.TestRunningTaskInfoBuilder; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.SyncTransactionQueue; +import com.android.wm.shell.windowdecor.WindowDecoration.RelayoutParams; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -57,6 +68,13 @@ import java.util.function.Supplier; @SmallTest @RunWith(AndroidTestingRunner.class) public class DesktopModeWindowDecorationTests extends ShellTestCase { + private static final String USE_WINDOW_SHADOWS_SYSPROP_KEY = + "persist.wm.debug.desktop_use_window_shadows"; + private static final String FOCUSED_USE_WINDOW_SHADOWS_SYSPROP_KEY = + "persist.wm.debug.desktop_use_window_shadows_focused_window"; + private static final String USE_ROUNDED_CORNERS_SYSPROP_KEY = + "persist.wm.debug.desktop_use_rounded_corners"; + @Mock private DisplayController mMockDisplayController; @Mock @@ -79,14 +97,29 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { private SurfaceControlViewHost mMockSurfaceControlViewHost; @Mock private WindowDecoration.SurfaceControlViewHostFactory mMockSurfaceControlViewHostFactory; + @Mock + private TypedArray mMockRoundedCornersRadiusArray; private final Configuration mConfiguration = new Configuration(); + private TestableContext mTestableContext; + + /** Set up run before test class. */ + @BeforeClass + public static void setUpClass() { + // Reset the sysprop settings before running the test. + SystemProperties.set(USE_WINDOW_SHADOWS_SYSPROP_KEY, ""); + SystemProperties.set(FOCUSED_USE_WINDOW_SHADOWS_SYSPROP_KEY, ""); + SystemProperties.set(USE_ROUNDED_CORNERS_SYSPROP_KEY, ""); + } + @Before public void setUp() { doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory).create( any(), any(), any()); doReturn(mMockTransaction).when(mMockTransactionSupplier).get(); + mTestableContext = new TestableContext(mContext); + mTestableContext.ensureTestableResources(); } @Test @@ -105,6 +138,50 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { } + @Test + public void updateRelayoutParams_noSysPropFlagsSet_windowShadowsAreEnabled() { + final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); + RelayoutParams relayoutParams = new RelayoutParams(); + + DesktopModeWindowDecoration.updateRelayoutParams( + relayoutParams, mContext, taskInfo, /* applyStartTransactionOnDraw= */ true); + + assertThat(relayoutParams.mShadowRadiusId).isNotEqualTo(Resources.ID_NULL); + } + + @Test + public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersAreEnabled() { + final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); + fillRoundedCornersResources(/* fillValue= */ 30); + RelayoutParams relayoutParams = new RelayoutParams(); + + DesktopModeWindowDecoration.updateRelayoutParams( + relayoutParams, + mTestableContext, + taskInfo, + /* applyStartTransactionOnDraw= */ true); + + assertThat(relayoutParams.mCornerRadius).isGreaterThan(0); + } + + private void fillRoundedCornersResources(int fillValue) { + when(mMockRoundedCornersRadiusArray.getDimensionPixelSize(anyInt(), anyInt())) + .thenReturn(fillValue); + mTestableContext.getOrCreateTestableResources().addOverride( + R.array.config_roundedCornerRadiusArray, mMockRoundedCornersRadiusArray); + mTestableContext.getOrCreateTestableResources().addOverride( + R.dimen.rounded_corner_radius, fillValue); + mTestableContext.getOrCreateTestableResources().addOverride( + R.array.config_roundedCornerTopRadiusArray, mMockRoundedCornersRadiusArray); + mTestableContext.getOrCreateTestableResources().addOverride( + R.dimen.rounded_corner_radius_top, fillValue); + mTestableContext.getOrCreateTestableResources().addOverride( + R.array.config_roundedCornerBottomRadiusArray, mMockRoundedCornersRadiusArray); + mTestableContext.getOrCreateTestableResources().addOverride( + R.dimen.rounded_corner_radius_bottom, fillValue); + } + + private DesktopModeWindowDecoration createWindowDecoration( ActivityManager.RunningTaskInfo taskInfo) { return new DesktopModeWindowDecoration(mContext, mMockDisplayController, |