Loading core/java/android/app/TaskInfo.java +4 −2 Original line number Diff line number Diff line Loading @@ -655,8 +655,10 @@ public class TaskInfo { + " effectiveUid=" + effectiveUid + " displayId=" + displayId + " isRunning=" + isRunning + " baseIntent=" + baseIntent + " baseActivity=" + baseActivity + " topActivity=" + topActivity + " origActivity=" + origActivity + " baseIntent=" + baseIntent + " baseActivity=" + baseActivity + " topActivity=" + topActivity + " origActivity=" + origActivity + " realActivity=" + realActivity + " numActivities=" + numActivities + " lastActiveTime=" + lastActiveTime Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt +61 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,13 @@ import android.annotation.DimenRes import android.app.ActivityManager.RunningTaskInfo import android.app.TaskInfo import android.content.Context import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK import android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK import android.content.Intent.FLAG_ACTIVITY_NEW_TASK import android.content.pm.ActivityInfo.LAUNCH_MULTIPLE import android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE import android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK import android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED import android.content.pm.ActivityInfo.isFixedOrientationLandscape import android.content.pm.ActivityInfo.isFixedOrientationPortrait Loading @@ -30,7 +37,9 @@ import android.content.res.Configuration.ORIENTATION_PORTRAIT import android.graphics.Rect import android.os.SystemProperties import android.util.Size import android.window.DesktopModeFlags import com.android.wm.shell.R import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayLayout import kotlin.math.ceil Loading Loading @@ -263,6 +272,58 @@ fun getAppHeaderHeight(context: Context): Int = /** Returns the resource id of the app header height in desktop mode. */ @DimenRes fun getAppHeaderHeightId(): Int = R.dimen.desktop_mode_freeform_decor_caption_height /** * Returns the task bounds a launching task should inherit from an existing running instance. * Returns null if there are no bounds to inherit. */ fun getInheritedExistingTaskBounds( taskRepository: DesktopRepository, shellTaskOrganizer: ShellTaskOrganizer, task: RunningTaskInfo, deskId: Int, ): Rect? { if (!DesktopModeFlags.INHERIT_TASK_BOUNDS_FOR_TRAMPOLINE_TASK_LAUNCHES.isTrue) return null val activeTask = taskRepository.getExpandedTasksIdsInDeskOrdered(deskId).firstOrNull() if (activeTask == null) return null val lastTask = shellTaskOrganizer.getRunningTaskInfo(activeTask) val lastTaskTopActivity = lastTask?.topActivity val currentTaskTopActivity = task.topActivity val intentFlags = task.baseIntent.flags val launchMode = task.topActivityInfo?.launchMode ?: LAUNCH_MULTIPLE return when { // No running task activity to inherit bounds from. lastTaskTopActivity == null -> null // No current top activity to set bounds for. currentTaskTopActivity == null -> null // Top task is not an instance of the launching activity, do not inherit its bounds. lastTaskTopActivity.packageName != currentTaskTopActivity.packageName -> null // Top task is an instance of launching activity. Activity will be launching in a new // task with the existing task also being closed. Inherit existing task bounds to // prevent new task jumping. (isLaunchingNewTask(launchMode, intentFlags) && isClosingExitingInstance(intentFlags)) -> lastTask.configuration.windowConfiguration.bounds else -> null } } /** * Returns true if the launch mode or intent will result in a new task being created for the * activity. */ private fun isLaunchingNewTask(launchMode: Int, intentFlags: Int) = launchMode == LAUNCH_SINGLE_TASK || launchMode == LAUNCH_SINGLE_INSTANCE || launchMode == LAUNCH_SINGLE_INSTANCE_PER_TASK || (intentFlags and FLAG_ACTIVITY_NEW_TASK) != 0 /** * Returns true if the intent will result in an existing task instance being closed if a new one * appears. */ private fun isClosingExitingInstance(intentFlags: Int) = (intentFlags and FLAG_ACTIVITY_CLEAR_TASK) != 0 || (intentFlags and FLAG_ACTIVITY_MULTIPLE_TASK) == 0 /** * Calculates the desired initial bounds for applications in desktop windowing. This is done as a * scale of the screen bounds. Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +23 −5 Original line number Diff line number Diff line Loading @@ -32,6 +32,8 @@ import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.app.WindowConfiguration.WindowingMode import android.content.Context import android.content.Intent import android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK import android.content.Intent.FLAG_ACTIVITY_NEW_TASK import android.graphics.Point import android.graphics.PointF import android.graphics.Rect Loading Loading @@ -2284,10 +2286,18 @@ class DesktopTasksController( wct.reorder(task.token, true) return wct } val inheritedTaskBounds = getInheritedExistingTaskBounds(taskRepository, shellTaskOrganizer, task, deskId) if (!taskRepository.isActiveTask(task.taskId) && inheritedTaskBounds != null) { // Inherit bounds from closing task instance to prevent application jumping different // cascading positions. wct.setBounds(task.token, inheritedTaskBounds) } // TODO(b/365723620): Handle non running tasks that were launched after reboot. // If task is already visible, it must have been handled already and added to desktop mode. // Cascade task only if it's not visible yet. // Cascade task only if it's not visible yet and has no inherited bounds. if ( inheritedTaskBounds == null && DesktopModeFlags.ENABLE_CASCADING_WINDOWS.isTrue() && !taskRepository.isVisibleTask(task.taskId) ) { Loading Loading @@ -2524,10 +2534,18 @@ class DesktopTasksController( ) { val targetDisplayId = taskRepository.getDisplayForDesk(deskId) val displayLayout = displayController.getDisplayLayout(targetDisplayId) ?: return val inheritedTaskBounds = getInheritedExistingTaskBounds(taskRepository, shellTaskOrganizer, task, deskId) if (inheritedTaskBounds != null) { // Inherit bounds from closing task instance to prevent application jumping different // cascading positions. wct.setBounds(task.token, inheritedTaskBounds) } else { val initialBounds = getInitialBounds(displayLayout, task, targetDisplayId) if (canChangeTaskPosition(task)) { wct.setBounds(task.token, initialBounds) } } if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { desksOrganizer.moveTaskToDesk(wct = wct, deskId = deskId, task = task) } else { Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +49 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.Intent.FLAG_ACTIVITY_NEW_TASK import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo.CONFIG_DENSITY import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE Loading Loading @@ -1132,6 +1133,54 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() assertThat(finalBounds).isEqualTo(Rect()) } @Test @EnableFlags(Flags.FLAG_INHERIT_TASK_BOUNDS_FOR_TRAMPOLINE_TASK_LAUNCHES) fun addMoveToDeskTaskChanges_newTaskInstance_inheritsClosingInstanceBounds() { // Setup existing task. val existingTask = setUpFreeformTask(active = true) val testComponent = ComponentName(/* package */ "test.package", /* class */ "test.class") existingTask.topActivity = testComponent existingTask.configuration.windowConfiguration.setBounds(Rect(0, 0, 500, 500)) // Set up new instance of already existing task. val launchingTask = setUpFullscreenTask() launchingTask.topActivity = testComponent launchingTask.baseIntent.addFlags(FLAG_ACTIVITY_NEW_TASK) // Move new instance to desktop. By default multi instance is not supported so first // instance will close. val wct = WindowContainerTransaction() controller.addMoveToDeskTaskChanges(wct, launchingTask, deskId = 0) // New instance should inherit task bounds of old instance. assertThat(findBoundsChange(wct, launchingTask)) .isEqualTo(existingTask.configuration.windowConfiguration.bounds) } @Test @EnableFlags(Flags.FLAG_INHERIT_TASK_BOUNDS_FOR_TRAMPOLINE_TASK_LAUNCHES) fun handleRequest_newTaskInstance_inheritsClosingInstanceBounds() { setUpLandscapeDisplay() // Setup existing task. val existingTask = setUpFreeformTask(active = true) val testComponent = ComponentName(/* package */ "test.package", /* class */ "test.class") existingTask.topActivity = testComponent existingTask.configuration.windowConfiguration.setBounds(Rect(0, 0, 500, 500)) // Set up new instance of already existing task. val launchingTask = setUpFreeformTask(active = false) taskRepository.removeTask(launchingTask.displayId, launchingTask.taskId) launchingTask.topActivity = testComponent launchingTask.baseIntent.addFlags(FLAG_ACTIVITY_NEW_TASK) // Move new instance to desktop. By default multi instance is not supported so first // instance will close. val wct = controller.handleRequest(Binder(), createTransition(launchingTask)) assertNotNull(wct, "should handle request") val finalBounds = findBoundsChange(wct, launchingTask) // New instance should inherit task bounds of old instance. assertThat(finalBounds).isEqualTo(existingTask.configuration.windowConfiguration.bounds) } @Test @EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS) fun handleRequest_newFreeformTaskLaunch_cascadeApplied() { Loading services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java +53 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,12 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; Loading Loading @@ -131,6 +137,18 @@ class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { return RESULT_SKIP; } if (DesktopModeFlags.INHERIT_TASK_BOUNDS_FOR_TRAMPOLINE_TASK_LAUNCHES.isTrue()) { ActivityRecord topVisibleFreeformActivity = task.getDisplayContent().getTopMostVisibleFreeformActivity(); if (shouldInheritExistingTaskBounds(topVisibleFreeformActivity, activity, task)) { appendLog("inheriting bounds from existing closing instance"); outParams.mBounds.set(topVisibleFreeformActivity.getBounds()); appendLog("final desktop mode task bounds set to %s", outParams.mBounds); // Return result done to prevent other modifiers from changing or cascading bounds. return RESULT_DONE; } } DesktopModeBoundsCalculator.updateInitialBounds(task, layout, activity, options, outParams.mBounds, this::appendLog); appendLog("final desktop mode task bounds set to %s", outParams.mBounds); Loading Loading @@ -159,7 +177,7 @@ class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { // activity will also enter desktop mode. On this same relationship, we can also assume // if there are not visible freeform tasks but a freeform activity is now launching, it // will force the device into desktop mode. return (task.getDisplayContent().getTopMostVisibleFreeformActivity() != null return (task.getDisplayContent().getTopMostFreeformActivity() != null && checkSourceWindowModesCompatible(task, options, currentParams)) || isRequestingFreeformWindowMode(task, options, currentParams); } Loading Loading @@ -201,6 +219,40 @@ class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { }; } /** * Whether the launching task should inherit the task bounds of an existing closing instance. */ private boolean shouldInheritExistingTaskBounds( @Nullable ActivityRecord existingTaskActivity, @Nullable ActivityRecord launchingActivity, @NonNull Task launchingTask) { if (existingTaskActivity == null || launchingActivity == null) return false; return (existingTaskActivity.packageName == launchingActivity.packageName) && isLaunchingNewTask(launchingActivity.launchMode, launchingTask.getBaseIntent().getFlags()) && isClosingExitingInstance(launchingTask.getBaseIntent().getFlags()); } /** * Returns true if the launch mode or intent will result in a new task being created for the * activity. */ private boolean isLaunchingNewTask(int launchMode, int intentFlags) { return launchMode == LAUNCH_SINGLE_TASK || launchMode == LAUNCH_SINGLE_INSTANCE || launchMode == LAUNCH_SINGLE_INSTANCE_PER_TASK || (intentFlags & FLAG_ACTIVITY_NEW_TASK) != 0; } /** * Returns true if the intent will result in an existing task instance being closed if a new * one appears. */ private boolean isClosingExitingInstance(int intentFlags) { return (intentFlags & FLAG_ACTIVITY_CLEAR_TASK) != 0 || (intentFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0; } private void initLogBuilder(Task task, ActivityRecord activity) { if (DEBUG) { mLogBuilder = new StringBuilder( Loading Loading
core/java/android/app/TaskInfo.java +4 −2 Original line number Diff line number Diff line Loading @@ -655,8 +655,10 @@ public class TaskInfo { + " effectiveUid=" + effectiveUid + " displayId=" + displayId + " isRunning=" + isRunning + " baseIntent=" + baseIntent + " baseActivity=" + baseActivity + " topActivity=" + topActivity + " origActivity=" + origActivity + " baseIntent=" + baseIntent + " baseActivity=" + baseActivity + " topActivity=" + topActivity + " origActivity=" + origActivity + " realActivity=" + realActivity + " numActivities=" + numActivities + " lastActiveTime=" + lastActiveTime Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt +61 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,13 @@ import android.annotation.DimenRes import android.app.ActivityManager.RunningTaskInfo import android.app.TaskInfo import android.content.Context import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK import android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK import android.content.Intent.FLAG_ACTIVITY_NEW_TASK import android.content.pm.ActivityInfo.LAUNCH_MULTIPLE import android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE import android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK import android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED import android.content.pm.ActivityInfo.isFixedOrientationLandscape import android.content.pm.ActivityInfo.isFixedOrientationPortrait Loading @@ -30,7 +37,9 @@ import android.content.res.Configuration.ORIENTATION_PORTRAIT import android.graphics.Rect import android.os.SystemProperties import android.util.Size import android.window.DesktopModeFlags import com.android.wm.shell.R import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayLayout import kotlin.math.ceil Loading Loading @@ -263,6 +272,58 @@ fun getAppHeaderHeight(context: Context): Int = /** Returns the resource id of the app header height in desktop mode. */ @DimenRes fun getAppHeaderHeightId(): Int = R.dimen.desktop_mode_freeform_decor_caption_height /** * Returns the task bounds a launching task should inherit from an existing running instance. * Returns null if there are no bounds to inherit. */ fun getInheritedExistingTaskBounds( taskRepository: DesktopRepository, shellTaskOrganizer: ShellTaskOrganizer, task: RunningTaskInfo, deskId: Int, ): Rect? { if (!DesktopModeFlags.INHERIT_TASK_BOUNDS_FOR_TRAMPOLINE_TASK_LAUNCHES.isTrue) return null val activeTask = taskRepository.getExpandedTasksIdsInDeskOrdered(deskId).firstOrNull() if (activeTask == null) return null val lastTask = shellTaskOrganizer.getRunningTaskInfo(activeTask) val lastTaskTopActivity = lastTask?.topActivity val currentTaskTopActivity = task.topActivity val intentFlags = task.baseIntent.flags val launchMode = task.topActivityInfo?.launchMode ?: LAUNCH_MULTIPLE return when { // No running task activity to inherit bounds from. lastTaskTopActivity == null -> null // No current top activity to set bounds for. currentTaskTopActivity == null -> null // Top task is not an instance of the launching activity, do not inherit its bounds. lastTaskTopActivity.packageName != currentTaskTopActivity.packageName -> null // Top task is an instance of launching activity. Activity will be launching in a new // task with the existing task also being closed. Inherit existing task bounds to // prevent new task jumping. (isLaunchingNewTask(launchMode, intentFlags) && isClosingExitingInstance(intentFlags)) -> lastTask.configuration.windowConfiguration.bounds else -> null } } /** * Returns true if the launch mode or intent will result in a new task being created for the * activity. */ private fun isLaunchingNewTask(launchMode: Int, intentFlags: Int) = launchMode == LAUNCH_SINGLE_TASK || launchMode == LAUNCH_SINGLE_INSTANCE || launchMode == LAUNCH_SINGLE_INSTANCE_PER_TASK || (intentFlags and FLAG_ACTIVITY_NEW_TASK) != 0 /** * Returns true if the intent will result in an existing task instance being closed if a new one * appears. */ private fun isClosingExitingInstance(intentFlags: Int) = (intentFlags and FLAG_ACTIVITY_CLEAR_TASK) != 0 || (intentFlags and FLAG_ACTIVITY_MULTIPLE_TASK) == 0 /** * Calculates the desired initial bounds for applications in desktop windowing. This is done as a * scale of the screen bounds. Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +23 −5 Original line number Diff line number Diff line Loading @@ -32,6 +32,8 @@ import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.app.WindowConfiguration.WindowingMode import android.content.Context import android.content.Intent import android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK import android.content.Intent.FLAG_ACTIVITY_NEW_TASK import android.graphics.Point import android.graphics.PointF import android.graphics.Rect Loading Loading @@ -2284,10 +2286,18 @@ class DesktopTasksController( wct.reorder(task.token, true) return wct } val inheritedTaskBounds = getInheritedExistingTaskBounds(taskRepository, shellTaskOrganizer, task, deskId) if (!taskRepository.isActiveTask(task.taskId) && inheritedTaskBounds != null) { // Inherit bounds from closing task instance to prevent application jumping different // cascading positions. wct.setBounds(task.token, inheritedTaskBounds) } // TODO(b/365723620): Handle non running tasks that were launched after reboot. // If task is already visible, it must have been handled already and added to desktop mode. // Cascade task only if it's not visible yet. // Cascade task only if it's not visible yet and has no inherited bounds. if ( inheritedTaskBounds == null && DesktopModeFlags.ENABLE_CASCADING_WINDOWS.isTrue() && !taskRepository.isVisibleTask(task.taskId) ) { Loading Loading @@ -2524,10 +2534,18 @@ class DesktopTasksController( ) { val targetDisplayId = taskRepository.getDisplayForDesk(deskId) val displayLayout = displayController.getDisplayLayout(targetDisplayId) ?: return val inheritedTaskBounds = getInheritedExistingTaskBounds(taskRepository, shellTaskOrganizer, task, deskId) if (inheritedTaskBounds != null) { // Inherit bounds from closing task instance to prevent application jumping different // cascading positions. wct.setBounds(task.token, inheritedTaskBounds) } else { val initialBounds = getInitialBounds(displayLayout, task, targetDisplayId) if (canChangeTaskPosition(task)) { wct.setBounds(task.token, initialBounds) } } if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { desksOrganizer.moveTaskToDesk(wct = wct, deskId = deskId, task = task) } else { Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +49 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.Intent.FLAG_ACTIVITY_NEW_TASK import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo.CONFIG_DENSITY import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE Loading Loading @@ -1132,6 +1133,54 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() assertThat(finalBounds).isEqualTo(Rect()) } @Test @EnableFlags(Flags.FLAG_INHERIT_TASK_BOUNDS_FOR_TRAMPOLINE_TASK_LAUNCHES) fun addMoveToDeskTaskChanges_newTaskInstance_inheritsClosingInstanceBounds() { // Setup existing task. val existingTask = setUpFreeformTask(active = true) val testComponent = ComponentName(/* package */ "test.package", /* class */ "test.class") existingTask.topActivity = testComponent existingTask.configuration.windowConfiguration.setBounds(Rect(0, 0, 500, 500)) // Set up new instance of already existing task. val launchingTask = setUpFullscreenTask() launchingTask.topActivity = testComponent launchingTask.baseIntent.addFlags(FLAG_ACTIVITY_NEW_TASK) // Move new instance to desktop. By default multi instance is not supported so first // instance will close. val wct = WindowContainerTransaction() controller.addMoveToDeskTaskChanges(wct, launchingTask, deskId = 0) // New instance should inherit task bounds of old instance. assertThat(findBoundsChange(wct, launchingTask)) .isEqualTo(existingTask.configuration.windowConfiguration.bounds) } @Test @EnableFlags(Flags.FLAG_INHERIT_TASK_BOUNDS_FOR_TRAMPOLINE_TASK_LAUNCHES) fun handleRequest_newTaskInstance_inheritsClosingInstanceBounds() { setUpLandscapeDisplay() // Setup existing task. val existingTask = setUpFreeformTask(active = true) val testComponent = ComponentName(/* package */ "test.package", /* class */ "test.class") existingTask.topActivity = testComponent existingTask.configuration.windowConfiguration.setBounds(Rect(0, 0, 500, 500)) // Set up new instance of already existing task. val launchingTask = setUpFreeformTask(active = false) taskRepository.removeTask(launchingTask.displayId, launchingTask.taskId) launchingTask.topActivity = testComponent launchingTask.baseIntent.addFlags(FLAG_ACTIVITY_NEW_TASK) // Move new instance to desktop. By default multi instance is not supported so first // instance will close. val wct = controller.handleRequest(Binder(), createTransition(launchingTask)) assertNotNull(wct, "should handle request") val finalBounds = findBoundsChange(wct, launchingTask) // New instance should inherit task bounds of old instance. assertThat(finalBounds).isEqualTo(existingTask.configuration.windowConfiguration.bounds) } @Test @EnableFlags(Flags.FLAG_ENABLE_CASCADING_WINDOWS) fun handleRequest_newFreeformTaskLaunch_cascadeApplied() { Loading
services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java +53 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,12 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; Loading Loading @@ -131,6 +137,18 @@ class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { return RESULT_SKIP; } if (DesktopModeFlags.INHERIT_TASK_BOUNDS_FOR_TRAMPOLINE_TASK_LAUNCHES.isTrue()) { ActivityRecord topVisibleFreeformActivity = task.getDisplayContent().getTopMostVisibleFreeformActivity(); if (shouldInheritExistingTaskBounds(topVisibleFreeformActivity, activity, task)) { appendLog("inheriting bounds from existing closing instance"); outParams.mBounds.set(topVisibleFreeformActivity.getBounds()); appendLog("final desktop mode task bounds set to %s", outParams.mBounds); // Return result done to prevent other modifiers from changing or cascading bounds. return RESULT_DONE; } } DesktopModeBoundsCalculator.updateInitialBounds(task, layout, activity, options, outParams.mBounds, this::appendLog); appendLog("final desktop mode task bounds set to %s", outParams.mBounds); Loading Loading @@ -159,7 +177,7 @@ class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { // activity will also enter desktop mode. On this same relationship, we can also assume // if there are not visible freeform tasks but a freeform activity is now launching, it // will force the device into desktop mode. return (task.getDisplayContent().getTopMostVisibleFreeformActivity() != null return (task.getDisplayContent().getTopMostFreeformActivity() != null && checkSourceWindowModesCompatible(task, options, currentParams)) || isRequestingFreeformWindowMode(task, options, currentParams); } Loading Loading @@ -201,6 +219,40 @@ class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { }; } /** * Whether the launching task should inherit the task bounds of an existing closing instance. */ private boolean shouldInheritExistingTaskBounds( @Nullable ActivityRecord existingTaskActivity, @Nullable ActivityRecord launchingActivity, @NonNull Task launchingTask) { if (existingTaskActivity == null || launchingActivity == null) return false; return (existingTaskActivity.packageName == launchingActivity.packageName) && isLaunchingNewTask(launchingActivity.launchMode, launchingTask.getBaseIntent().getFlags()) && isClosingExitingInstance(launchingTask.getBaseIntent().getFlags()); } /** * Returns true if the launch mode or intent will result in a new task being created for the * activity. */ private boolean isLaunchingNewTask(int launchMode, int intentFlags) { return launchMode == LAUNCH_SINGLE_TASK || launchMode == LAUNCH_SINGLE_INSTANCE || launchMode == LAUNCH_SINGLE_INSTANCE_PER_TASK || (intentFlags & FLAG_ACTIVITY_NEW_TASK) != 0; } /** * Returns true if the intent will result in an existing task instance being closed if a new * one appears. */ private boolean isClosingExitingInstance(int intentFlags) { return (intentFlags & FLAG_ACTIVITY_CLEAR_TASK) != 0 || (intentFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0; } private void initLogBuilder(Task task, ActivityRecord activity) { if (DEBUG) { mLogBuilder = new StringBuilder( Loading