diff options
5 files changed, 328 insertions, 0 deletions
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/OWNERS b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/OWNERS new file mode 100644 index 000000000000..73a5a23909c5 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/OWNERS @@ -0,0 +1,5 @@ +# Android > Android OS & Apps > Framework (Java + Native) > Window Manager > WM Shell > Freeform +# Bug component: 929241 + +uysalorhan@google.com +pragyabajoria@google.com
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/flicker/EnterDesktopWithDragLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/flicker/EnterDesktopWithDragLandscape.kt new file mode 100644 index 000000000000..4c781d36acf6 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/flicker/EnterDesktopWithDragLandscape.kt @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2024 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.flicker.service.desktopmode.flicker + +import android.tools.Rotation +import android.tools.flicker.AssertionInvocationGroup +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.assertors.assertions.AppLayerIsVisibleAlways +import android.tools.flicker.assertors.assertions.AppWindowHasDesktopModeInitialBoundsAtTheEnd +import android.tools.flicker.assertors.assertions.AppWindowOnTopAtEnd +import android.tools.flicker.config.AssertionTemplates +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerConfigEntry +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.config.ScenarioId +import android.tools.flicker.config.desktopmode.Components +import android.tools.flicker.extractors.ITransitionMatcher +import android.tools.flicker.extractors.ShellTransitionScenarioExtractor +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.traces.wm.Transition +import android.tools.traces.wm.TransitionType +import com.android.wm.shell.flicker.service.desktopmode.scenarios.EnterDesktopWithDrag +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(FlickerServiceJUnit4ClassRunner::class) +class EnterDesktopWithDragLandscape : EnterDesktopWithDrag(Rotation.ROTATION_90) { + @ExpectedScenarios(["END_DRAG_TO_DESKTOP"]) @Test override fun enterDesktopWithDrag() = + super.enterDesktopWithDrag() + + companion object { + private val END_DRAG_TO_DESKTOP = FlickerConfigEntry( + scenarioId = ScenarioId("END_DRAG_TO_DESKTOP"), + extractor = ShellTransitionScenarioExtractor( + transitionMatcher = object : ITransitionMatcher { + override fun findAll( + transitions: Collection<Transition> + ): Collection<Transition> { + return transitions.filter { + it.type == TransitionType.DESKTOP_MODE_END_DRAG_TO_DESKTOP} + } + }), + assertions = AssertionTemplates.COMMON_ASSERTIONS + + listOf( + AppLayerIsVisibleAlways(Components.DESKTOP_MODE_APP), + AppWindowOnTopAtEnd(Components.DESKTOP_MODE_APP), + AppWindowHasDesktopModeInitialBoundsAtTheEnd(Components.DESKTOP_MODE_APP) + ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }), + ) + + @JvmStatic + @FlickerConfigProvider + fun flickerConfigProvider(): FlickerConfig = + FlickerConfig() + .use(FlickerServiceConfig.DEFAULT) + .use(END_DRAG_TO_DESKTOP) + } +} diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/flicker/EnterDesktopWithDragPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/flicker/EnterDesktopWithDragPortrait.kt new file mode 100644 index 000000000000..d99d875fb126 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/flicker/EnterDesktopWithDragPortrait.kt @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2024 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.flicker.service.desktopmode.flicker + +import android.tools.Rotation +import android.tools.flicker.AssertionInvocationGroup +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.assertors.assertions.AppLayerIsVisibleAlways +import android.tools.flicker.assertors.assertions.AppWindowHasDesktopModeInitialBoundsAtTheEnd +import android.tools.flicker.assertors.assertions.AppWindowOnTopAtEnd +import android.tools.flicker.config.AssertionTemplates +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerConfigEntry +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.config.ScenarioId +import android.tools.flicker.config.desktopmode.Components +import android.tools.flicker.extractors.ITransitionMatcher +import android.tools.flicker.extractors.ShellTransitionScenarioExtractor +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.traces.wm.Transition +import android.tools.traces.wm.TransitionType +import com.android.wm.shell.flicker.service.desktopmode.scenarios.EnterDesktopWithDrag +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(FlickerServiceJUnit4ClassRunner::class) +class EnterDesktopWithDragPortrait : EnterDesktopWithDrag(Rotation.ROTATION_0) { + @ExpectedScenarios(["END_DRAG_TO_DESKTOP"]) @Test override fun enterDesktopWithDrag() = + super.enterDesktopWithDrag() + + companion object { + private val END_DRAG_TO_DESKTOP = FlickerConfigEntry( + scenarioId = ScenarioId("END_DRAG_TO_DESKTOP"), + extractor = ShellTransitionScenarioExtractor( + transitionMatcher = object : ITransitionMatcher { + override fun findAll( + transitions: Collection<Transition> + ): Collection<Transition> { + return transitions.filter { + it.type == TransitionType.DESKTOP_MODE_END_DRAG_TO_DESKTOP} + } + }), + assertions = AssertionTemplates.COMMON_ASSERTIONS + + listOf( + AppLayerIsVisibleAlways(Components.DESKTOP_MODE_APP), + AppWindowOnTopAtEnd(Components.DESKTOP_MODE_APP), + AppWindowHasDesktopModeInitialBoundsAtTheEnd(Components.DESKTOP_MODE_APP) + ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }), + ) + + @JvmStatic + @FlickerConfigProvider + fun flickerConfigProvider(): FlickerConfig = + FlickerConfig() + .use(FlickerServiceConfig.DEFAULT) + .use(END_DRAG_TO_DESKTOP) + } +} diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/scenarios/EnterDesktopWithDrag.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/scenarios/EnterDesktopWithDrag.kt new file mode 100644 index 000000000000..0403b4f64faf --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/desktopmode/scenarios/EnterDesktopWithDrag.kt @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2024 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.flicker.service.desktopmode.scenarios + +import android.app.Instrumentation +import android.tools.NavBar +import android.tools.Rotation +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.SimpleAppHelper +import com.android.wm.shell.flicker.service.common.Utils +import com.android.wm.shell.flicker.utils.DesktopModeUtils +import org.junit.After +import org.junit.Before +import org.junit.Ignore +import org.junit.Rule +import org.junit.Test + +@Ignore("Base Test Class") +abstract class EnterDesktopWithDrag +@JvmOverloads +constructor(val rotation: Rotation = Rotation.ROTATION_0) { + + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val tapl = LauncherInstrumentation() + private val wmHelper = WindowManagerStateHelper(instrumentation) + private val device = UiDevice.getInstance(instrumentation) + private val testApp = SimpleAppHelper(instrumentation) + + @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation) + + @Before + fun setup() { + tapl.setEnableRotation(true) + tapl.setExpectedRotation(rotation.value) + } + + @Test + open fun enterDesktopWithDrag() { + DesktopModeUtils.enterDesktopWithDrag(wmHelper, device, testApp) + } + + @After + fun teardown() { + testApp.exit(wmHelper) + } +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/DesktopModeUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/DesktopModeUtils.kt new file mode 100644 index 000000000000..345bc5ebb20e --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/DesktopModeUtils.kt @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2024 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.flicker.utils + +import android.tools.device.apphelpers.StandardAppHelper +import android.tools.helpers.SYSTEMUI_PACKAGE +import android.tools.traces.component.IComponentMatcher +import android.tools.traces.parsers.WindowManagerStateHelper +import android.tools.traces.wm.WindowingMode +import androidx.test.uiautomator.By +import androidx.test.uiautomator.BySelector +import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.Until + +/** + * Provides a collection of utility functions for desktop mode testing. + */ +object DesktopModeUtils { + private const val TIMEOUT_MS = 3_000L + private const val CAPTION = "desktop_mode_caption" + private const val CAPTION_HANDLE = "caption_handle" + private const val MAXIMIZE_BUTTON = "maximize_button_view" + + private val captionFullscreen: BySelector + get() = By.res(SYSTEMUI_PACKAGE, CAPTION) + private val captionHandle: BySelector + get() = By.res(SYSTEMUI_PACKAGE, CAPTION_HANDLE) + private val maximizeButton: BySelector + get() = By.res(SYSTEMUI_PACKAGE, MAXIMIZE_BUTTON) + + /** + * Wait for an app moved to desktop to finish its transition. + */ + private fun waitForAppToMoveToDesktop( + wmHelper: WindowManagerStateHelper, + currentApp: IComponentMatcher, + ) { + wmHelper + .StateSyncBuilder() + .withWindowSurfaceAppeared(currentApp) + .withFreeformApp(currentApp) + .withAppTransitionIdle() + .waitForAndVerify() + } + + /** + * Click maximise button on the app header for the given app. + */ + fun maximiseDesktopApp( + wmHelper: WindowManagerStateHelper, + device: UiDevice, + currentApp: StandardAppHelper + ) { + if (wmHelper.getWindow(currentApp)?.windowingMode + != WindowingMode.WINDOWING_MODE_FREEFORM.value) + error("expected a freeform window to maximise but window is not in freefrom mode") + + val maximizeButton = + device.wait(Until.findObject(maximizeButton), TIMEOUT_MS) + ?: error("Unable to find view $maximizeButton\n") + maximizeButton.click() + } + + /** + * Move an app to Desktop by dragging the app handle at the top. + */ + fun enterDesktopWithDrag( + wmHelper: WindowManagerStateHelper, + device: UiDevice, + currentApp: StandardAppHelper, + ) { + currentApp.launchViaIntent(wmHelper) + dragToDesktop(wmHelper, currentApp, device) + waitForAppToMoveToDesktop(wmHelper, currentApp) + } + + private fun dragToDesktop( + wmHelper: WindowManagerStateHelper, + currentApp: StandardAppHelper, + device: UiDevice + ) { + val windowRect = wmHelper.getWindowRegion(currentApp).bounds + val startX = windowRect.centerX() + + // Start dragging a little under the top to prevent dragging the notification shade. + val startY = 10 + + val displayRect = + wmHelper.currentState.wmState.getDefaultDisplay()?.displayRect + ?: throw IllegalStateException("Default display is null") + + // The position we want to drag to + val endY = displayRect.centerY() / 2 + + // drag the window to move to desktop + device.drag(startX, startY, startX, endY, 100) + } +} |