Loading libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/RestartSizeCompatAppInDesktopMode.kt 0 → 100644 +30 −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.functional import android.platform.test.annotations.Postsubmit import android.platform.test.rule.ScreenRecordRule import com.android.wm.shell.scenarios.RestartAppInDesktopMode import org.junit.runner.RunWith import org.junit.runners.BlockJUnit4ClassRunner /** Functional test of [RestartAppInDesktopMode] for a size-compat app. */ @RunWith(BlockJUnit4ClassRunner::class) @ScreenRecordRule.ScreenRecord @Postsubmit class RestartSizeCompatAppInDesktopMode : RestartAppInDesktopMode(isResizable = false, isLandscapeApp = false) libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MoveToNextDisplay.kt +1 −10 Original line number Diff line number Diff line Loading @@ -69,16 +69,7 @@ abstract class MoveToNextDisplay { val connectedDisplayId = connectedDisplayRule.setupTestDisplay() testApp.enterDesktopMode(wmHelper, device) testApp.moveToNextDisplayViaKeyboard(wmHelper) wmHelper.StateSyncBuilder().apply { add("testApp is on the connected display") { dump -> val display = requireNotNull(dump.wmState.getDisplay(connectedDisplayId)) { "Display $connectedDisplayId not found" } display.containsActivity(testApp) } }.waitForAndVerify() testApp.moveToNextDisplayViaKeyboard(wmHelper, connectedDisplayId) } @After Loading libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/RestartAppInDesktopMode.kt 0 → 100644 +92 −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.scenarios import android.platform.test.annotations.RequiresFlagsEnabled import android.platform.test.flag.junit.DeviceFlagsValueProvider import android.tools.NavBar import android.tools.Rotation import com.android.window.flags.Flags import com.android.wm.shell.Utils import org.junit.After import org.junit.Assume.assumeTrue import org.junit.Before import org.junit.Ignore import org.junit.Rule import org.junit.Test import platform.test.desktop.SimulatedConnectedDisplayTestRule /** Base scenario test for moving an app between displays and manually restarting the app. */ @Ignore("Test Base Class") @RequiresFlagsEnabled( Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, Flags.FLAG_ENABLE_RESTART_MENU_FOR_CONNECTED_DISPLAYS, ) abstract class RestartAppInDesktopMode( isResizable: Boolean = true, isLandscapeApp: Boolean = true, ) : DesktopScenarioCustomAppTestBase(isResizable, isLandscapeApp) { @get:Rule(order = 0) val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() @get:Rule(order = 1) val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, Rotation.ROTATION_0) @get:Rule(order = 2) val connectedDisplayRule = SimulatedConnectedDisplayTestRule() @Before fun setup() { assumeTrue("isTablet", tapl.isTablet) } @Test open fun restartFromAppHandleMenu() { val connectedDisplayId = connectedDisplayRule.setupTestDisplay() testApp.enterDesktopMode(wmHelper, device) testApp.moveToNextDisplayViaKeyboard(wmHelper, connectedDisplayId) waitForAndVerifyDensityConfiguration(displayId = connectedDisplayId, shouldMatch = false) testApp.restartFromAppHandleMenu(wmHelper) waitForAndVerifyDensityConfiguration(displayId = connectedDisplayId, shouldMatch = true) } private fun waitForAndVerifyDensityConfiguration(displayId: Int, shouldMatch: Boolean) { wmHelper .StateSyncBuilder() .add( String.format( "App density %s match display density %s restart", if (shouldMatch) "should" else "should not", if (shouldMatch) "after" else "before", ) ) { dump -> val activityConfig = requireNotNull(dump.wmState.focusedActivity?.fullConfiguration) { "Focused activity not found" } val displayConfig = requireNotNull(dump.wmState.getDisplay(displayId)?.fullConfiguration) { "Display $displayId not found" } shouldMatch == (activityConfig.densityDpi == displayConfig.densityDpi) } .waitForAndVerify() } @After fun teardown() { testApp.exit(wmHelper) } } tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt +28 −1 Original line number Diff line number Diff line Loading @@ -583,10 +583,34 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) : wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() } fun moveToNextDisplayViaKeyboard(wmHelper: WindowManagerStateHelper) { fun restartFromAppHandleMenu(wmHelper: WindowManagerStateHelper) { val openMenuButton = getDesktopAppViewByRes(OPEN_MENU_BUTTON) openMenuButton?.click() wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() val restartHandleMenu = getDesktopAppViewByRes(RESTART_BUTTON) restartHandleMenu?.click() wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() val restartDialogConfirmButton = getDesktopAppViewByRes(RESTART_DIALOG_RESTART_BUTTON) restartDialogConfirmButton?.click() wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() } fun moveToNextDisplayViaKeyboard(wmHelper: WindowManagerStateHelper, expectedDisplayId: Int) { val keyEventHelper = KeyEventHelper(getInstrumentation()) keyEventHelper.press(KEYCODE_D, META_META_ON or META_CTRL_ON) wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() wmHelper.StateSyncBuilder().apply { add("App is on display #$expectedDisplayId") { dump -> val display = requireNotNull(dump.wmState.getDisplay(expectedDisplayId)) { "Display $expectedDisplayId not found" } display.containsActivity(innerHelper) } }.waitForAndVerify() } private fun getDesktopAppViewByRes(viewResId: String): UiObject2? = Loading Loading @@ -678,6 +702,9 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) : const val MAXIMIZE_BUTTON_IN_MENU: String = "maximize_menu_size_toggle_button" const val MINIMIZE_BUTTON_VIEW: String = "minimize_window" const val HEADER_EMPTY_VIEW: String = "caption_handle" const val OPEN_MENU_BUTTON: String = "open_menu_button" const val RESTART_BUTTON: String = "handle_menu_restart_button" const val RESTART_DIALOG_RESTART_BUTTON: String = "letterbox_restart_dialog_restart_button" val caption: BySelector get() = By.res(SYSTEMUI_PACKAGE, CAPTION) // In DesktopMode, window snap can be done with just a single window. In this case, the Loading Loading
libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/RestartSizeCompatAppInDesktopMode.kt 0 → 100644 +30 −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.functional import android.platform.test.annotations.Postsubmit import android.platform.test.rule.ScreenRecordRule import com.android.wm.shell.scenarios.RestartAppInDesktopMode import org.junit.runner.RunWith import org.junit.runners.BlockJUnit4ClassRunner /** Functional test of [RestartAppInDesktopMode] for a size-compat app. */ @RunWith(BlockJUnit4ClassRunner::class) @ScreenRecordRule.ScreenRecord @Postsubmit class RestartSizeCompatAppInDesktopMode : RestartAppInDesktopMode(isResizable = false, isLandscapeApp = false)
libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MoveToNextDisplay.kt +1 −10 Original line number Diff line number Diff line Loading @@ -69,16 +69,7 @@ abstract class MoveToNextDisplay { val connectedDisplayId = connectedDisplayRule.setupTestDisplay() testApp.enterDesktopMode(wmHelper, device) testApp.moveToNextDisplayViaKeyboard(wmHelper) wmHelper.StateSyncBuilder().apply { add("testApp is on the connected display") { dump -> val display = requireNotNull(dump.wmState.getDisplay(connectedDisplayId)) { "Display $connectedDisplayId not found" } display.containsActivity(testApp) } }.waitForAndVerify() testApp.moveToNextDisplayViaKeyboard(wmHelper, connectedDisplayId) } @After Loading
libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/RestartAppInDesktopMode.kt 0 → 100644 +92 −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.scenarios import android.platform.test.annotations.RequiresFlagsEnabled import android.platform.test.flag.junit.DeviceFlagsValueProvider import android.tools.NavBar import android.tools.Rotation import com.android.window.flags.Flags import com.android.wm.shell.Utils import org.junit.After import org.junit.Assume.assumeTrue import org.junit.Before import org.junit.Ignore import org.junit.Rule import org.junit.Test import platform.test.desktop.SimulatedConnectedDisplayTestRule /** Base scenario test for moving an app between displays and manually restarting the app. */ @Ignore("Test Base Class") @RequiresFlagsEnabled( Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, Flags.FLAG_ENABLE_RESTART_MENU_FOR_CONNECTED_DISPLAYS, ) abstract class RestartAppInDesktopMode( isResizable: Boolean = true, isLandscapeApp: Boolean = true, ) : DesktopScenarioCustomAppTestBase(isResizable, isLandscapeApp) { @get:Rule(order = 0) val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() @get:Rule(order = 1) val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, Rotation.ROTATION_0) @get:Rule(order = 2) val connectedDisplayRule = SimulatedConnectedDisplayTestRule() @Before fun setup() { assumeTrue("isTablet", tapl.isTablet) } @Test open fun restartFromAppHandleMenu() { val connectedDisplayId = connectedDisplayRule.setupTestDisplay() testApp.enterDesktopMode(wmHelper, device) testApp.moveToNextDisplayViaKeyboard(wmHelper, connectedDisplayId) waitForAndVerifyDensityConfiguration(displayId = connectedDisplayId, shouldMatch = false) testApp.restartFromAppHandleMenu(wmHelper) waitForAndVerifyDensityConfiguration(displayId = connectedDisplayId, shouldMatch = true) } private fun waitForAndVerifyDensityConfiguration(displayId: Int, shouldMatch: Boolean) { wmHelper .StateSyncBuilder() .add( String.format( "App density %s match display density %s restart", if (shouldMatch) "should" else "should not", if (shouldMatch) "after" else "before", ) ) { dump -> val activityConfig = requireNotNull(dump.wmState.focusedActivity?.fullConfiguration) { "Focused activity not found" } val displayConfig = requireNotNull(dump.wmState.getDisplay(displayId)?.fullConfiguration) { "Display $displayId not found" } shouldMatch == (activityConfig.densityDpi == displayConfig.densityDpi) } .waitForAndVerify() } @After fun teardown() { testApp.exit(wmHelper) } }
tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt +28 −1 Original line number Diff line number Diff line Loading @@ -583,10 +583,34 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) : wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() } fun moveToNextDisplayViaKeyboard(wmHelper: WindowManagerStateHelper) { fun restartFromAppHandleMenu(wmHelper: WindowManagerStateHelper) { val openMenuButton = getDesktopAppViewByRes(OPEN_MENU_BUTTON) openMenuButton?.click() wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() val restartHandleMenu = getDesktopAppViewByRes(RESTART_BUTTON) restartHandleMenu?.click() wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() val restartDialogConfirmButton = getDesktopAppViewByRes(RESTART_DIALOG_RESTART_BUTTON) restartDialogConfirmButton?.click() wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() } fun moveToNextDisplayViaKeyboard(wmHelper: WindowManagerStateHelper, expectedDisplayId: Int) { val keyEventHelper = KeyEventHelper(getInstrumentation()) keyEventHelper.press(KEYCODE_D, META_META_ON or META_CTRL_ON) wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() wmHelper.StateSyncBuilder().apply { add("App is on display #$expectedDisplayId") { dump -> val display = requireNotNull(dump.wmState.getDisplay(expectedDisplayId)) { "Display $expectedDisplayId not found" } display.containsActivity(innerHelper) } }.waitForAndVerify() } private fun getDesktopAppViewByRes(viewResId: String): UiObject2? = Loading Loading @@ -678,6 +702,9 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) : const val MAXIMIZE_BUTTON_IN_MENU: String = "maximize_menu_size_toggle_button" const val MINIMIZE_BUTTON_VIEW: String = "minimize_window" const val HEADER_EMPTY_VIEW: String = "caption_handle" const val OPEN_MENU_BUTTON: String = "open_menu_button" const val RESTART_BUTTON: String = "handle_menu_restart_button" const val RESTART_DIALOG_RESTART_BUTTON: String = "letterbox_restart_dialog_restart_button" val caption: BySelector get() = By.res(SYSTEMUI_PACKAGE, CAPTION) // In DesktopMode, window snap can be done with just a single window. In this case, the Loading