summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Massimo Carli <mcarli@google.com> 2024-03-05 09:26:34 +0000
committer Massimo Carli <mcarli@google.com> 2024-03-14 01:16:57 +0000
commit240c02d41629d01d3705836c5eff036314e27c0c (patch)
tree51bc1a49dde0ac5ccbcf4fd7d123645d51ea3d5a
parent77964d188ef9f64cec5d0c08a5d917e207b46442 (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
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/AppCompatUtils.kt24
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt92
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/extension/TaskInfo.kt8
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt59
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt61
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt34
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskTests.java17
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.