Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt +27 −27 Original line number Diff line number Diff line Loading @@ -207,37 +207,27 @@ fun calculateMaximizeBounds(displayLayout: DisplayLayout, taskInfo: RunningTaskI } /** * Position the new window based on the drag event. * It uses the drag shadow to maintain the relative position on the new window. * If shadow has anomaly, the new window is created from the top-center at the drop point. * Position the new window based on the drag event. It uses the drag shadow to maintain the relative * position on the new window. If shadow has anomaly, the new window is created from the top-center * at the drop point. */ fun positionDragAndDropBounds( newBounds : Rect, dragEvent : DragEvent ) { fun positionDragAndDropBounds(newBounds: Rect, dragEvent: DragEvent) { val shadowSurface = dragEvent.dragSurface if (DesktopExperienceFlags.ENABLE_INTERACTION_DEPENDENT_TAB_TEARING_BOUNDS.isTrue() && if ( DesktopExperienceFlags.ENABLE_INTERACTION_DEPENDENT_TAB_TEARING_BOUNDS.isTrue() && shadowSurface != null && shadowSurface.isValid && shadowSurface.width != 0) { shadowSurface.width != 0 ) { // Calculate the horizontal offset to maintain the touch point's relative // position on the new window. val dropOffset = calculateDropPositionOffset( dragEvent.offsetX, shadowSurface.width, newBounds.width() ) val dropOffset = calculateDropPositionOffset(dragEvent.offsetX, shadowSurface.width, newBounds.width()) // Position the new window based on the drop point and its relative offset. newBounds.offsetTo( dragEvent.x.toInt() - dropOffset, dragEvent.y.toInt()) newBounds.offsetTo(dragEvent.x.toInt() - dropOffset, dragEvent.y.toInt()) } else { // Position the new window to the top-center at the drop point. newBounds.offsetTo( dragEvent.x.toInt() - (newBounds.width() / 2), dragEvent.y.toInt(), ) newBounds.offsetTo(dragEvent.x.toInt() - (newBounds.width() / 2), dragEvent.y.toInt()) } } Loading Loading @@ -510,13 +500,13 @@ fun createActivityOptionsForStartTask( /** * Calculates the horizontal offset from the left edge of a new window to the user's touch point. * This preserves the same relative position of the touch point as it was on the dragShadow, * which allows a better positioning based on user's finger. * This preserves the same relative position of the touch point as it was on the dragShadow, which * allows a better positioning based on user's finger. */ private fun calculateDropPositionOffset( dragOffsetX: Float, shadowWidth: Int, windowWidth: Int windowWidth: Int, ): Int { val touchPointHorizontalRatio = dragOffsetX / shadowWidth.toFloat() return (windowWidth * touchPointHorizontalRatio).toInt() Loading @@ -539,6 +529,16 @@ private fun positionInScreen(desiredSize: Size, stableBounds: Rect): Rect = offsetTo(offset.x, offset.y) } /** * Gets the freeform caption insets if task was eligible for exclude caption insets from app bounds * compatibility treatment. Returns 0 if no compatibility treatment was applied. */ val TaskInfo.freeformCaptionInsets: Int get() = configuration.windowConfiguration.appBounds?.let { it.top - configuration.windowConfiguration.bounds.top } ?: 0 /** * Whether the activity's aspect ratio can be changed or if it should be maintained as if it was * unresizeable. Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +30 −4 Original line number Diff line number Diff line Loading @@ -2452,6 +2452,7 @@ class DesktopTasksController( bounds: Rect? = null, transitionHandler: TransitionHandler? = null, enterReason: EnterReason, captionInsets: Int = 0, ) { logV("moveToDisplay: taskId=%d displayId=%d", task.taskId, displayId) if (task.displayId == displayId) { Loading Loading @@ -2518,6 +2519,28 @@ class DesktopTasksController( } if (bounds != null) { wct.setBounds(task.token, bounds) val prevCaptionInsets = task.freeformCaptionInsets if (prevCaptionInsets != 0) { val appBounds = Rect(bounds).apply { if (captionInsets != 0) { this.top += captionInsets } else { val captionInsetsDp = displayController .getDisplayLayout(task.getDisplayId()) ?.pxToDp(prevCaptionInsets) ?.toInt() ?: 0 val newDisplayLayout = displayController.getDisplayLayout(displayId) val insets = newDisplayLayout?.dpToPx(captionInsetsDp)?.toInt() ?: 0 this.top += insets } } wct.setAppBounds(task.token, appBounds) } } else if (DesktopExperienceFlags.ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT.isTrue) { applyFreeformDisplayChange(wct, task, displayId, destinationDeskId) } Loading Loading @@ -5718,12 +5741,9 @@ class DesktopTasksController( DesktopExperienceFlags.ENABLE_CONNECTED_DISPLAYS_WINDOW_DRAG.isTrue() && newDisplayId != taskInfo.getDisplayId() && displayAreaInfo != null val prevCaptionInsets = taskInfo.freeformCaptionInsets if (isCrossDisplayDrag) { val prevCaptionInsets = taskInfo.configuration.windowConfiguration.appBounds?.let { it.top - taskInfo.configuration.windowConfiguration.bounds.top } ?: 0 val captionInsetsDp = displayController .getDisplayLayout(taskInfo.getDisplayId()) Loading Loading @@ -5752,12 +5772,18 @@ class DesktopTasksController( constrainedBounds, windowDragTransitionHandler, enterReason = EnterReason.APP_HANDLE_DRAG, captionInsets = captionInsets, ) } else { // Update task bounds so that the task position will match the position of its // leash val wct = WindowContainerTransaction() wct.setBounds(taskInfo.token, destinationBounds) if (prevCaptionInsets != 0) { val appBounds = Rect(destinationBounds).apply { this.top += prevCaptionInsets } wct.setAppBounds(taskInfo.token, appBounds) } transitions.startTransition(TRANSIT_CHANGE, wct, windowDragTransitionHandler) } releaseVisualIndicator() Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt +6 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMe import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.getInputMethodType import com.android.wm.shell.desktopmode.DesktopTasksController import com.android.wm.shell.desktopmode.freeformCaptionInsets import com.android.wm.shell.shared.annotations.ShellMainThread import com.android.wm.shell.shared.desktopmode.DesktopState import com.android.wm.shell.transition.Transitions Loading Loading @@ -316,6 +317,11 @@ class MultiDisplayVeiledResizeTaskPositioner( windowDecoration.updateResizeVeil(repositionTaskBounds) val wct = WindowContainerTransaction() wct.setBounds(windowDecoration.taskInfo.token, repositionTaskBounds) val captionInsets = windowDecoration.taskInfo.freeformCaptionInsets if (captionInsets != 0) { // Reset app bounds if app bounds were overridden. wct.setAppBounds(windowDecoration.taskInfo.token, null) } transitions.startTransition(WindowManager.TRANSIT_CHANGE, wct, this) } else { // If bounds haven't changed, perform necessary veil reset here as startAnimation Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +10 −0 Original line number Diff line number Diff line Loading @@ -8864,9 +8864,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val task = setUpFreeformTask() val spyController = spy(controller) val mockSurface = mock(SurfaceControl::class.java) val captionInsets = 20 val mockDisplayLayout = mock(DisplayLayout::class.java) whenever(displayController.getDisplayLayout(task.displayId)).thenReturn(mockDisplayLayout) whenever(mockDisplayLayout.stableInsets()).thenReturn(Rect(0, 100, 2000, 2000)) task.configuration.windowConfiguration.appBounds = Rect(task.configuration.windowConfiguration.bounds).apply { this.top += captionInsets } spyController.onDragPositioningMove( task, mockSurface, Loading @@ -8891,12 +8894,14 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() motionEvent, ) val rectAfterEnd = Rect(100, 50, 500, 1150) val appBoundsAfterEnd = Rect(rectAfterEnd).apply { this.top += captionInsets } verify(transitions) .startTransition( eq(TRANSIT_CHANGE), Mockito.argThat { wct -> return@argThat wct.changes.any { (token, change) -> change.configuration.windowConfiguration.bounds == rectAfterEnd change.configuration.windowConfiguration.appBounds == appBoundsAfterEnd } }, eq(windowDragTransitionHandler), Loading @@ -8911,8 +8916,11 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val spyController = spy(controller) val mockSurface = mock(SurfaceControl::class.java) val mockDisplayLayout = mock(DisplayLayout::class.java) val captionInsets = 20 whenever(displayController.getDisplayLayout(task.displayId)).thenReturn(mockDisplayLayout) whenever(mockDisplayLayout.stableInsets()).thenReturn(Rect(0, 100, 2000, 2000)) task.configuration.windowConfiguration.appBounds = Rect(task.configuration.windowConfiguration.bounds).apply { this.top += captionInsets } spyController.onDragPositioningMove( task, mockSurface, Loading @@ -8923,6 +8931,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() ) val currentDragBounds = Rect(100, 200, 500, 1000) val appBounds = Rect(currentDragBounds).apply { this.top += captionInsets } whenever(spyController.getVisualIndicator()).thenReturn(desktopModeVisualIndicator) whenever(desktopModeVisualIndicator.updateIndicatorType(any(), anyOrNull())) .thenReturn(DesktopModeVisualIndicator.IndicatorType.NO_INDICATOR) Loading @@ -8945,6 +8954,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() Mockito.argThat { wct -> return@argThat wct.changes.any { (token, change) -> change.configuration.windowConfiguration.bounds == currentDragBounds change.configuration.windowConfiguration.appBounds == appBounds } }, eq(windowDragTransitionHandler), Loading services/core/java/com/android/server/wm/AppCompatSandboxingPolicy.java +4 −1 Original line number Diff line number Diff line Loading @@ -59,7 +59,10 @@ class AppCompatSandboxingPolicy { // parent. appBounds = mActivityRecord.mResolveConfigHint.mParentAppBoundsOverride; } if (!resolvedConfig.windowConfiguration.getBounds().isEmpty()) { // Only set if there is a resolved override config. resolvedConfig.windowConfiguration.setBounds(appBounds); } } } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt +27 −27 Original line number Diff line number Diff line Loading @@ -207,37 +207,27 @@ fun calculateMaximizeBounds(displayLayout: DisplayLayout, taskInfo: RunningTaskI } /** * Position the new window based on the drag event. * It uses the drag shadow to maintain the relative position on the new window. * If shadow has anomaly, the new window is created from the top-center at the drop point. * Position the new window based on the drag event. It uses the drag shadow to maintain the relative * position on the new window. If shadow has anomaly, the new window is created from the top-center * at the drop point. */ fun positionDragAndDropBounds( newBounds : Rect, dragEvent : DragEvent ) { fun positionDragAndDropBounds(newBounds: Rect, dragEvent: DragEvent) { val shadowSurface = dragEvent.dragSurface if (DesktopExperienceFlags.ENABLE_INTERACTION_DEPENDENT_TAB_TEARING_BOUNDS.isTrue() && if ( DesktopExperienceFlags.ENABLE_INTERACTION_DEPENDENT_TAB_TEARING_BOUNDS.isTrue() && shadowSurface != null && shadowSurface.isValid && shadowSurface.width != 0) { shadowSurface.width != 0 ) { // Calculate the horizontal offset to maintain the touch point's relative // position on the new window. val dropOffset = calculateDropPositionOffset( dragEvent.offsetX, shadowSurface.width, newBounds.width() ) val dropOffset = calculateDropPositionOffset(dragEvent.offsetX, shadowSurface.width, newBounds.width()) // Position the new window based on the drop point and its relative offset. newBounds.offsetTo( dragEvent.x.toInt() - dropOffset, dragEvent.y.toInt()) newBounds.offsetTo(dragEvent.x.toInt() - dropOffset, dragEvent.y.toInt()) } else { // Position the new window to the top-center at the drop point. newBounds.offsetTo( dragEvent.x.toInt() - (newBounds.width() / 2), dragEvent.y.toInt(), ) newBounds.offsetTo(dragEvent.x.toInt() - (newBounds.width() / 2), dragEvent.y.toInt()) } } Loading Loading @@ -510,13 +500,13 @@ fun createActivityOptionsForStartTask( /** * Calculates the horizontal offset from the left edge of a new window to the user's touch point. * This preserves the same relative position of the touch point as it was on the dragShadow, * which allows a better positioning based on user's finger. * This preserves the same relative position of the touch point as it was on the dragShadow, which * allows a better positioning based on user's finger. */ private fun calculateDropPositionOffset( dragOffsetX: Float, shadowWidth: Int, windowWidth: Int windowWidth: Int, ): Int { val touchPointHorizontalRatio = dragOffsetX / shadowWidth.toFloat() return (windowWidth * touchPointHorizontalRatio).toInt() Loading @@ -539,6 +529,16 @@ private fun positionInScreen(desiredSize: Size, stableBounds: Rect): Rect = offsetTo(offset.x, offset.y) } /** * Gets the freeform caption insets if task was eligible for exclude caption insets from app bounds * compatibility treatment. Returns 0 if no compatibility treatment was applied. */ val TaskInfo.freeformCaptionInsets: Int get() = configuration.windowConfiguration.appBounds?.let { it.top - configuration.windowConfiguration.bounds.top } ?: 0 /** * Whether the activity's aspect ratio can be changed or if it should be maintained as if it was * unresizeable. Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +30 −4 Original line number Diff line number Diff line Loading @@ -2452,6 +2452,7 @@ class DesktopTasksController( bounds: Rect? = null, transitionHandler: TransitionHandler? = null, enterReason: EnterReason, captionInsets: Int = 0, ) { logV("moveToDisplay: taskId=%d displayId=%d", task.taskId, displayId) if (task.displayId == displayId) { Loading Loading @@ -2518,6 +2519,28 @@ class DesktopTasksController( } if (bounds != null) { wct.setBounds(task.token, bounds) val prevCaptionInsets = task.freeformCaptionInsets if (prevCaptionInsets != 0) { val appBounds = Rect(bounds).apply { if (captionInsets != 0) { this.top += captionInsets } else { val captionInsetsDp = displayController .getDisplayLayout(task.getDisplayId()) ?.pxToDp(prevCaptionInsets) ?.toInt() ?: 0 val newDisplayLayout = displayController.getDisplayLayout(displayId) val insets = newDisplayLayout?.dpToPx(captionInsetsDp)?.toInt() ?: 0 this.top += insets } } wct.setAppBounds(task.token, appBounds) } } else if (DesktopExperienceFlags.ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT.isTrue) { applyFreeformDisplayChange(wct, task, displayId, destinationDeskId) } Loading Loading @@ -5718,12 +5741,9 @@ class DesktopTasksController( DesktopExperienceFlags.ENABLE_CONNECTED_DISPLAYS_WINDOW_DRAG.isTrue() && newDisplayId != taskInfo.getDisplayId() && displayAreaInfo != null val prevCaptionInsets = taskInfo.freeformCaptionInsets if (isCrossDisplayDrag) { val prevCaptionInsets = taskInfo.configuration.windowConfiguration.appBounds?.let { it.top - taskInfo.configuration.windowConfiguration.bounds.top } ?: 0 val captionInsetsDp = displayController .getDisplayLayout(taskInfo.getDisplayId()) Loading Loading @@ -5752,12 +5772,18 @@ class DesktopTasksController( constrainedBounds, windowDragTransitionHandler, enterReason = EnterReason.APP_HANDLE_DRAG, captionInsets = captionInsets, ) } else { // Update task bounds so that the task position will match the position of its // leash val wct = WindowContainerTransaction() wct.setBounds(taskInfo.token, destinationBounds) if (prevCaptionInsets != 0) { val appBounds = Rect(destinationBounds).apply { this.top += prevCaptionInsets } wct.setAppBounds(taskInfo.token, appBounds) } transitions.startTransition(TRANSIT_CHANGE, wct, windowDragTransitionHandler) } releaseVisualIndicator() Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt +6 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMe import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.getInputMethodType import com.android.wm.shell.desktopmode.DesktopTasksController import com.android.wm.shell.desktopmode.freeformCaptionInsets import com.android.wm.shell.shared.annotations.ShellMainThread import com.android.wm.shell.shared.desktopmode.DesktopState import com.android.wm.shell.transition.Transitions Loading Loading @@ -316,6 +317,11 @@ class MultiDisplayVeiledResizeTaskPositioner( windowDecoration.updateResizeVeil(repositionTaskBounds) val wct = WindowContainerTransaction() wct.setBounds(windowDecoration.taskInfo.token, repositionTaskBounds) val captionInsets = windowDecoration.taskInfo.freeformCaptionInsets if (captionInsets != 0) { // Reset app bounds if app bounds were overridden. wct.setAppBounds(windowDecoration.taskInfo.token, null) } transitions.startTransition(WindowManager.TRANSIT_CHANGE, wct, this) } else { // If bounds haven't changed, perform necessary veil reset here as startAnimation Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +10 −0 Original line number Diff line number Diff line Loading @@ -8864,9 +8864,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val task = setUpFreeformTask() val spyController = spy(controller) val mockSurface = mock(SurfaceControl::class.java) val captionInsets = 20 val mockDisplayLayout = mock(DisplayLayout::class.java) whenever(displayController.getDisplayLayout(task.displayId)).thenReturn(mockDisplayLayout) whenever(mockDisplayLayout.stableInsets()).thenReturn(Rect(0, 100, 2000, 2000)) task.configuration.windowConfiguration.appBounds = Rect(task.configuration.windowConfiguration.bounds).apply { this.top += captionInsets } spyController.onDragPositioningMove( task, mockSurface, Loading @@ -8891,12 +8894,14 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() motionEvent, ) val rectAfterEnd = Rect(100, 50, 500, 1150) val appBoundsAfterEnd = Rect(rectAfterEnd).apply { this.top += captionInsets } verify(transitions) .startTransition( eq(TRANSIT_CHANGE), Mockito.argThat { wct -> return@argThat wct.changes.any { (token, change) -> change.configuration.windowConfiguration.bounds == rectAfterEnd change.configuration.windowConfiguration.appBounds == appBoundsAfterEnd } }, eq(windowDragTransitionHandler), Loading @@ -8911,8 +8916,11 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val spyController = spy(controller) val mockSurface = mock(SurfaceControl::class.java) val mockDisplayLayout = mock(DisplayLayout::class.java) val captionInsets = 20 whenever(displayController.getDisplayLayout(task.displayId)).thenReturn(mockDisplayLayout) whenever(mockDisplayLayout.stableInsets()).thenReturn(Rect(0, 100, 2000, 2000)) task.configuration.windowConfiguration.appBounds = Rect(task.configuration.windowConfiguration.bounds).apply { this.top += captionInsets } spyController.onDragPositioningMove( task, mockSurface, Loading @@ -8923,6 +8931,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() ) val currentDragBounds = Rect(100, 200, 500, 1000) val appBounds = Rect(currentDragBounds).apply { this.top += captionInsets } whenever(spyController.getVisualIndicator()).thenReturn(desktopModeVisualIndicator) whenever(desktopModeVisualIndicator.updateIndicatorType(any(), anyOrNull())) .thenReturn(DesktopModeVisualIndicator.IndicatorType.NO_INDICATOR) Loading @@ -8945,6 +8954,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() Mockito.argThat { wct -> return@argThat wct.changes.any { (token, change) -> change.configuration.windowConfiguration.bounds == currentDragBounds change.configuration.windowConfiguration.appBounds == appBounds } }, eq(windowDragTransitionHandler), Loading
services/core/java/com/android/server/wm/AppCompatSandboxingPolicy.java +4 −1 Original line number Diff line number Diff line Loading @@ -59,7 +59,10 @@ class AppCompatSandboxingPolicy { // parent. appBounds = mActivityRecord.mResolveConfigHint.mParentAppBoundsOverride; } if (!resolvedConfig.windowConfiguration.getBounds().isEmpty()) { // Only set if there is a resolved override config. resolvedConfig.windowConfiguration.setBounds(appBounds); } } } }