Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +12 −2 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.os.Handler; import android.os.UserManager; import android.view.Choreographer; import android.view.IWindowManager; import android.view.SurfaceControl; import android.view.WindowManager; import android.window.DesktopModeFlags; Loading Loading @@ -93,6 +94,7 @@ import com.android.wm.shell.desktopmode.DesktopModeDragAndDropTransitionHandler; import com.android.wm.shell.desktopmode.DesktopModeEventLogger; import com.android.wm.shell.desktopmode.DesktopModeKeyGestureHandler; import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver; import com.android.wm.shell.desktopmode.DesktopModeMoveToDisplayTransitionHandler; import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger; import com.android.wm.shell.desktopmode.DesktopTaskChangeListener; import com.android.wm.shell.desktopmode.DesktopTasksController; Loading Loading @@ -772,7 +774,8 @@ public abstract class WMShellModule { DesksTransitionObserver desksTransitionObserver, UserProfileContexts userProfileContexts, DesktopModeCompatPolicy desktopModeCompatPolicy, DragToDisplayTransitionHandler dragToDisplayTransitionHandler) { DragToDisplayTransitionHandler dragToDisplayTransitionHandler, DesktopModeMoveToDisplayTransitionHandler moveToDisplayTransitionHandler) { return new DesktopTasksController( context, shellInit, Loading Loading @@ -812,7 +815,8 @@ public abstract class WMShellModule { desksTransitionObserver, userProfileContexts, desktopModeCompatPolicy, dragToDisplayTransitionHandler); dragToDisplayTransitionHandler, moveToDisplayTransitionHandler); } @WMSingleton Loading Loading @@ -948,6 +952,12 @@ public abstract class WMShellModule { return new DragToDisplayTransitionHandler(); } @WMSingleton @Provides static DesktopModeMoveToDisplayTransitionHandler provideMoveToDisplayTransitionHandler() { return new DesktopModeMoveToDisplayTransitionHandler(new SurfaceControl.Transaction()); } @WMSingleton @Provides static Optional<DesktopModeKeyGestureHandler> provideDesktopModeKeyGestureHandler( Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeMoveToDisplayTransitionHandler.kt 0 → 100644 +96 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.desktopmode import android.animation.Animator import android.animation.ValueAnimator import android.os.IBinder import android.view.Choreographer import android.view.SurfaceControl import android.window.TransitionInfo import android.window.TransitionRequestInfo import android.window.WindowContainerTransaction import com.android.wm.shell.shared.animation.Interpolators import com.android.wm.shell.transition.Transitions import kotlin.time.Duration.Companion.milliseconds /** * Transition handler for moving a window to a different display. */ class DesktopModeMoveToDisplayTransitionHandler( private val animationTransaction: SurfaceControl.Transaction ) : Transitions.TransitionHandler { override fun handleRequest( transition: IBinder, request: TransitionRequestInfo, ): WindowContainerTransaction? = null override fun startAnimation( transition: IBinder, info: TransitionInfo, startTransaction: SurfaceControl.Transaction, finishTransaction: SurfaceControl.Transaction, finishCallback: Transitions.TransitionFinishCallback, ): Boolean { val change = info.changes.find { it.startDisplayId != it.endDisplayId } ?: return false ValueAnimator.ofFloat(0f, 1f) .apply { duration = ANIM_DURATION.inWholeMilliseconds interpolator = Interpolators.LINEAR addUpdateListener { animation -> animationTransaction .setAlpha(change.leash, animation.animatedValue as Float) .setFrameTimeline(Choreographer.getInstance().vsyncId) .apply() } addListener( object : Animator.AnimatorListener { override fun onAnimationStart(animation: Animator) { val endBounds = change.endAbsBounds startTransaction .setPosition( change.leash, endBounds.left.toFloat(), endBounds.top.toFloat(), ) .setWindowCrop(change.leash, endBounds.width(), endBounds.height()) .apply() } override fun onAnimationEnd(animation: Animator) { finishTransaction.apply() finishCallback.onTransitionFinished(null) } override fun onAnimationCancel(animation: Animator) { finishTransaction.apply() finishCallback.onTransitionFinished(null) } override fun onAnimationRepeat(animation: Animator) = Unit } ) } .start() return true } private companion object { val ANIM_DURATION = 100.milliseconds } } libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +5 −2 Original line number Diff line number Diff line Loading @@ -209,6 +209,7 @@ class DesktopTasksController( private val userProfileContexts: UserProfileContexts, private val desktopModeCompatPolicy: DesktopModeCompatPolicy, private val dragToDisplayTransitionHandler: DragToDisplayTransitionHandler, private val moveToDisplayTransitionHandler: DesktopModeMoveToDisplayTransitionHandler, ) : RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler, Loading Loading @@ -1202,7 +1203,8 @@ class DesktopTasksController( } else { null } val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null) val transition = transitions.startTransition(TRANSIT_CHANGE, wct, moveToDisplayTransitionHandler) deactivationRunnable?.invoke(transition) return } Loading Loading @@ -1261,7 +1263,8 @@ class DesktopTasksController( } else { null } val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null) val transition = transitions.startTransition(TRANSIT_CHANGE, wct, moveToDisplayTransitionHandler) deactivationRunnable?.invoke(transition) activationRunnable?.invoke(transition) } Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeMoveToDisplayTransitionHandlerTest.kt 0 → 100644 +87 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.desktopmode import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.view.WindowManager import android.window.TransitionInfo import androidx.test.filters.SmallTest import com.android.wm.shell.ShellTestCase import com.android.wm.shell.util.StubTransaction import org.junit.Assert.assertFalse import org.junit.Assert.assertNull import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.mock @SmallTest @RunWithLooper @RunWith(AndroidTestingRunner::class) class DesktopModeMoveToDisplayTransitionHandlerTest : ShellTestCase() { private lateinit var handler: DesktopModeMoveToDisplayTransitionHandler @Before fun setUp() { handler = DesktopModeMoveToDisplayTransitionHandler(StubTransaction()) } @Test fun handleRequest_returnsNull() { assertNull(handler.handleRequest(mock(), mock())) } @Test fun startAnimation_changeWithinDisplay_returnsFalse() { val animates = handler.startAnimation( transition = mock(), info = TransitionInfo(WindowManager.TRANSIT_CHANGE, /* flags= */ 0).apply { addChange( TransitionInfo.Change(mock(), mock()).apply { setDisplayId(1, 1) } ) }, startTransaction = StubTransaction(), finishTransaction = StubTransaction(), finishCallback = mock(), ) assertFalse("Should not animate open transition", animates) } @Test fun startAnimation_changeMoveToDisplay_returnsTrue() { val animates = handler.startAnimation( transition = mock(), info = TransitionInfo(WindowManager.TRANSIT_CHANGE, /* flags= */ 0).apply { addChange( TransitionInfo.Change(mock(), mock()).apply { setDisplayId(1, 2) } ) }, startTransaction = StubTransaction(), finishTransaction = StubTransaction(), finishCallback = mock(), ) assertTrue("Should animate display change transition", animates) } } libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +60 −18 Original line number Diff line number Diff line Loading @@ -263,6 +263,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Mock private lateinit var packageManager: PackageManager @Mock private lateinit var mockDisplayContext: Context @Mock private lateinit var dragToDisplayTransitionHandler: DragToDisplayTransitionHandler @Mock private lateinit var moveToDisplayTransitionHandler: DesktopModeMoveToDisplayTransitionHandler private lateinit var controller: DesktopTasksController private lateinit var shellInit: ShellInit Loading Loading @@ -445,6 +447,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() userProfileContexts, desktopModeCompatPolicy, dragToDisplayTransitionHandler, moveToDisplayTransitionHandler, ) @After Loading Loading @@ -2521,7 +2524,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() whenever(rootTaskDisplayAreaOrganizer.displayIds).thenReturn(intArrayOf(DEFAULT_DISPLAY)) val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY) controller.moveToNextDisplay(task.taskId) verifyWCTNotExecuted() verify(transitions, never()).startTransition(anyInt(), any(), anyOrNull()) } @Test Loading @@ -2539,9 +2542,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.moveToNextDisplay(task.taskId) val taskChange = getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find { it.container == task.token.asBinder() && it.isReparent } getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) .hierarchyOps .find { it.container == task.token.asBinder() && it.isReparent } assertNotNull(taskChange) assertThat(taskChange.newParent).isEqualTo(secondDisplayArea.token.asBinder()) assertThat(taskChange.toTop).isTrue() Loading @@ -2562,9 +2568,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.moveToNextDisplay(task.taskId) val taskChange = getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find { it.container == task.token.asBinder() && it.isReparent } getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) .hierarchyOps .find { it.container == task.token.asBinder() && it.isReparent } assertNotNull(taskChange) assertThat(taskChange.newParent).isEqualTo(defaultDisplayArea.token.asBinder()) assertThat(taskChange.toTop).isTrue() Loading @@ -2589,7 +2598,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.moveToNextDisplay(task.taskId) with(getLatestWct(type = TRANSIT_CHANGE)) { with( getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) ) { val wallpaperChange = hierarchyOps.find { op -> op.container == wallpaperToken.asBinder() } assertNotNull(wallpaperChange) Loading @@ -2615,9 +2629,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.moveToNextDisplay(task.taskId) val wallpaperChange = getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find { op -> op.container == wallpaperToken.asBinder() } getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) .hierarchyOps .find { op -> op.container == wallpaperToken.asBinder() } assertNotNull(wallpaperChange) assertThat(wallpaperChange.type).isEqualTo(HIERARCHY_OP_TYPE_REMOVE_TASK) } Loading Loading @@ -2649,7 +2666,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.moveToNextDisplay(task.taskId) val taskChange = getLatestWct(type = TRANSIT_CHANGE).changes[task.token.asBinder()] val taskChange = getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) .changes[task.token.asBinder()] assertNotNull(taskChange) // To preserve DP size, pixel size is changed to 320x240. The ratio of the left margin // to the right margin and the ratio of the top margin to bottom margin are also Loading Loading @@ -2686,7 +2708,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.moveToNextDisplay(task.taskId) val taskChange = getLatestWct(type = TRANSIT_CHANGE).changes[task.token.asBinder()] val taskChange = getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) .changes[task.token.asBinder()] assertNotNull(taskChange) assertThat(taskChange.configuration.windowConfiguration.bounds) .isEqualTo(Rect(960, 480, 1280, 720)) Loading Loading @@ -2717,7 +2744,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.moveToNextDisplay(task.taskId) val taskChange = getLatestWct(type = TRANSIT_CHANGE).changes[task.token.asBinder()] val taskChange = getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) .changes[task.token.asBinder()] assertNotNull(taskChange) // DP size is preserved. The window is centered in the destination display. assertThat(taskChange.configuration.windowConfiguration.bounds) Loading Loading @@ -2755,7 +2787,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.moveToNextDisplay(task.taskId) val taskChange = getLatestWct(type = TRANSIT_CHANGE).changes[task.token.asBinder()] val taskChange = getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) .changes[task.token.asBinder()] assertNotNull(taskChange) assertThat(taskChange.configuration.windowConfiguration.bounds.left).isAtLeast(0) assertThat(taskChange.configuration.windowConfiguration.bounds.top).isAtLeast(0) Loading @@ -2782,7 +2819,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.moveToNextDisplay(task.taskId) val taskChange = getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find { getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) .hierarchyOps .find { it.container == task.token.asBinder() && it.type == HIERARCHY_OP_TYPE_REORDER } assertNotNull(taskChange) Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +12 −2 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.os.Handler; import android.os.UserManager; import android.view.Choreographer; import android.view.IWindowManager; import android.view.SurfaceControl; import android.view.WindowManager; import android.window.DesktopModeFlags; Loading Loading @@ -93,6 +94,7 @@ import com.android.wm.shell.desktopmode.DesktopModeDragAndDropTransitionHandler; import com.android.wm.shell.desktopmode.DesktopModeEventLogger; import com.android.wm.shell.desktopmode.DesktopModeKeyGestureHandler; import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver; import com.android.wm.shell.desktopmode.DesktopModeMoveToDisplayTransitionHandler; import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger; import com.android.wm.shell.desktopmode.DesktopTaskChangeListener; import com.android.wm.shell.desktopmode.DesktopTasksController; Loading Loading @@ -772,7 +774,8 @@ public abstract class WMShellModule { DesksTransitionObserver desksTransitionObserver, UserProfileContexts userProfileContexts, DesktopModeCompatPolicy desktopModeCompatPolicy, DragToDisplayTransitionHandler dragToDisplayTransitionHandler) { DragToDisplayTransitionHandler dragToDisplayTransitionHandler, DesktopModeMoveToDisplayTransitionHandler moveToDisplayTransitionHandler) { return new DesktopTasksController( context, shellInit, Loading Loading @@ -812,7 +815,8 @@ public abstract class WMShellModule { desksTransitionObserver, userProfileContexts, desktopModeCompatPolicy, dragToDisplayTransitionHandler); dragToDisplayTransitionHandler, moveToDisplayTransitionHandler); } @WMSingleton Loading Loading @@ -948,6 +952,12 @@ public abstract class WMShellModule { return new DragToDisplayTransitionHandler(); } @WMSingleton @Provides static DesktopModeMoveToDisplayTransitionHandler provideMoveToDisplayTransitionHandler() { return new DesktopModeMoveToDisplayTransitionHandler(new SurfaceControl.Transaction()); } @WMSingleton @Provides static Optional<DesktopModeKeyGestureHandler> provideDesktopModeKeyGestureHandler( Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeMoveToDisplayTransitionHandler.kt 0 → 100644 +96 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.desktopmode import android.animation.Animator import android.animation.ValueAnimator import android.os.IBinder import android.view.Choreographer import android.view.SurfaceControl import android.window.TransitionInfo import android.window.TransitionRequestInfo import android.window.WindowContainerTransaction import com.android.wm.shell.shared.animation.Interpolators import com.android.wm.shell.transition.Transitions import kotlin.time.Duration.Companion.milliseconds /** * Transition handler for moving a window to a different display. */ class DesktopModeMoveToDisplayTransitionHandler( private val animationTransaction: SurfaceControl.Transaction ) : Transitions.TransitionHandler { override fun handleRequest( transition: IBinder, request: TransitionRequestInfo, ): WindowContainerTransaction? = null override fun startAnimation( transition: IBinder, info: TransitionInfo, startTransaction: SurfaceControl.Transaction, finishTransaction: SurfaceControl.Transaction, finishCallback: Transitions.TransitionFinishCallback, ): Boolean { val change = info.changes.find { it.startDisplayId != it.endDisplayId } ?: return false ValueAnimator.ofFloat(0f, 1f) .apply { duration = ANIM_DURATION.inWholeMilliseconds interpolator = Interpolators.LINEAR addUpdateListener { animation -> animationTransaction .setAlpha(change.leash, animation.animatedValue as Float) .setFrameTimeline(Choreographer.getInstance().vsyncId) .apply() } addListener( object : Animator.AnimatorListener { override fun onAnimationStart(animation: Animator) { val endBounds = change.endAbsBounds startTransaction .setPosition( change.leash, endBounds.left.toFloat(), endBounds.top.toFloat(), ) .setWindowCrop(change.leash, endBounds.width(), endBounds.height()) .apply() } override fun onAnimationEnd(animation: Animator) { finishTransaction.apply() finishCallback.onTransitionFinished(null) } override fun onAnimationCancel(animation: Animator) { finishTransaction.apply() finishCallback.onTransitionFinished(null) } override fun onAnimationRepeat(animation: Animator) = Unit } ) } .start() return true } private companion object { val ANIM_DURATION = 100.milliseconds } }
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +5 −2 Original line number Diff line number Diff line Loading @@ -209,6 +209,7 @@ class DesktopTasksController( private val userProfileContexts: UserProfileContexts, private val desktopModeCompatPolicy: DesktopModeCompatPolicy, private val dragToDisplayTransitionHandler: DragToDisplayTransitionHandler, private val moveToDisplayTransitionHandler: DesktopModeMoveToDisplayTransitionHandler, ) : RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler, Loading Loading @@ -1202,7 +1203,8 @@ class DesktopTasksController( } else { null } val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null) val transition = transitions.startTransition(TRANSIT_CHANGE, wct, moveToDisplayTransitionHandler) deactivationRunnable?.invoke(transition) return } Loading Loading @@ -1261,7 +1263,8 @@ class DesktopTasksController( } else { null } val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null) val transition = transitions.startTransition(TRANSIT_CHANGE, wct, moveToDisplayTransitionHandler) deactivationRunnable?.invoke(transition) activationRunnable?.invoke(transition) } Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeMoveToDisplayTransitionHandlerTest.kt 0 → 100644 +87 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.desktopmode import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.view.WindowManager import android.window.TransitionInfo import androidx.test.filters.SmallTest import com.android.wm.shell.ShellTestCase import com.android.wm.shell.util.StubTransaction import org.junit.Assert.assertFalse import org.junit.Assert.assertNull import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.mock @SmallTest @RunWithLooper @RunWith(AndroidTestingRunner::class) class DesktopModeMoveToDisplayTransitionHandlerTest : ShellTestCase() { private lateinit var handler: DesktopModeMoveToDisplayTransitionHandler @Before fun setUp() { handler = DesktopModeMoveToDisplayTransitionHandler(StubTransaction()) } @Test fun handleRequest_returnsNull() { assertNull(handler.handleRequest(mock(), mock())) } @Test fun startAnimation_changeWithinDisplay_returnsFalse() { val animates = handler.startAnimation( transition = mock(), info = TransitionInfo(WindowManager.TRANSIT_CHANGE, /* flags= */ 0).apply { addChange( TransitionInfo.Change(mock(), mock()).apply { setDisplayId(1, 1) } ) }, startTransaction = StubTransaction(), finishTransaction = StubTransaction(), finishCallback = mock(), ) assertFalse("Should not animate open transition", animates) } @Test fun startAnimation_changeMoveToDisplay_returnsTrue() { val animates = handler.startAnimation( transition = mock(), info = TransitionInfo(WindowManager.TRANSIT_CHANGE, /* flags= */ 0).apply { addChange( TransitionInfo.Change(mock(), mock()).apply { setDisplayId(1, 2) } ) }, startTransaction = StubTransaction(), finishTransaction = StubTransaction(), finishCallback = mock(), ) assertTrue("Should animate display change transition", animates) } }
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +60 −18 Original line number Diff line number Diff line Loading @@ -263,6 +263,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Mock private lateinit var packageManager: PackageManager @Mock private lateinit var mockDisplayContext: Context @Mock private lateinit var dragToDisplayTransitionHandler: DragToDisplayTransitionHandler @Mock private lateinit var moveToDisplayTransitionHandler: DesktopModeMoveToDisplayTransitionHandler private lateinit var controller: DesktopTasksController private lateinit var shellInit: ShellInit Loading Loading @@ -445,6 +447,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() userProfileContexts, desktopModeCompatPolicy, dragToDisplayTransitionHandler, moveToDisplayTransitionHandler, ) @After Loading Loading @@ -2521,7 +2524,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() whenever(rootTaskDisplayAreaOrganizer.displayIds).thenReturn(intArrayOf(DEFAULT_DISPLAY)) val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY) controller.moveToNextDisplay(task.taskId) verifyWCTNotExecuted() verify(transitions, never()).startTransition(anyInt(), any(), anyOrNull()) } @Test Loading @@ -2539,9 +2542,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.moveToNextDisplay(task.taskId) val taskChange = getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find { it.container == task.token.asBinder() && it.isReparent } getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) .hierarchyOps .find { it.container == task.token.asBinder() && it.isReparent } assertNotNull(taskChange) assertThat(taskChange.newParent).isEqualTo(secondDisplayArea.token.asBinder()) assertThat(taskChange.toTop).isTrue() Loading @@ -2562,9 +2568,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.moveToNextDisplay(task.taskId) val taskChange = getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find { it.container == task.token.asBinder() && it.isReparent } getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) .hierarchyOps .find { it.container == task.token.asBinder() && it.isReparent } assertNotNull(taskChange) assertThat(taskChange.newParent).isEqualTo(defaultDisplayArea.token.asBinder()) assertThat(taskChange.toTop).isTrue() Loading @@ -2589,7 +2598,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.moveToNextDisplay(task.taskId) with(getLatestWct(type = TRANSIT_CHANGE)) { with( getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) ) { val wallpaperChange = hierarchyOps.find { op -> op.container == wallpaperToken.asBinder() } assertNotNull(wallpaperChange) Loading @@ -2615,9 +2629,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.moveToNextDisplay(task.taskId) val wallpaperChange = getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find { op -> op.container == wallpaperToken.asBinder() } getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) .hierarchyOps .find { op -> op.container == wallpaperToken.asBinder() } assertNotNull(wallpaperChange) assertThat(wallpaperChange.type).isEqualTo(HIERARCHY_OP_TYPE_REMOVE_TASK) } Loading Loading @@ -2649,7 +2666,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.moveToNextDisplay(task.taskId) val taskChange = getLatestWct(type = TRANSIT_CHANGE).changes[task.token.asBinder()] val taskChange = getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) .changes[task.token.asBinder()] assertNotNull(taskChange) // To preserve DP size, pixel size is changed to 320x240. The ratio of the left margin // to the right margin and the ratio of the top margin to bottom margin are also Loading Loading @@ -2686,7 +2708,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.moveToNextDisplay(task.taskId) val taskChange = getLatestWct(type = TRANSIT_CHANGE).changes[task.token.asBinder()] val taskChange = getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) .changes[task.token.asBinder()] assertNotNull(taskChange) assertThat(taskChange.configuration.windowConfiguration.bounds) .isEqualTo(Rect(960, 480, 1280, 720)) Loading Loading @@ -2717,7 +2744,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.moveToNextDisplay(task.taskId) val taskChange = getLatestWct(type = TRANSIT_CHANGE).changes[task.token.asBinder()] val taskChange = getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) .changes[task.token.asBinder()] assertNotNull(taskChange) // DP size is preserved. The window is centered in the destination display. assertThat(taskChange.configuration.windowConfiguration.bounds) Loading Loading @@ -2755,7 +2787,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.moveToNextDisplay(task.taskId) val taskChange = getLatestWct(type = TRANSIT_CHANGE).changes[task.token.asBinder()] val taskChange = getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) .changes[task.token.asBinder()] assertNotNull(taskChange) assertThat(taskChange.configuration.windowConfiguration.bounds.left).isAtLeast(0) assertThat(taskChange.configuration.windowConfiguration.bounds.top).isAtLeast(0) Loading @@ -2782,7 +2819,12 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.moveToNextDisplay(task.taskId) val taskChange = getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find { getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) .hierarchyOps .find { it.container == task.token.asBinder() && it.type == HIERARCHY_OP_TYPE_REORDER } assertNotNull(taskChange) Loading