diff options
| author | 2024-03-05 09:26:34 +0000 | |
|---|---|---|
| committer | 2024-03-14 01:16:57 +0000 | |
| commit | 240c02d41629d01d3705836c5eff036314e27c0c (patch) | |
| tree | 51bc1a49dde0ac5ccbcf4fd7d123645d51ea3d5a | |
| parent | 77964d188ef9f64cec5d0c08a5d917e207b46442 (diff) | |
[1/n] Use fullscreen for modals dialog in desktop mode
When a transparent activity is launched as the only activity of a task
we disable desktop mode and hide the header.
Bug: 319492844
Test: atest WmTests:TaskTests
Test: atest WMShellUnitTests:DesktopTasksControllerTest
Test: atest WMShellUnitTests:DesktopModeWindowDecorViewModelTests
Test: atest WMShellUnitTests:AppCompatUtilsTest
Change-Id: I2ecf7c9d84ffc39fe6f5b28abc5ad7d50b3314a8
8 files changed, 266 insertions, 35 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/AppCompatUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/AppCompatUtils.kt new file mode 100644 index 000000000000..6781d08c9904 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/AppCompatUtils.kt @@ -0,0 +1,24 @@ +/* + * 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. + */ + +@file:JvmName("AppCompatUtils") + +package com.android.wm.shell.compatui + +import android.app.TaskInfo +fun isSingleTopActivityTranslucent(task: TaskInfo) = + task.isTopActivityTransparent && task.numActivities == 1 + 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 95237c38f309..b7c924c5b1ec 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 @@ -19,6 +19,7 @@ package com.android.wm.shell.desktopmode import android.app.ActivityManager.RunningTaskInfo import android.app.ActivityOptions import android.app.PendingIntent +import android.app.TaskInfo import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM @@ -46,6 +47,7 @@ import android.window.TransitionRequestInfo import android.window.WindowContainerTransaction import androidx.annotation.BinderThread import com.android.internal.policy.ScreenDecorationsUtils +import com.android.window.flags.Flags import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.common.DisplayController @@ -63,6 +65,7 @@ import com.android.wm.shell.common.annotations.ExternalThread import com.android.wm.shell.common.annotations.ShellMainThread import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT +import com.android.wm.shell.compatui.isSingleTopActivityTranslucent import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksListener import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.DragToDesktopStateListener import com.android.wm.shell.draganddrop.DragAndDropController @@ -80,6 +83,8 @@ import com.android.wm.shell.transition.Transitions import com.android.wm.shell.util.KtProtoLog import com.android.wm.shell.windowdecor.MoveToDesktopAnimator import com.android.wm.shell.windowdecor.OnTaskResizeAnimationListener +import com.android.wm.shell.windowdecor.extension.isFreeform +import com.android.wm.shell.windowdecor.extension.isFullscreen import java.io.PrintWriter import java.util.concurrent.Executor import java.util.function.Consumer @@ -162,8 +167,11 @@ class DesktopTasksController( private fun onInit() { KtProtoLog.d(WM_SHELL_DESKTOP_MODE, "Initialize DesktopTasksController") shellCommandHandler.addDumpCallback(this::dump, this) - shellCommandHandler.addCommandCallback("desktopmode", desktopModeShellCommandHandler, - this) + shellCommandHandler.addCommandCallback( + "desktopmode", + desktopModeShellCommandHandler, + this + ) shellController.addExternalInterface( ShellSharedConstants.KEY_EXTRA_SHELL_DESKTOP_MODE, { createExternalInterface() }, @@ -267,9 +275,11 @@ class DesktopTasksController( // Split-screen case where there are two focused tasks, then we find the child // task to move to desktop. val splitFocusedTask = - if (allFocusedTasks[0].taskId == allFocusedTasks[1].parentTaskId) + if (allFocusedTasks[0].taskId == allFocusedTasks[1].parentTaskId) { allFocusedTasks[1] - else allFocusedTasks[0] + } else { + allFocusedTasks[0] + } moveToDesktop(splitFocusedTask) } 1 -> { @@ -308,8 +318,18 @@ class DesktopTasksController( ) { if (!DesktopModeStatus.canEnterDesktopMode(context)) { KtProtoLog.w( - WM_SHELL_DESKTOP_MODE, "DesktopTasksController: Cannot enter desktop, " + - "display does not meet minimum size requirements") + WM_SHELL_DESKTOP_MODE, + "DesktopTasksController: Cannot enter desktop, " + + "display does not meet minimum size requirements" + ) + return + } + if (Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(task)) { + KtProtoLog.w( + WM_SHELL_DESKTOP_MODE, + "DesktopTasksController: Cannot enter desktop, " + + "translucent top activity found. This is likely a modal dialog." + ) return } KtProtoLog.v( @@ -444,7 +464,11 @@ class DesktopTasksController( if (Transitions.ENABLE_SHELL_TRANSITIONS) { exitDesktopTaskTransitionHandler.startTransition( - Transitions.TRANSIT_EXIT_DESKTOP_MODE, wct, position, mOnAnimationFinishedCallback) + Transitions.TRANSIT_EXIT_DESKTOP_MODE, + wct, + position, + mOnAnimationFinishedCallback + ) } else { shellTaskOrganizer.applyTransaction(wct) releaseVisualIndicator() @@ -490,8 +514,12 @@ class DesktopTasksController( KtProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveToNextDisplay: taskId=%d not found", taskId) return } - KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToNextDisplay: taskId=%d taskDisplayId=%d", - taskId, task.displayId) + KtProtoLog.v( + WM_SHELL_DESKTOP_MODE, + "moveToNextDisplay: taskId=%d taskDisplayId=%d", + taskId, + task.displayId + ) val displayIds = rootTaskDisplayAreaOrganizer.displayIds.sorted() // Get the first display id that is higher than current task display id @@ -513,8 +541,12 @@ class DesktopTasksController( * No-op if task is already on that display per [RunningTaskInfo.displayId]. */ private fun moveToDisplay(task: RunningTaskInfo, displayId: Int) { - KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToDisplay: taskId=%d displayId=%d", - task.taskId, displayId) + KtProtoLog.v( + WM_SHELL_DESKTOP_MODE, + "moveToDisplay: taskId=%d displayId=%d", + task.taskId, + displayId + ) if (task.displayId == displayId) { KtProtoLog.d(WM_SHELL_DESKTOP_MODE, "moveToDisplay: task already on display") @@ -588,7 +620,8 @@ class DesktopTasksController( // Center the task in screen bounds outBounds.offset( screenBounds.centerX() - outBounds.centerX(), - screenBounds.centerY() - outBounds.centerY()) + screenBounds.centerY() - outBounds.centerY() + ) } private fun getSnapBounds(taskInfo: RunningTaskInfo, position: SnapPosition): Rect { @@ -735,11 +768,13 @@ class DesktopTasksController( val result = triggerTask?.let { task -> when { // If display has tasks stashed, handle as stashed launch - desktopModeTaskRepository.isStashed(task.displayId) -> handleStashedTaskLaunch(task) + task.isStashed -> handleStashedTaskLaunch(task) + // Check if the task has a top transparent activity + shouldLaunchAsModal(task) -> handleTransparentTaskLaunch(task) // Check if fullscreen task should be updated - task.windowingMode == WINDOWING_MODE_FULLSCREEN -> handleFullscreenTaskLaunch(task) + task.isFullscreen -> handleFullscreenTaskLaunch(task) // Check if freeform task should be updated - task.windowingMode == WINDOWING_MODE_FREEFORM -> handleFreeformTaskLaunch(task) + task.isFreeform -> handleFreeformTaskLaunch(task) else -> { null } @@ -772,6 +807,13 @@ class DesktopTasksController( .forEach { finishTransaction.setCornerRadius(it.leash, cornerRadius) } } + private val TaskInfo.isStashed: Boolean + get() = desktopModeTaskRepository.isStashed(displayId) + + private fun shouldLaunchAsModal(task: TaskInfo): Boolean { + return Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(task) + } + private fun handleFreeformTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? { KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: handleFreeformTaskLaunch") val activeTasks = desktopModeTaskRepository.getActiveTasks(task.displayId) @@ -819,6 +861,16 @@ class DesktopTasksController( return wct } + // Always launch transparent tasks in fullscreen. + private fun handleTransparentTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? { + // Already fullscreen, no-op. + if (task.isFullscreen) + return null + return WindowContainerTransaction().also { wct -> + addMoveToFullscreenChanges(wct, task) + } + } + private fun addMoveToDesktopChanges( wct: WindowContainerTransaction, taskInfo: RunningTaskInfo @@ -899,9 +951,12 @@ class DesktopTasksController( ) { val wct = WindowContainerTransaction() addMoveToSplitChanges(wct, taskInfo) - splitScreenController.requestEnterSplitSelect(taskInfo, wct, + splitScreenController.requestEnterSplitSelect( + taskInfo, + wct, if (leftOrTop) SPLIT_POSITION_TOP_OR_LEFT else SPLIT_POSITION_BOTTOM_OR_RIGHT, - taskInfo.configuration.windowConfiguration.bounds) + taskInfo.configuration.windowConfiguration.bounds + ) } } @@ -1096,7 +1151,8 @@ class DesktopTasksController( pendingIntentLaunchFlags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK setPendingIntentBackgroundActivityStartMode( - ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED) + ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED + ) isPendingIntentBackgroundActivityLaunchAllowedByPermission = true } val wct = WindowContainerTransaction() diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index 9c0144292c12..b4c8bd0f1585 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -30,6 +30,7 @@ import static android.view.WindowInsets.Type.statusBars; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; +import static com.android.wm.shell.compatui.AppCompatUtils.isSingleTopActivityTranslucent; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR; import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR; @@ -75,6 +76,7 @@ import android.window.WindowContainerTransaction; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; +import com.android.window.flags.Flags; import com.android.wm.shell.R; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; @@ -1048,6 +1050,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { && taskInfo.isFocused) { return false; } + if (Flags.enableDesktopWindowingModalsPolicy() + && isSingleTopActivityTranslucent(taskInfo)) { + return false; + } return DesktopModeStatus.isEnabled() && taskInfo.getWindowingMode() != WINDOWING_MODE_PINNED && taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/extension/TaskInfo.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/extension/TaskInfo.kt index 7a64a47a46cc..a2293d53618a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/extension/TaskInfo.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/extension/TaskInfo.kt @@ -17,6 +17,8 @@ package com.android.wm.shell.windowdecor.extension import android.app.TaskInfo +import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM +import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.view.WindowInsetsController.APPEARANCE_LIGHT_CAPTION_BARS import android.view.WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND @@ -31,3 +33,9 @@ val TaskInfo.isLightCaptionBarAppearance: Boolean val appearance = taskDescription?.systemBarsAppearance ?: 0 return (appearance and APPEARANCE_LIGHT_CAPTION_BARS) != 0 } + +val TaskInfo.isFullscreen: Boolean + get() = windowingMode == WINDOWING_MODE_FULLSCREEN + +val TaskInfo.isFreeform: Boolean + get() = windowingMode == WINDOWING_MODE_FREEFORM diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt new file mode 100644 index 000000000000..4cd2a366f5eb --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt @@ -0,0 +1,59 @@ +/* + * 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.wm.shell.compatui + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Tests for {@link AppCompatUtils}. + * + * Build/Install/Run: + * atest WMShellUnitTests:AppCompatUtilsTest + */ +@RunWith(AndroidTestingRunner::class) +@SmallTest +class AppCompatUtilsTest : ShellTestCase() { + + @Test + fun testIsSingleTopActivityTranslucent() { + assertTrue(isSingleTopActivityTranslucent( + createFreeformTask(/* displayId */ 0) + .apply { + isTopActivityTransparent = true + numActivities = 1 + })) + assertFalse(isSingleTopActivityTranslucent( + createFreeformTask(/* displayId */ 0) + .apply { + isTopActivityTransparent = true + numActivities = 0 + })) + assertFalse(isSingleTopActivityTranslucent( + createFreeformTask(/* displayId */ 0) + .apply { + isTopActivityTransparent = false + numActivities = 1 + })) + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index 0136751d8c9a..d2cb80a7c180 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -24,6 +24,7 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.os.Binder +import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.view.Display.DEFAULT_DISPLAY import android.view.WindowManager @@ -40,11 +41,11 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession import com.android.dx.mockito.inline.extended.ExtendedMockito.never import com.android.dx.mockito.inline.extended.StaticMockitoSession +import com.android.window.flags.Flags import com.android.wm.shell.MockToken import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.ShellTestCase -import com.android.wm.shell.transition.TestRemoteTransition import com.android.wm.shell.TestRunningTaskInfoBuilder import com.android.wm.shell.TestShellExecutor import com.android.wm.shell.common.DisplayController @@ -65,16 +66,17 @@ import com.android.wm.shell.sysui.ShellCommandHandler import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.OneShotRemoteHandler +import com.android.wm.shell.transition.TestRemoteTransition import com.android.wm.shell.transition.Transitions import com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS import com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_DESKTOP_MODE import com.android.wm.shell.transition.Transitions.TransitionHandler -import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertWithMessage import org.junit.After import org.junit.Assume.assumeTrue import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor @@ -90,10 +92,19 @@ import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever import org.mockito.quality.Strictness +/** + * Test class for {@link DesktopTasksController} + * + * Usage: atest WMShellUnitTests:DesktopTasksControllerTest + */ @SmallTest @RunWith(AndroidTestingRunner::class) class DesktopTasksControllerTest : ShellTestCase() { + @JvmField + @Rule + val setFlagsRule = SetFlagsRule() + @Mock lateinit var testExecutor: ShellExecutor @Mock lateinit var shellCommandHandler: ShellCommandHandler @Mock lateinit var shellController: ShellController @@ -108,7 +119,6 @@ class DesktopTasksControllerTest : ShellTestCase() { ToggleResizeDesktopTaskTransitionHandler @Mock lateinit var dragToDesktopTransitionHandler: DragToDesktopTransitionHandler @Mock lateinit var launchAdjacentController: LaunchAdjacentController - @Mock lateinit var desktopModeWindowDecoration: DesktopModeWindowDecoration @Mock lateinit var splitScreenController: SplitScreenController @Mock lateinit var recentsTransitionHandler: RecentsTransitionHandler @Mock lateinit var dragAndDropController: DragAndDropController @@ -121,6 +131,7 @@ class DesktopTasksControllerTest : ShellTestCase() { private lateinit var recentsTransitionStateListener: RecentsTransitionStateListener private val shellExecutor = TestShellExecutor() + // Mock running tasks are registered here so we can get the list from mock shell task organizer private val runningTasks = mutableListOf<RunningTaskInfo>() @@ -347,6 +358,18 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test + fun moveToDesktop_topActivityTranslucent_doesNothing() { + setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) + val task = setUpFullscreenTask().apply { + isTopActivityTransparent = true + numActivities = 1 + } + + controller.moveToDesktop(task) + verifyWCTNotExecuted() + } + + @Test fun moveToDesktop_deviceNotSupported_deviceRestrictionsOverridden_taskIsMovedToDesktop() { val task = setUpFullscreenTask() @@ -421,7 +444,9 @@ class DesktopTasksControllerTest : ShellTestCase() { val wct = getLatestMoveToDesktopWct() assertThat(wct.changes[task.token.asBinder()]?.windowingMode) .isEqualTo(WINDOWING_MODE_FREEFORM) - verify(splitScreenController).prepareExitSplitScreen(any(), anyInt(), + verify(splitScreenController).prepareExitSplitScreen( + any(), + anyInt(), eq(SplitScreenController.EXIT_REASON_DESKTOP_MODE) ) } @@ -433,7 +458,9 @@ class DesktopTasksControllerTest : ShellTestCase() { val wct = getLatestMoveToDesktopWct() assertThat(wct.changes[task.token.asBinder()]?.windowingMode) .isEqualTo(WINDOWING_MODE_FREEFORM) - verify(splitScreenController, never()).prepareExitSplitScreen(any(), anyInt(), + verify(splitScreenController, never()).prepareExitSplitScreen( + any(), + anyInt(), eq(SplitScreenController.EXIT_REASON_DESKTOP_MODE) ) } @@ -741,6 +768,19 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test + fun handleRequest_shouldLaunchAsModal_returnSwitchToFullscreenWCT() { + setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) + val task = setUpFreeformTask().apply { + isTopActivityTransparent = true + numActivities = 1 + } + + val result = controller.handleRequest(Binder(), createTransition(task)) + assertThat(result?.changes?.get(task.token.asBinder())?.windowingMode) + .isEqualTo(WINDOWING_MODE_FULLSCREEN) + } + + @Test fun stashDesktopApps_stateUpdates() { whenever(DesktopModeStatus.isStashingEnabled()).thenReturn(true) @@ -819,7 +859,9 @@ class DesktopTasksControllerTest : ShellTestCase() { val wct = getLatestMoveToDesktopWct() assertThat(wct.changes[task4.token.asBinder()]?.windowingMode) .isEqualTo(WINDOWING_MODE_FREEFORM) - verify(splitScreenController).prepareExitSplitScreen(any(), anyInt(), + verify(splitScreenController).prepareExitSplitScreen( + any(), + anyInt(), eq(SplitScreenController.EXIT_REASON_DESKTOP_MODE) ) } @@ -852,9 +894,12 @@ class DesktopTasksControllerTest : ShellTestCase() { controller.enterSplit(DEFAULT_DISPLAY, false) - verify(splitScreenController).requestEnterSplitSelect(task2, any(), + verify(splitScreenController).requestEnterSplitSelect( + task2, + any(), SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT, - task2.configuration.windowConfiguration.bounds) + task2.configuration.windowConfiguration.bounds + ) } private fun setUpFreeformTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt index 6940739d68b2..8e9619dc1430 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt @@ -44,8 +44,8 @@ import android.view.SurfaceView import android.view.WindowInsets.Type.navigationBars import android.view.WindowInsets.Type.statusBars import androidx.test.filters.SmallTest -import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn +import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession import com.android.dx.mockito.inline.extended.StaticMockitoSession import com.android.window.flags.Flags import com.android.wm.shell.RootTaskDisplayAreaOrganizer @@ -65,11 +65,14 @@ import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.Transitions import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeOnInsetsChangedListener +import java.util.Optional +import java.util.function.Supplier import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito import org.mockito.Mockito.anyInt import org.mockito.Mockito.mock import org.mockito.Mockito.never @@ -78,15 +81,14 @@ import org.mockito.Mockito.verify import org.mockito.kotlin.any import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.eq +import org.mockito.kotlin.spy import org.mockito.kotlin.whenever import org.mockito.quality.Strictness -import java.util.Optional -import java.util.function.Supplier -import org.mockito.Mockito -import org.mockito.kotlin.spy - -/** Tests of [DesktopModeWindowDecorViewModel] */ +/** + * Tests of [DesktopModeWindowDecorViewModel] + * Usage: atest WMShellUnitTests:DesktopModeWindowDecorViewModelTests + */ @SmallTest @RunWith(AndroidTestingRunner::class) @RunWithLooper @@ -291,6 +293,19 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { } @Test + fun testDescorationIsNotCreatedForTopTranslucentActivities() { + setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) + val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true).apply { + isTopActivityTransparent = true + numActivities = 1 + } + onTaskOpening(task) + + verify(mockDesktopModeWindowDecorFactory, never()) + .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any()) + } + + @Test fun testRelayoutRunsWhenStatusBarsInsetsSourceVisibilityChanges() { val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM, focused = true) val decoration = setUpMockDecorationForTask(task) @@ -470,7 +485,8 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { private fun setUpMockDecorationForTask(task: RunningTaskInfo): DesktopModeWindowDecoration { val decoration = mock(DesktopModeWindowDecoration::class.java) - whenever(mockDesktopModeWindowDecorFactory.create( + whenever( + mockDesktopModeWindowDecorFactory.create( any(), any(), any(), eq(task), any(), any(), any(), any(), any()) ).thenReturn(decoration) decoration.mTaskInfo = task @@ -489,7 +505,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { "testEventReceiversOnMultipleDisplays", /*width=*/ 400, /*height=*/ 400, - /*densityDpi=*/320, + /*densityDpi=*/ 320, surfaceView.holder.surface, DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY ) diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java index 961fdfb14bf3..5ad66e38dfd2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -606,6 +606,23 @@ public class TaskTests extends WindowTestsBase { doReturn(true).when(root).fillsParent(); } + @Test + public void testIsTopActivityTranslucent() { + DisplayContent display = mAtm.mRootWindowContainer.getDefaultDisplay(); + final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true) + .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build(); + final Task task = rootTask.getBottomMostTask(); + final ActivityRecord root = task.getTopNonFinishingActivity(); + spyOn(mWm.mLetterboxConfiguration); + spyOn(root); + + doReturn(false).when(root).fillsParent(); + assertTrue(task.getTaskInfo().isTopActivityTransparent); + + doReturn(true).when(root).fillsParent(); + assertFalse(task.getTaskInfo().isTopActivityTransparent); + } + /** * Tests that a task with forced orientation has orientation-consistent bounds within the * parent. |