Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ae34ea14 authored by Gustav Sennton's avatar Gustav Sennton Committed by Android (Google) Code Review
Browse files

Merge "Desktop Windowing: add sysprop flags for shadows and rounded corners" into main

parents be1761a0 159f9de4
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
@@ -54,6 +54,26 @@ public class DesktopModeStatus {
    private static final boolean IS_STASHING_ENABLED = SystemProperties.getBoolean(
            "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
     */
@@ -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;
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -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 }
+50 −33
Original line number Diff line number Diff line
@@ -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;
+77 −0
Original line number Diff line number Diff line
@@ -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,