Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java +22 −1 Original line number Diff line number Diff line Loading @@ -103,6 +103,10 @@ public class DesktopModeVisualIndicator { return null; } } private static boolean isDragToDesktopStartState(DragStartState startState) { return startState == FROM_FULLSCREEN || startState == FROM_SPLIT; } } private final VisualIndicatorViewContainer mVisualIndicatorViewContainer; Loading @@ -125,7 +129,12 @@ public class DesktopModeVisualIndicator { @Nullable BubbleDropTargetBoundsProvider bubbleBoundsProvider, SnapEventHandler snapEventHandler) { SurfaceControl.Builder builder = new SurfaceControl.Builder(); if (!DragStartState.isDragToDesktopStartState(dragStartState) || !DesktopModeFlags.ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX.isTrue()) { // In the DragToDesktop transition we attach the indicator to the transition root once // that is available - for all other cases attach the indicator here. taskDisplayAreaOrganizer.attachToDisplayArea(taskInfo.displayId, builder); } mVisualIndicatorViewContainer = new VisualIndicatorViewContainer( DesktopModeFlags.ENABLE_DESKTOP_INDICATOR_IN_SEPARATE_THREAD_BUGFIX.isTrue() ? desktopExecutor : mainExecutor, Loading Loading @@ -159,6 +168,18 @@ public class DesktopModeVisualIndicator { mVisualIndicatorViewContainer.releaseVisualIndicator(); } /** Reparent the visual indicator to {@code newParent}. */ void reparentLeash(SurfaceControl.Transaction t, SurfaceControl newParent) { mVisualIndicatorViewContainer.reparentLeash(t, newParent); } /** Start the fade-in animation. */ void fadeInIndicator() { mVisualIndicatorViewContainer.fadeInIndicator( mDisplayController.getDisplayLayout(mTaskInfo.displayId), mCurrentType, mTaskInfo.displayId); } /** * Based on the coordinates of the current drag event, determine which indicator type we should * display, including no visible indicator. Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +1 −0 Original line number Diff line number Diff line Loading @@ -639,6 +639,7 @@ class DesktopTasksController( dragToDesktopTransitionHandler.startDragToDesktopTransition( taskInfo, dragToDesktopValueAnimator, visualIndicator, ) } Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt +29 −2 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.os.SystemProperties import android.os.UserHandle import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CLOSE import android.window.DesktopModeFlags import android.window.TransitionInfo import android.window.TransitionInfo.Change import android.window.TransitionRequestInfo Loading Loading @@ -118,6 +119,7 @@ sealed class DragToDesktopTransitionHandler( fun startDragToDesktopTransition( taskInfo: RunningTaskInfo, dragToDesktopAnimator: MoveToDesktopAnimator, visualIndicator: DesktopModeVisualIndicator?, ) { if (inProgress) { logV("Drag to desktop transition already in progress.") Loading Loading @@ -163,12 +165,14 @@ sealed class DragToDesktopTransitionHandler( dragAnimator = dragToDesktopAnimator, startTransitionToken = startTransitionToken, otherSplitTask = otherTask, visualIndicator = visualIndicator, ) } else { TransitionState.FromFullscreen( draggedTaskId = taskInfo.taskId, dragAnimator = dragToDesktopAnimator, startTransitionToken = startTransitionToken, visualIndicator = visualIndicator, ) } } Loading Loading @@ -457,6 +461,13 @@ sealed class DragToDesktopTransitionHandler( state.surfaceLayers = layers state.startTransitionFinishCb = finishCallback state.startTransitionFinishTransaction = finishTransaction val taskChange = state.draggedTaskChange ?: error("Expected non-null task change.") val taskInfo = taskChange.taskInfo ?: error("Expected non-null task info.") if (DesktopModeFlags.ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX.isTrue) { attachIndicatorToTransitionRoot(state, info, taskInfo, startTransaction) } startTransaction.apply() if (state.cancelState == CancelState.NO_CANCEL) { Loading Loading @@ -485,8 +496,6 @@ sealed class DragToDesktopTransitionHandler( } else { SPLIT_POSITION_BOTTOM_OR_RIGHT } val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null task info.") val wct = WindowContainerTransaction() restoreWindowOrder(wct) state.startTransitionFinishTransaction?.apply() Loading @@ -511,6 +520,21 @@ sealed class DragToDesktopTransitionHandler( return true } private fun attachIndicatorToTransitionRoot( state: TransitionState, info: TransitionInfo, taskInfo: RunningTaskInfo, t: SurfaceControl.Transaction, ) { val transitionRoot = info.getRoot(info.findRootIndex(taskInfo.displayId)) state.visualIndicator?.let { // Attach the indicator to the transition root so that it's removed at the end of the // transition regardless of whether we managed to release the indicator. it.reparentLeash(t, transitionRoot.leash) it.fadeInIndicator() } } /** * Calculates start drag to desktop layers for transition [info]. The leash layer is calculated * based on its change position in the transition, e.g. `appLayer = appLayers - i`, where i is Loading Loading @@ -901,6 +925,7 @@ sealed class DragToDesktopTransitionHandler( abstract var surfaceLayers: DragToDesktopLayers? abstract var cancelState: CancelState abstract var startAborted: Boolean abstract val visualIndicator: DesktopModeVisualIndicator? data class FromFullscreen( override val draggedTaskId: Int, Loading @@ -915,6 +940,7 @@ sealed class DragToDesktopTransitionHandler( override var surfaceLayers: DragToDesktopLayers? = null, override var cancelState: CancelState = CancelState.NO_CANCEL, override var startAborted: Boolean = false, override val visualIndicator: DesktopModeVisualIndicator?, var otherRootChanges: MutableList<Change> = mutableListOf(), ) : TransitionState() Loading @@ -931,6 +957,7 @@ sealed class DragToDesktopTransitionHandler( override var surfaceLayers: DragToDesktopLayers? = null, override var cancelState: CancelState = CancelState.NO_CANCEL, override var startAborted: Boolean = false, override val visualIndicator: DesktopModeVisualIndicator?, var splitRootChange: Change? = null, var otherSplitTask: Int, ) : TransitionState() Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainer.kt +20 −2 Original line number Diff line number Diff line Loading @@ -130,6 +130,12 @@ constructor( } } /** Reparent the indicator to {@code newParent}. */ fun reparentLeash(t: SurfaceControl.Transaction, newParent: SurfaceControl) { val leash = indicatorLeash ?: return t.reparent(leash, newParent) } private fun showIndicator(taskSurface: SurfaceControl, leash: SurfaceControl) { mainExecutor.execute { indicatorLeash = leash Loading Loading @@ -166,7 +172,7 @@ constructor( displayController.getDisplayLayout(taskInfo.displayId) ?: error("Expected to find DisplayLayout for taskId${taskInfo.taskId}.") if (currentType == IndicatorType.NO_INDICATOR) { fadeInIndicator(layout, newType, taskInfo.displayId, snapEventHandler) fadeInIndicatorInternal(layout, newType, taskInfo.displayId, snapEventHandler) } else if (newType == IndicatorType.NO_INDICATOR) { fadeOutIndicator( layout, Loading Loading @@ -194,11 +200,23 @@ constructor( } } /** * Fade indicator in as provided type. * * Animator fades the indicator in while expanding the bounds outwards. */ fun fadeInIndicator(layout: DisplayLayout, type: IndicatorType, displayId: Int) { if (isReleased) return desktopExecutor.execute { fadeInIndicatorInternal(layout, type, displayId, snapEventHandler) } } /** * Fade indicator in as provided type. Animator fades it in while expanding the bounds outwards. */ @VisibleForTesting fun fadeInIndicator( fun fadeInIndicatorInternal( layout: DisplayLayout, type: IndicatorType, displayId: Int, Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt +36 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.animation.AnimatorTestRule import android.app.ActivityManager.RunningTaskInfo import android.graphics.PointF import android.graphics.Rect import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper Loading @@ -28,6 +29,7 @@ import android.view.SurfaceControl import androidx.test.filters.SmallTest import com.android.internal.policy.SystemBarUtils import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE import com.android.window.flags.Flags.FLAG_ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX import com.android.wm.shell.R import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.ShellTestCase Loading @@ -45,6 +47,8 @@ import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock import org.mockito.kotlin.any import org.mockito.kotlin.never import org.mockito.kotlin.verify import org.mockito.kotlin.whenever /** Loading Loading @@ -345,6 +349,38 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() { assertThat(visualIndicator.indicatorBounds).isEqualTo(dropTargetBounds) } @Test @DisableFlags(FLAG_ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX) fun createIndicator_inTransitionFlagDisabled_isAttachedToDisplayArea() { createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FULLSCREEN) verify(taskDisplayAreaOrganizer).attachToDisplayArea(anyInt(), any()) } @Test @EnableFlags(FLAG_ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX) fun createIndicator_fromFreeform_inTransitionFlagEnabled_isAttachedToDisplayArea() { createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FREEFORM) verify(taskDisplayAreaOrganizer).attachToDisplayArea(anyInt(), any()) } @Test @EnableFlags(FLAG_ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX) fun createIndicator_fromFullscreen_inTransitionFlagEnabled_notAttachedToDisplayArea() { createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FULLSCREEN) verify(taskDisplayAreaOrganizer, never()).attachToDisplayArea(anyInt(), any()) } @Test @EnableFlags(FLAG_ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX) fun createIndicator_fromSplit_inTransitionFlagEnabled_notAttachedToDisplayArea() { createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_SPLIT) verify(taskDisplayAreaOrganizer, never()).attachToDisplayArea(anyInt(), any()) } private fun createVisualIndicator(dragStartState: DesktopModeVisualIndicator.DragStartState) { visualIndicator = DesktopModeVisualIndicator( Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java +22 −1 Original line number Diff line number Diff line Loading @@ -103,6 +103,10 @@ public class DesktopModeVisualIndicator { return null; } } private static boolean isDragToDesktopStartState(DragStartState startState) { return startState == FROM_FULLSCREEN || startState == FROM_SPLIT; } } private final VisualIndicatorViewContainer mVisualIndicatorViewContainer; Loading @@ -125,7 +129,12 @@ public class DesktopModeVisualIndicator { @Nullable BubbleDropTargetBoundsProvider bubbleBoundsProvider, SnapEventHandler snapEventHandler) { SurfaceControl.Builder builder = new SurfaceControl.Builder(); if (!DragStartState.isDragToDesktopStartState(dragStartState) || !DesktopModeFlags.ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX.isTrue()) { // In the DragToDesktop transition we attach the indicator to the transition root once // that is available - for all other cases attach the indicator here. taskDisplayAreaOrganizer.attachToDisplayArea(taskInfo.displayId, builder); } mVisualIndicatorViewContainer = new VisualIndicatorViewContainer( DesktopModeFlags.ENABLE_DESKTOP_INDICATOR_IN_SEPARATE_THREAD_BUGFIX.isTrue() ? desktopExecutor : mainExecutor, Loading Loading @@ -159,6 +168,18 @@ public class DesktopModeVisualIndicator { mVisualIndicatorViewContainer.releaseVisualIndicator(); } /** Reparent the visual indicator to {@code newParent}. */ void reparentLeash(SurfaceControl.Transaction t, SurfaceControl newParent) { mVisualIndicatorViewContainer.reparentLeash(t, newParent); } /** Start the fade-in animation. */ void fadeInIndicator() { mVisualIndicatorViewContainer.fadeInIndicator( mDisplayController.getDisplayLayout(mTaskInfo.displayId), mCurrentType, mTaskInfo.displayId); } /** * Based on the coordinates of the current drag event, determine which indicator type we should * display, including no visible indicator. Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +1 −0 Original line number Diff line number Diff line Loading @@ -639,6 +639,7 @@ class DesktopTasksController( dragToDesktopTransitionHandler.startDragToDesktopTransition( taskInfo, dragToDesktopValueAnimator, visualIndicator, ) } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt +29 −2 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.os.SystemProperties import android.os.UserHandle import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CLOSE import android.window.DesktopModeFlags import android.window.TransitionInfo import android.window.TransitionInfo.Change import android.window.TransitionRequestInfo Loading Loading @@ -118,6 +119,7 @@ sealed class DragToDesktopTransitionHandler( fun startDragToDesktopTransition( taskInfo: RunningTaskInfo, dragToDesktopAnimator: MoveToDesktopAnimator, visualIndicator: DesktopModeVisualIndicator?, ) { if (inProgress) { logV("Drag to desktop transition already in progress.") Loading Loading @@ -163,12 +165,14 @@ sealed class DragToDesktopTransitionHandler( dragAnimator = dragToDesktopAnimator, startTransitionToken = startTransitionToken, otherSplitTask = otherTask, visualIndicator = visualIndicator, ) } else { TransitionState.FromFullscreen( draggedTaskId = taskInfo.taskId, dragAnimator = dragToDesktopAnimator, startTransitionToken = startTransitionToken, visualIndicator = visualIndicator, ) } } Loading Loading @@ -457,6 +461,13 @@ sealed class DragToDesktopTransitionHandler( state.surfaceLayers = layers state.startTransitionFinishCb = finishCallback state.startTransitionFinishTransaction = finishTransaction val taskChange = state.draggedTaskChange ?: error("Expected non-null task change.") val taskInfo = taskChange.taskInfo ?: error("Expected non-null task info.") if (DesktopModeFlags.ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX.isTrue) { attachIndicatorToTransitionRoot(state, info, taskInfo, startTransaction) } startTransaction.apply() if (state.cancelState == CancelState.NO_CANCEL) { Loading Loading @@ -485,8 +496,6 @@ sealed class DragToDesktopTransitionHandler( } else { SPLIT_POSITION_BOTTOM_OR_RIGHT } val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null task info.") val wct = WindowContainerTransaction() restoreWindowOrder(wct) state.startTransitionFinishTransaction?.apply() Loading @@ -511,6 +520,21 @@ sealed class DragToDesktopTransitionHandler( return true } private fun attachIndicatorToTransitionRoot( state: TransitionState, info: TransitionInfo, taskInfo: RunningTaskInfo, t: SurfaceControl.Transaction, ) { val transitionRoot = info.getRoot(info.findRootIndex(taskInfo.displayId)) state.visualIndicator?.let { // Attach the indicator to the transition root so that it's removed at the end of the // transition regardless of whether we managed to release the indicator. it.reparentLeash(t, transitionRoot.leash) it.fadeInIndicator() } } /** * Calculates start drag to desktop layers for transition [info]. The leash layer is calculated * based on its change position in the transition, e.g. `appLayer = appLayers - i`, where i is Loading Loading @@ -901,6 +925,7 @@ sealed class DragToDesktopTransitionHandler( abstract var surfaceLayers: DragToDesktopLayers? abstract var cancelState: CancelState abstract var startAborted: Boolean abstract val visualIndicator: DesktopModeVisualIndicator? data class FromFullscreen( override val draggedTaskId: Int, Loading @@ -915,6 +940,7 @@ sealed class DragToDesktopTransitionHandler( override var surfaceLayers: DragToDesktopLayers? = null, override var cancelState: CancelState = CancelState.NO_CANCEL, override var startAborted: Boolean = false, override val visualIndicator: DesktopModeVisualIndicator?, var otherRootChanges: MutableList<Change> = mutableListOf(), ) : TransitionState() Loading @@ -931,6 +957,7 @@ sealed class DragToDesktopTransitionHandler( override var surfaceLayers: DragToDesktopLayers? = null, override var cancelState: CancelState = CancelState.NO_CANCEL, override var startAborted: Boolean = false, override val visualIndicator: DesktopModeVisualIndicator?, var splitRootChange: Change? = null, var otherSplitTask: Int, ) : TransitionState() Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainer.kt +20 −2 Original line number Diff line number Diff line Loading @@ -130,6 +130,12 @@ constructor( } } /** Reparent the indicator to {@code newParent}. */ fun reparentLeash(t: SurfaceControl.Transaction, newParent: SurfaceControl) { val leash = indicatorLeash ?: return t.reparent(leash, newParent) } private fun showIndicator(taskSurface: SurfaceControl, leash: SurfaceControl) { mainExecutor.execute { indicatorLeash = leash Loading Loading @@ -166,7 +172,7 @@ constructor( displayController.getDisplayLayout(taskInfo.displayId) ?: error("Expected to find DisplayLayout for taskId${taskInfo.taskId}.") if (currentType == IndicatorType.NO_INDICATOR) { fadeInIndicator(layout, newType, taskInfo.displayId, snapEventHandler) fadeInIndicatorInternal(layout, newType, taskInfo.displayId, snapEventHandler) } else if (newType == IndicatorType.NO_INDICATOR) { fadeOutIndicator( layout, Loading Loading @@ -194,11 +200,23 @@ constructor( } } /** * Fade indicator in as provided type. * * Animator fades the indicator in while expanding the bounds outwards. */ fun fadeInIndicator(layout: DisplayLayout, type: IndicatorType, displayId: Int) { if (isReleased) return desktopExecutor.execute { fadeInIndicatorInternal(layout, type, displayId, snapEventHandler) } } /** * Fade indicator in as provided type. Animator fades it in while expanding the bounds outwards. */ @VisibleForTesting fun fadeInIndicator( fun fadeInIndicatorInternal( layout: DisplayLayout, type: IndicatorType, displayId: Int, Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt +36 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.animation.AnimatorTestRule import android.app.ActivityManager.RunningTaskInfo import android.graphics.PointF import android.graphics.Rect import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper Loading @@ -28,6 +29,7 @@ import android.view.SurfaceControl import androidx.test.filters.SmallTest import com.android.internal.policy.SystemBarUtils import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE import com.android.window.flags.Flags.FLAG_ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX import com.android.wm.shell.R import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.ShellTestCase Loading @@ -45,6 +47,8 @@ import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock import org.mockito.kotlin.any import org.mockito.kotlin.never import org.mockito.kotlin.verify import org.mockito.kotlin.whenever /** Loading Loading @@ -345,6 +349,38 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() { assertThat(visualIndicator.indicatorBounds).isEqualTo(dropTargetBounds) } @Test @DisableFlags(FLAG_ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX) fun createIndicator_inTransitionFlagDisabled_isAttachedToDisplayArea() { createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FULLSCREEN) verify(taskDisplayAreaOrganizer).attachToDisplayArea(anyInt(), any()) } @Test @EnableFlags(FLAG_ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX) fun createIndicator_fromFreeform_inTransitionFlagEnabled_isAttachedToDisplayArea() { createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FREEFORM) verify(taskDisplayAreaOrganizer).attachToDisplayArea(anyInt(), any()) } @Test @EnableFlags(FLAG_ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX) fun createIndicator_fromFullscreen_inTransitionFlagEnabled_notAttachedToDisplayArea() { createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FULLSCREEN) verify(taskDisplayAreaOrganizer, never()).attachToDisplayArea(anyInt(), any()) } @Test @EnableFlags(FLAG_ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX) fun createIndicator_fromSplit_inTransitionFlagEnabled_notAttachedToDisplayArea() { createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_SPLIT) verify(taskDisplayAreaOrganizer, never()).attachToDisplayArea(anyInt(), any()) } private fun createVisualIndicator(dragStartState: DesktopModeVisualIndicator.DragStartState) { visualIndicator = DesktopModeVisualIndicator( Loading