Loading libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/TabTearingDragAndDropTest.kt 0 → 100644 +29 −0 Original line number Original line 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.functional import android.platform.test.annotations.Postsubmit import android.platform.test.rule.ScreenRecordRule import com.android.wm.shell.scenarios.TabTearingDragAndDrop import org.junit.runner.RunWith import org.junit.runners.BlockJUnit4ClassRunner /* Functional test for [TabTearingDragAndDrop]. */ @RunWith(BlockJUnit4ClassRunner::class) @Postsubmit @ScreenRecordRule.ScreenRecord class TabTearingDragAndDropTest : TabTearingDragAndDrop() No newline at end of file libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/TabTearingDragAndDrop.kt 0 → 100644 +84 −0 Original line number Original line 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.scenarios import android.app.Instrumentation import android.tools.NavBar import android.tools.Rotation import android.tools.device.apphelpers.BrowserAppHelper import android.tools.flicker.rules.ChangeDisplayOrientationRule import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation import com.android.server.wm.flicker.helpers.DesktopModeAppHelper import com.android.window.flags.Flags import com.android.wm.shell.Utils import org.junit.After import org.junit.Assume import org.junit.Before import org.junit.Ignore import org.junit.Rule import org.junit.Test @Ignore("Test Base Class") abstract class TabTearingDragAndDrop(val rotation: Rotation = Rotation.ROTATION_0) : TestScenarioBase() { private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() private val tapl = LauncherInstrumentation() private val wmHelper = WindowManagerStateHelper(instrumentation) private val device = UiDevice.getInstance(instrumentation) private val browserAppHelper = BrowserAppHelper(instrumentation) private val browserDesktopAppHelper = DesktopModeAppHelper(browserAppHelper) @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation) @Before fun setup() { Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) tapl.apply { setEnableRotation(true) setExpectedRotation(rotation.value) enableTransientTaskbar(false) } ChangeDisplayOrientationRule.setRotation(rotation) browserDesktopAppHelper.enterDesktopMode(wmHelper, device) } @Test open fun tearTab() { browserAppHelper.openThreeDotsMenu() browserAppHelper.clickNewTabInMenu() browserDesktopAppHelper.dragWindowTopLeftCorner( device, wmHelper, DesktopModeAppHelper.WindowDraggingDirection.CENTER ) browserAppHelper.performTabTearing( wmHelper, BrowserAppHelper.Companion.TabDraggingDirection.TOP_LEFT ) wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() } @After fun teardown() { browserDesktopAppHelper.exit(wmHelper) } } No newline at end of file tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt +49 −0 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.wm.flicker.helpers import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.content.Context import android.content.Context import android.graphics.Insets import android.graphics.Insets import android.graphics.Point import android.graphics.Rect import android.graphics.Rect import android.graphics.Region import android.graphics.Region import android.os.SystemClock import android.os.SystemClock Loading Loading @@ -417,6 +418,50 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) : .waitForAndVerify() .waitForAndVerify() } } /** * Simulates dragging the top-left corner of the current window to the center of the device * screen. * * This function calculates a starting point slightly offset from the actual top-left corner (60 * pixels down and right to prevent app resizing) and drags it to the center of the default * display. * * @param device The UiDevice instance used to perform the drag interaction on the device. * @param wmHelper A helper class instance used to retrieve window and display dimension * information. * @param direction A direction where the window should be dragged to. * @throws IllegalStateException if the default display information cannot be obtained from the * wmHelper. */ fun dragWindowTopLeftCorner( device: UiDevice, wmHelper: WindowManagerStateHelper, direction: WindowDraggingDirection = WindowDraggingDirection.CENTER, ) { val windowBounds = wmHelper.getWindowRegion(this).bounds val displayBounds = getDisplayRect(wmHelper) // We take start dragging point with some offset to use app moving instead of resizing. val startDraggingPoint = Point(/* x= */ windowBounds.left + 60, /* y= */ windowBounds.top + 60) val endDraggingPoint = when (direction) { WindowDraggingDirection.CENTER -> Point(/* x= */ displayBounds.centerX(), /* y= */ displayBounds.centerY()) } device.drag( startDraggingPoint.x, startDraggingPoint.y, endDraggingPoint.x, endDraggingPoint.y, /* steps= */ 100, ) wmHelper .StateSyncBuilder() .withAppTransitionIdle() .waitForAndVerify() } /** Drag a window to a snap resize region, found at the left and right edges of the screen. */ /** Drag a window to a snap resize region, found at the left and right edges of the screen. */ fun dragToSnapResizeRegion( fun dragToSnapResizeRegion( wmHelper: WindowManagerStateHelper, wmHelper: WindowManagerStateHelper, Loading Loading @@ -606,6 +651,10 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) : MAXIMIZE_BUTTON_IN_MENU MAXIMIZE_BUTTON_IN_MENU } } enum class WindowDraggingDirection { CENTER } private companion object { private companion object { val TIMEOUT: Duration = Duration.ofSeconds(3) val TIMEOUT: Duration = Duration.ofSeconds(3) const val SNAP_RESIZE_DRAG_INSET: Int = 5 // inset to avoid dragging to display edge const val SNAP_RESIZE_DRAG_INSET: Int = 5 // inset to avoid dragging to display edge Loading Loading
libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/TabTearingDragAndDropTest.kt 0 → 100644 +29 −0 Original line number Original line 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.functional import android.platform.test.annotations.Postsubmit import android.platform.test.rule.ScreenRecordRule import com.android.wm.shell.scenarios.TabTearingDragAndDrop import org.junit.runner.RunWith import org.junit.runners.BlockJUnit4ClassRunner /* Functional test for [TabTearingDragAndDrop]. */ @RunWith(BlockJUnit4ClassRunner::class) @Postsubmit @ScreenRecordRule.ScreenRecord class TabTearingDragAndDropTest : TabTearingDragAndDrop() No newline at end of file
libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/TabTearingDragAndDrop.kt 0 → 100644 +84 −0 Original line number Original line 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.scenarios import android.app.Instrumentation import android.tools.NavBar import android.tools.Rotation import android.tools.device.apphelpers.BrowserAppHelper import android.tools.flicker.rules.ChangeDisplayOrientationRule import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation import com.android.server.wm.flicker.helpers.DesktopModeAppHelper import com.android.window.flags.Flags import com.android.wm.shell.Utils import org.junit.After import org.junit.Assume import org.junit.Before import org.junit.Ignore import org.junit.Rule import org.junit.Test @Ignore("Test Base Class") abstract class TabTearingDragAndDrop(val rotation: Rotation = Rotation.ROTATION_0) : TestScenarioBase() { private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() private val tapl = LauncherInstrumentation() private val wmHelper = WindowManagerStateHelper(instrumentation) private val device = UiDevice.getInstance(instrumentation) private val browserAppHelper = BrowserAppHelper(instrumentation) private val browserDesktopAppHelper = DesktopModeAppHelper(browserAppHelper) @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation) @Before fun setup() { Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) tapl.apply { setEnableRotation(true) setExpectedRotation(rotation.value) enableTransientTaskbar(false) } ChangeDisplayOrientationRule.setRotation(rotation) browserDesktopAppHelper.enterDesktopMode(wmHelper, device) } @Test open fun tearTab() { browserAppHelper.openThreeDotsMenu() browserAppHelper.clickNewTabInMenu() browserDesktopAppHelper.dragWindowTopLeftCorner( device, wmHelper, DesktopModeAppHelper.WindowDraggingDirection.CENTER ) browserAppHelper.performTabTearing( wmHelper, BrowserAppHelper.Companion.TabDraggingDirection.TOP_LEFT ) wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() } @After fun teardown() { browserDesktopAppHelper.exit(wmHelper) } } No newline at end of file
tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt +49 −0 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.wm.flicker.helpers import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.content.Context import android.content.Context import android.graphics.Insets import android.graphics.Insets import android.graphics.Point import android.graphics.Rect import android.graphics.Rect import android.graphics.Region import android.graphics.Region import android.os.SystemClock import android.os.SystemClock Loading Loading @@ -417,6 +418,50 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) : .waitForAndVerify() .waitForAndVerify() } } /** * Simulates dragging the top-left corner of the current window to the center of the device * screen. * * This function calculates a starting point slightly offset from the actual top-left corner (60 * pixels down and right to prevent app resizing) and drags it to the center of the default * display. * * @param device The UiDevice instance used to perform the drag interaction on the device. * @param wmHelper A helper class instance used to retrieve window and display dimension * information. * @param direction A direction where the window should be dragged to. * @throws IllegalStateException if the default display information cannot be obtained from the * wmHelper. */ fun dragWindowTopLeftCorner( device: UiDevice, wmHelper: WindowManagerStateHelper, direction: WindowDraggingDirection = WindowDraggingDirection.CENTER, ) { val windowBounds = wmHelper.getWindowRegion(this).bounds val displayBounds = getDisplayRect(wmHelper) // We take start dragging point with some offset to use app moving instead of resizing. val startDraggingPoint = Point(/* x= */ windowBounds.left + 60, /* y= */ windowBounds.top + 60) val endDraggingPoint = when (direction) { WindowDraggingDirection.CENTER -> Point(/* x= */ displayBounds.centerX(), /* y= */ displayBounds.centerY()) } device.drag( startDraggingPoint.x, startDraggingPoint.y, endDraggingPoint.x, endDraggingPoint.y, /* steps= */ 100, ) wmHelper .StateSyncBuilder() .withAppTransitionIdle() .waitForAndVerify() } /** Drag a window to a snap resize region, found at the left and right edges of the screen. */ /** Drag a window to a snap resize region, found at the left and right edges of the screen. */ fun dragToSnapResizeRegion( fun dragToSnapResizeRegion( wmHelper: WindowManagerStateHelper, wmHelper: WindowManagerStateHelper, Loading Loading @@ -606,6 +651,10 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) : MAXIMIZE_BUTTON_IN_MENU MAXIMIZE_BUTTON_IN_MENU } } enum class WindowDraggingDirection { CENTER } private companion object { private companion object { val TIMEOUT: Duration = Duration.ofSeconds(3) val TIMEOUT: Duration = Duration.ofSeconds(3) const val SNAP_RESIZE_DRAG_INSET: Int = 5 // inset to avoid dragging to display edge const val SNAP_RESIZE_DRAG_INSET: Int = 5 // inset to avoid dragging to display edge Loading