Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +24 −3 Original line number Diff line number Diff line Loading @@ -155,6 +155,8 @@ class DesktopTasksController( visualIndicator = null } } private val sysUIPackageName = context.resources.getString( com.android.internal.R.string.config_systemUi) private val transitionAreaHeight get() = Loading Loading @@ -214,6 +216,11 @@ class DesktopTasksController( return visualIndicator } // TODO(b/347289970): Consider replacing with API private fun isSystemUIApplication(taskInfo: RunningTaskInfo): Boolean { return taskInfo.baseActivity?.packageName == sysUIPackageName } fun setOnTaskResizeAnimationListener(listener: OnTaskResizeAnimationListener) { toggleResizeDesktopTaskTransitionHandler.setOnTaskResizeAnimationListener(listener) enterDesktopTaskTransitionHandler.setOnTaskResizeAnimationListener(listener) Loading Loading @@ -349,6 +356,14 @@ class DesktopTasksController( ) return } if (isSystemUIApplication(task)) { KtProtoLog.w( WM_SHELL_DESKTOP_MODE, "DesktopTasksController: Cannot enter desktop, " + "systemUI top activity found." ) return } KtProtoLog.v( WM_SHELL_DESKTOP_MODE, "DesktopTasksController: moveToDesktop taskId=%d", Loading Loading @@ -896,7 +911,9 @@ class DesktopTasksController( when { request.type == TRANSIT_TO_BACK -> handleBackNavigation(task) // Check if the task has a top transparent activity shouldLaunchAsModal(task) -> handleTransparentTaskLaunch(task) shouldLaunchAsModal(task) -> handleIncompatibleTaskLaunch(task) // Check if the task has a top systemUI activity isSystemUIApplication(task) -> handleIncompatibleTaskLaunch(task) // Check if fullscreen task should be updated task.isFullscreen -> handleFullscreenTaskLaunch(task, transition) // Check if freeform task should be updated Loading Loading @@ -930,6 +947,7 @@ class DesktopTasksController( .forEach { finishTransaction.setCornerRadius(it.leash, cornerRadius) } } // TODO(b/347289970): Consider replacing with API private fun shouldLaunchAsModal(task: TaskInfo) = Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(task) Loading Loading @@ -996,8 +1014,11 @@ class DesktopTasksController( return null } // Always launch transparent tasks in fullscreen. private fun handleTransparentTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? { /** * If a task is not compatible with desktop mode freeform, it should always be launched in * fullscreen. */ private fun handleIncompatibleTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? { // Already fullscreen, no-op. if (task.isFullscreen) return null return WindowContainerTransaction().also { wct -> addMoveToFullscreenChanges(wct, task) } Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +16 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,7 @@ import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.ExclusionReg import com.android.wm.shell.windowdecor.extension.TaskInfoKt; import java.io.PrintWriter; import java.util.Objects; import java.util.Optional; import java.util.function.Supplier; Loading Loading @@ -152,6 +153,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private final DisplayInsetsController mDisplayInsetsController; private final Region mExclusionRegion = Region.obtain(); private boolean mInImmersiveMode; private final String mSysUIPackageName; private final ISystemGestureExclusionListener mGestureExclusionListener = new ISystemGestureExclusionListener.Stub() { Loading Loading @@ -247,6 +249,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer; mInputManager = mContext.getSystemService(InputManager.class); mWindowDecorByTaskId = windowDecorByTaskId; mSysUIPackageName = mContext.getResources().getString( com.android.internal.R.string.config_systemUi); shellInit.addInitCallback(this::onInit, this); } Loading Loading @@ -1035,10 +1039,14 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { && taskInfo.isFocused) { return false; } // TODO(b/347289970): Consider replacing with API if (Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(taskInfo)) { return false; } if (isSystemUIApplication(taskInfo)) { return false; } return DesktopModeStatus.canEnterDesktopMode(mContext) && !DesktopWallpaperActivity.isWallpaperTask(taskInfo) && taskInfo.getWindowingMode() != WINDOWING_MODE_PINNED Loading Loading @@ -1109,6 +1117,14 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { && mSplitScreenController.isTaskInSplitScreen(taskId); } // TODO(b/347289970): Consider replacing with API private boolean isSystemUIApplication(RunningTaskInfo taskInfo) { if (taskInfo.baseActivity != null) { return (Objects.equals(taskInfo.baseActivity.getPackageName(), mSysUIPackageName)); } return false; } private void dump(PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; pw.println(prefix + "DesktopModeWindowDecorViewModel"); Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +32 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.content.ComponentName import android.content.Intent import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo.CONFIG_DENSITY Loading Loading @@ -667,6 +668,20 @@ class DesktopTasksControllerTest : ShellTestCase() { verifyEnterDesktopWCTNotExecuted() } @Test fun moveToDesktop_systemUIActivity_doesNothing() { val task = setUpFullscreenTask() // Set task as systemUI package val systemUIPackageName = context.resources.getString( com.android.internal.R.string.config_systemUi) val baseComponent = ComponentName(systemUIPackageName, /* class */ "") task.baseActivity = baseComponent controller.moveToDesktop(task, transitionSource = UNKNOWN) verifyEnterDesktopWCTNotExecuted() } @Test fun moveToDesktop_deviceSupported_taskIsMovedToDesktop() { val task = setUpFullscreenTask() Loading Loading @@ -1169,6 +1184,21 @@ class DesktopTasksControllerTest : ShellTestCase() { .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN } @Test fun handleRequest_systemUIActivity_returnSwitchToFullscreenWCT() { val task = setUpFreeformTask() // Set task as systemUI package val systemUIPackageName = context.resources.getString( com.android.internal.R.string.config_systemUi) val baseComponent = ComponentName(systemUIPackageName, /* class */ "") task.baseActivity = baseComponent val result = controller.handleRequest(Binder(), createTransition(task)) assertThat(result?.changes?.get(task.token.asBinder())?.windowingMode) .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN } @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun handleRequest_backTransition_singleActiveTask_noToken() { Loading Loading @@ -1581,6 +1611,8 @@ class DesktopTasksControllerTest : ShellTestCase() { bounds: Rect? = null ): RunningTaskInfo { val task = createFreeformTask(displayId, bounds) val activityInfo = ActivityInfo() task.topActivityInfo = activityInfo whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task) desktopModeTaskRepository.addActiveTask(displayId, task.taskId) desktopModeTaskRepository.addOrMoveFreeformTaskToTop(displayId, task.taskId) Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +22 −2 Original line number Diff line number Diff line Loading @@ -22,7 +22,9 @@ import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.content.ComponentName import android.content.Context import android.content.pm.ActivityInfo import android.graphics.Rect import android.hardware.display.DisplayManager import android.hardware.display.VirtualDisplay Loading Loading @@ -341,7 +343,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { } @Test fun testDescorationIsNotCreatedForTopTranslucentActivities() { fun testDecorationIsNotCreatedForTopTranslucentActivities() { setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true).apply { isTopActivityTransparent = true Loading @@ -353,6 +355,22 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any()) } @Test fun testDecorationIsNotCreatedForSystemUIActivities() { val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true) // Set task as systemUI package val systemUIPackageName = context.resources.getString( com.android.internal.R.string.config_systemUi) val baseComponent = ComponentName(systemUIPackageName, /* class */ "") task.baseActivity = baseComponent onTaskOpening(task) verify(mockDesktopModeWindowDecorFactory, never()) .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any()) } @Test @RequiresFlagsEnabled(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_IMMERSIVE_HANDLE_HIDING) fun testRelayoutRunsWhenStatusBarsInsetsSourceVisibilityChanges() { Loading Loading @@ -522,7 +540,8 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { displayId: Int = DEFAULT_DISPLAY, @WindowConfiguration.WindowingMode windowingMode: Int, activityType: Int = ACTIVITY_TYPE_STANDARD, focused: Boolean = true focused: Boolean = true, activityInfo: ActivityInfo = ActivityInfo() ): RunningTaskInfo { return TestRunningTaskInfoBuilder() .setDisplayId(displayId) Loading @@ -530,6 +549,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { .setVisible(true) .setActivityType(activityType) .build().apply { topActivityInfo = activityInfo isFocused = focused } } Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +24 −3 Original line number Diff line number Diff line Loading @@ -155,6 +155,8 @@ class DesktopTasksController( visualIndicator = null } } private val sysUIPackageName = context.resources.getString( com.android.internal.R.string.config_systemUi) private val transitionAreaHeight get() = Loading Loading @@ -214,6 +216,11 @@ class DesktopTasksController( return visualIndicator } // TODO(b/347289970): Consider replacing with API private fun isSystemUIApplication(taskInfo: RunningTaskInfo): Boolean { return taskInfo.baseActivity?.packageName == sysUIPackageName } fun setOnTaskResizeAnimationListener(listener: OnTaskResizeAnimationListener) { toggleResizeDesktopTaskTransitionHandler.setOnTaskResizeAnimationListener(listener) enterDesktopTaskTransitionHandler.setOnTaskResizeAnimationListener(listener) Loading Loading @@ -349,6 +356,14 @@ class DesktopTasksController( ) return } if (isSystemUIApplication(task)) { KtProtoLog.w( WM_SHELL_DESKTOP_MODE, "DesktopTasksController: Cannot enter desktop, " + "systemUI top activity found." ) return } KtProtoLog.v( WM_SHELL_DESKTOP_MODE, "DesktopTasksController: moveToDesktop taskId=%d", Loading Loading @@ -896,7 +911,9 @@ class DesktopTasksController( when { request.type == TRANSIT_TO_BACK -> handleBackNavigation(task) // Check if the task has a top transparent activity shouldLaunchAsModal(task) -> handleTransparentTaskLaunch(task) shouldLaunchAsModal(task) -> handleIncompatibleTaskLaunch(task) // Check if the task has a top systemUI activity isSystemUIApplication(task) -> handleIncompatibleTaskLaunch(task) // Check if fullscreen task should be updated task.isFullscreen -> handleFullscreenTaskLaunch(task, transition) // Check if freeform task should be updated Loading Loading @@ -930,6 +947,7 @@ class DesktopTasksController( .forEach { finishTransaction.setCornerRadius(it.leash, cornerRadius) } } // TODO(b/347289970): Consider replacing with API private fun shouldLaunchAsModal(task: TaskInfo) = Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(task) Loading Loading @@ -996,8 +1014,11 @@ class DesktopTasksController( return null } // Always launch transparent tasks in fullscreen. private fun handleTransparentTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? { /** * If a task is not compatible with desktop mode freeform, it should always be launched in * fullscreen. */ private fun handleIncompatibleTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? { // Already fullscreen, no-op. if (task.isFullscreen) return null return WindowContainerTransaction().also { wct -> addMoveToFullscreenChanges(wct, task) } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +16 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,7 @@ import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.ExclusionReg import com.android.wm.shell.windowdecor.extension.TaskInfoKt; import java.io.PrintWriter; import java.util.Objects; import java.util.Optional; import java.util.function.Supplier; Loading Loading @@ -152,6 +153,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private final DisplayInsetsController mDisplayInsetsController; private final Region mExclusionRegion = Region.obtain(); private boolean mInImmersiveMode; private final String mSysUIPackageName; private final ISystemGestureExclusionListener mGestureExclusionListener = new ISystemGestureExclusionListener.Stub() { Loading Loading @@ -247,6 +249,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer; mInputManager = mContext.getSystemService(InputManager.class); mWindowDecorByTaskId = windowDecorByTaskId; mSysUIPackageName = mContext.getResources().getString( com.android.internal.R.string.config_systemUi); shellInit.addInitCallback(this::onInit, this); } Loading Loading @@ -1035,10 +1039,14 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { && taskInfo.isFocused) { return false; } // TODO(b/347289970): Consider replacing with API if (Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(taskInfo)) { return false; } if (isSystemUIApplication(taskInfo)) { return false; } return DesktopModeStatus.canEnterDesktopMode(mContext) && !DesktopWallpaperActivity.isWallpaperTask(taskInfo) && taskInfo.getWindowingMode() != WINDOWING_MODE_PINNED Loading Loading @@ -1109,6 +1117,14 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { && mSplitScreenController.isTaskInSplitScreen(taskId); } // TODO(b/347289970): Consider replacing with API private boolean isSystemUIApplication(RunningTaskInfo taskInfo) { if (taskInfo.baseActivity != null) { return (Objects.equals(taskInfo.baseActivity.getPackageName(), mSysUIPackageName)); } return false; } private void dump(PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; pw.println(prefix + "DesktopModeWindowDecorViewModel"); Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +32 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.content.ComponentName import android.content.Intent import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo.CONFIG_DENSITY Loading Loading @@ -667,6 +668,20 @@ class DesktopTasksControllerTest : ShellTestCase() { verifyEnterDesktopWCTNotExecuted() } @Test fun moveToDesktop_systemUIActivity_doesNothing() { val task = setUpFullscreenTask() // Set task as systemUI package val systemUIPackageName = context.resources.getString( com.android.internal.R.string.config_systemUi) val baseComponent = ComponentName(systemUIPackageName, /* class */ "") task.baseActivity = baseComponent controller.moveToDesktop(task, transitionSource = UNKNOWN) verifyEnterDesktopWCTNotExecuted() } @Test fun moveToDesktop_deviceSupported_taskIsMovedToDesktop() { val task = setUpFullscreenTask() Loading Loading @@ -1169,6 +1184,21 @@ class DesktopTasksControllerTest : ShellTestCase() { .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN } @Test fun handleRequest_systemUIActivity_returnSwitchToFullscreenWCT() { val task = setUpFreeformTask() // Set task as systemUI package val systemUIPackageName = context.resources.getString( com.android.internal.R.string.config_systemUi) val baseComponent = ComponentName(systemUIPackageName, /* class */ "") task.baseActivity = baseComponent val result = controller.handleRequest(Binder(), createTransition(task)) assertThat(result?.changes?.get(task.token.asBinder())?.windowingMode) .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN } @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun handleRequest_backTransition_singleActiveTask_noToken() { Loading Loading @@ -1581,6 +1611,8 @@ class DesktopTasksControllerTest : ShellTestCase() { bounds: Rect? = null ): RunningTaskInfo { val task = createFreeformTask(displayId, bounds) val activityInfo = ActivityInfo() task.topActivityInfo = activityInfo whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task) desktopModeTaskRepository.addActiveTask(displayId, task.taskId) desktopModeTaskRepository.addOrMoveFreeformTaskToTop(displayId, task.taskId) Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +22 −2 Original line number Diff line number Diff line Loading @@ -22,7 +22,9 @@ import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.content.ComponentName import android.content.Context import android.content.pm.ActivityInfo import android.graphics.Rect import android.hardware.display.DisplayManager import android.hardware.display.VirtualDisplay Loading Loading @@ -341,7 +343,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { } @Test fun testDescorationIsNotCreatedForTopTranslucentActivities() { fun testDecorationIsNotCreatedForTopTranslucentActivities() { setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY) val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true).apply { isTopActivityTransparent = true Loading @@ -353,6 +355,22 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any()) } @Test fun testDecorationIsNotCreatedForSystemUIActivities() { val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true) // Set task as systemUI package val systemUIPackageName = context.resources.getString( com.android.internal.R.string.config_systemUi) val baseComponent = ComponentName(systemUIPackageName, /* class */ "") task.baseActivity = baseComponent onTaskOpening(task) verify(mockDesktopModeWindowDecorFactory, never()) .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any()) } @Test @RequiresFlagsEnabled(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_IMMERSIVE_HANDLE_HIDING) fun testRelayoutRunsWhenStatusBarsInsetsSourceVisibilityChanges() { Loading Loading @@ -522,7 +540,8 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { displayId: Int = DEFAULT_DISPLAY, @WindowConfiguration.WindowingMode windowingMode: Int, activityType: Int = ACTIVITY_TYPE_STANDARD, focused: Boolean = true focused: Boolean = true, activityInfo: ActivityInfo = ActivityInfo() ): RunningTaskInfo { return TestRunningTaskInfoBuilder() .setDisplayId(displayId) Loading @@ -530,6 +549,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { .setVisible(true) .setActivityType(activityType) .build().apply { topActivityInfo = activityInfo isFocused = focused } } Loading