Merge "Add support to move task to another display" into udc-dev
This commit is contained in:
@@ -180,6 +180,17 @@ public class RootTaskDisplayAreaOrganizer extends DisplayAreaOrganizer {
|
||||
applyConfigChangesToContext(displayAreaInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of display ids that are tracked by a {@link DisplayAreaInfo}
|
||||
*/
|
||||
public int[] getDisplayIds() {
|
||||
int[] displayIds = new int[mDisplayAreasInfo.size()];
|
||||
for (int i = 0; i < mDisplayAreasInfo.size(); i++) {
|
||||
displayIds[i] = mDisplayAreasInfo.keyAt(i);
|
||||
}
|
||||
return displayIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link DisplayAreaInfo} of the {@link DisplayAreaInfo#displayId}.
|
||||
*/
|
||||
|
||||
@@ -48,6 +48,12 @@ public class DesktopModeStatus {
|
||||
private static final boolean IS_VEILED_RESIZE_ENABLED = SystemProperties.getBoolean(
|
||||
"persist.wm.debug.desktop_veiled_resizing", true);
|
||||
|
||||
/**
|
||||
* Flag to indicate is moving task to another display is enabled.
|
||||
*/
|
||||
public static final boolean IS_DISPLAY_CHANGE_ENABLED = SystemProperties.getBoolean(
|
||||
"persist.wm.debug.desktop_change_display", false);
|
||||
|
||||
/**
|
||||
* Return {@code true} if desktop mode support is enabled
|
||||
*/
|
||||
|
||||
@@ -234,6 +234,69 @@ class DesktopTasksController(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move task to the next display.
|
||||
*
|
||||
* Queries all current known display ids and sorts them in ascending order. Then iterates
|
||||
* through the list and looks for the display id that is larger than the display id for
|
||||
* the passed in task. If a display with a higher id is not found, iterates through the list and
|
||||
* finds the first display id that is not the display id for the passed in task.
|
||||
*
|
||||
* If a display matching the above criteria is found, re-parents the task to that display.
|
||||
* No-op if no such display is found.
|
||||
*/
|
||||
fun moveToNextDisplay(taskId: Int) {
|
||||
val task = shellTaskOrganizer.getRunningTaskInfo(taskId)
|
||||
if (task == null) {
|
||||
ProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveToNextDisplay: taskId=%d not found", taskId)
|
||||
return
|
||||
}
|
||||
ProtoLog.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
|
||||
var newDisplayId = displayIds.firstOrNull { displayId -> displayId > task.displayId }
|
||||
if (newDisplayId == null) {
|
||||
// No display with a higher id, get the first display id that is not the task display id
|
||||
newDisplayId = displayIds.firstOrNull { displayId -> displayId < task.displayId }
|
||||
}
|
||||
if (newDisplayId == null) {
|
||||
ProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveToNextDisplay: next display not found")
|
||||
return
|
||||
}
|
||||
moveToDisplay(task, newDisplayId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Move [task] to display with [displayId].
|
||||
*
|
||||
* No-op if task is already on that display per [RunningTaskInfo.displayId].
|
||||
*/
|
||||
private fun moveToDisplay(task: RunningTaskInfo, displayId: Int) {
|
||||
ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToDisplay: taskId=%d displayId=%d",
|
||||
task.taskId, displayId)
|
||||
|
||||
if (task.displayId == displayId) {
|
||||
ProtoLog.d(WM_SHELL_DESKTOP_MODE, "moveToDisplay: task already on display")
|
||||
return
|
||||
}
|
||||
|
||||
val displayAreaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId)
|
||||
if (displayAreaInfo == null) {
|
||||
ProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveToDisplay: display not found")
|
||||
return
|
||||
}
|
||||
|
||||
val wct = WindowContainerTransaction()
|
||||
wct.reparent(task.token, displayAreaInfo.token, true /* onTop */)
|
||||
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
|
||||
transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
|
||||
} else {
|
||||
shellTaskOrganizer.applyTransaction(wct)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get windowing move for a given `taskId`
|
||||
*
|
||||
|
||||
@@ -326,6 +326,13 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
|
||||
decoration.closeHandleMenu();
|
||||
} else if (id == R.id.collapse_menu_button) {
|
||||
decoration.closeHandleMenu();
|
||||
} else if (id == R.id.select_button) {
|
||||
if (DesktopModeStatus.IS_DISPLAY_CHANGE_ENABLED) {
|
||||
// TODO(b/278084491): dev option to enable display switching
|
||||
// remove when select is implemented
|
||||
mDesktopTasksController.ifPresent(c -> c.moveToNextDisplay(mTaskId));
|
||||
decoration.closeHandleMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -187,6 +187,8 @@ class HandleMenu {
|
||||
final View moreActionsPillView = mMoreActionsPill.mWindowViewHost.getView();
|
||||
final Button closeBtn = moreActionsPillView.findViewById(R.id.close_button);
|
||||
closeBtn.setOnClickListener(mOnClickListener);
|
||||
final Button selectBtn = moreActionsPillView.findViewById(R.id.select_button);
|
||||
selectBtn.setOnClickListener(mOnClickListener);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.view.WindowManager.TRANSIT_CHANGE
|
||||
import android.view.WindowManager.TRANSIT_NONE
|
||||
import android.view.WindowManager.TRANSIT_OPEN
|
||||
import android.view.WindowManager.TRANSIT_TO_FRONT
|
||||
import android.window.DisplayAreaInfo
|
||||
import android.window.TransitionRequestInfo
|
||||
import android.window.WindowContainerTransaction
|
||||
import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER
|
||||
@@ -343,6 +344,57 @@ class DesktopTasksControllerTest : ShellTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun moveToNextDisplay_noOtherDisplays() {
|
||||
whenever(rootTaskDisplayAreaOrganizer.displayIds).thenReturn(intArrayOf(DEFAULT_DISPLAY))
|
||||
val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
|
||||
controller.moveToNextDisplay(task.taskId)
|
||||
verifyWCTNotExecuted()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun moveToNextDisplay_moveFromFirstToSecondDisplay() {
|
||||
// Set up two display ids
|
||||
whenever(rootTaskDisplayAreaOrganizer.displayIds)
|
||||
.thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY))
|
||||
// Create a mock for the target display area: second display
|
||||
val secondDisplayArea = DisplayAreaInfo(MockToken().token(), SECOND_DISPLAY, 0)
|
||||
whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(SECOND_DISPLAY))
|
||||
.thenReturn(secondDisplayArea)
|
||||
|
||||
val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
|
||||
controller.moveToNextDisplay(task.taskId)
|
||||
with(getLatestWct(expectTransition = TRANSIT_CHANGE)) {
|
||||
assertThat(hierarchyOps).hasSize(1)
|
||||
assertThat(hierarchyOps[0].container).isEqualTo(task.token.asBinder())
|
||||
assertThat(hierarchyOps[0].isReparent).isTrue()
|
||||
assertThat(hierarchyOps[0].newParent).isEqualTo(secondDisplayArea.token.asBinder())
|
||||
assertThat(hierarchyOps[0].toTop).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun moveToNextDisplay_moveFromSecondToFirstDisplay() {
|
||||
// Set up two display ids
|
||||
whenever(rootTaskDisplayAreaOrganizer.displayIds)
|
||||
.thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY))
|
||||
// Create a mock for the target display area: default display
|
||||
val defaultDisplayArea = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0)
|
||||
whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY))
|
||||
.thenReturn(defaultDisplayArea)
|
||||
|
||||
val task = setUpFreeformTask(displayId = SECOND_DISPLAY)
|
||||
controller.moveToNextDisplay(task.taskId)
|
||||
|
||||
with(getLatestWct(expectTransition = TRANSIT_CHANGE)) {
|
||||
assertThat(hierarchyOps).hasSize(1)
|
||||
assertThat(hierarchyOps[0].container).isEqualTo(task.token.asBinder())
|
||||
assertThat(hierarchyOps[0].isReparent).isTrue()
|
||||
assertThat(hierarchyOps[0].newParent).isEqualTo(defaultDisplayArea.token.asBinder())
|
||||
assertThat(hierarchyOps[0].toTop).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getTaskWindowingMode() {
|
||||
val fullscreenTask = setUpFullscreenTask()
|
||||
|
||||
Reference in New Issue
Block a user