Loading libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt +1 −1 Original line number Diff line number Diff line Loading @@ -50,7 +50,7 @@ abstract class BaseAppCompat(flicker: LegacyFlickerTest) : BaseTest(flicker) { } @Before fun before() { fun setUp() { Assume.assumeTrue(tapl.isTablet && letterboxRule.isIgnoreOrientationRequest) } Loading libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt 0 → 100644 +199 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.appcompat import android.os.Build import android.tools.common.datatypes.Rect import android.platform.test.annotations.Postsubmit import android.system.helpers.CommandsHelper import android.tools.common.NavBar import android.tools.common.Rotation import android.tools.common.flicker.assertions.FlickerTest import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.LegacyFlickerTest import android.tools.device.flicker.legacy.LegacyFlickerTestFactory import android.tools.device.helpers.FIND_TIMEOUT import android.tools.device.traces.parsers.toFlickerComponent import androidx.test.uiautomator.By import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.Until import com.android.server.wm.flicker.helpers.LetterboxAppHelper import com.android.server.wm.flicker.testapp.ActivityOptions import org.junit.Assume import org.junit.Before import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized /** * Test rotating an immersive app in fullscreen. * * To run this test: `atest WMShellFlickerTestsOther:RotateImmersiveAppInFullscreenTest` * * Actions: * ``` * Rotate the device by 90 degrees to trigger a rotation through sensors * Verify that the button exists * ``` * * Notes: * ``` * Some default assertions that are inherited from * the `BaseTest` are ignored due to the nature of the immersive apps. * * This test only works with Cuttlefish devices. * ``` */ @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) class RotateImmersiveAppInFullscreenTest(flicker: LegacyFlickerTest) : BaseAppCompat(flicker) { private val immersiveApp = LetterboxAppHelper(instrumentation, launcherName = ActivityOptions.PortraitImmersiveActivity.LABEL, component = ActivityOptions.PortraitImmersiveActivity.COMPONENT.toFlickerComponent()) private val cmdHelper: CommandsHelper = CommandsHelper.getInstance(instrumentation) private val execAdb: (String) -> String = { cmd -> cmdHelper.executeShellCommand(cmd) } protected val uiDevice: UiDevice = UiDevice.getInstance(instrumentation) private val isCuttlefishDevice: Boolean = Build.MODEL.contains("Cuttlefish") /** {@inheritDoc} */ override val transition: FlickerBuilder.() -> Unit get() = { setup { setStartRotation() immersiveApp.launchViaIntent(wmHelper) startDisplayBounds = wmHelper.currentState.layerState.physicalDisplayBounds ?: error("Display not found") } transitions { if (isCuttlefishDevice) { // Simulates a device rotation through sensors because the rotation button // only appears in a rotation event through sensors execAdb("/vendor/bin/cuttlefish_sensor_injection rotate 0") // verify rotation button existence val rotationButtonSelector = By.res(LAUNCHER_PACKAGE, "rotate_suggestion") uiDevice.wait(Until.hasObject(rotationButtonSelector), FIND_TIMEOUT) uiDevice.findObject(rotationButtonSelector) ?: error("rotation button not found") } } teardown { immersiveApp.exit(wmHelper) } } @Before fun setUpForImmersiveAppTests() { Assume.assumeTrue(isCuttlefishDevice) } /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") override fun taskBarLayerIsVisibleAtStartAndEnd() { } /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") override fun navBarLayerIsVisibleAtStartAndEnd() { } /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") override fun statusBarLayerIsVisibleAtStartAndEnd() { } /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") override fun taskBarWindowIsAlwaysVisible() { } /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") override fun navBarWindowIsAlwaysVisible() { } /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") override fun statusBarWindowIsAlwaysVisible() { } @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") override fun statusBarLayerPositionAtStartAndEnd() { } @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") override fun visibleWindowsShownMoreThanOneConsecutiveEntry() { } /** Test that app is fullscreen by checking status bar and task bar visibility. */ @Postsubmit @Test fun appWindowFullScreen() { flicker.assertWmEnd { this.isAppWindowInvisible(ComponentNameMatcher.STATUS_BAR) .isAppWindowInvisible(ComponentNameMatcher.TASK_BAR) .visibleRegion(immersiveApp).coversExactly(startDisplayBounds) } } /** Test that app is in the original rotation we have set up. */ @Postsubmit @Test fun appInOriginalRotation() { flicker.assertWmEnd { this.hasRotation(Rotation.ROTATION_90) } } companion object { private var startDisplayBounds = Rect.EMPTY const val LAUNCHER_PACKAGE = "com.google.android.apps.nexuslauncher" /** * Creates the test configurations. * * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and * navigation modes. */ @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): Collection<FlickerTest> { return LegacyFlickerTestFactory.nonRotationTests( supportedRotations = listOf(Rotation.ROTATION_90), // TODO(b/292403378): 3 button mode not added as rotation button is hidden in taskbar supportedNavigationModes = listOf(NavBar.MODE_GESTURAL) ) } } } tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml +14 −0 Original line number Diff line number Diff line Loading @@ -102,6 +102,20 @@ <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <activity android:name=".PortraitImmersiveActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.PortraitImmersiveActivity" android:immersive="true" android:resizeableActivity="true" android:screenOrientation="portrait" android:theme="@android:style/Theme.NoTitleBar" android:configChanges="screenSize" android:label="PortraitImmersiveActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <activity android:name=".LaunchTransparentActivity" android:resizeableActivity="false" android:screenOrientation="portrait" Loading tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java +6 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,12 @@ public class ActivityOptions { FLICKER_APP_PACKAGE + ".NonResizeablePortraitActivity"); } public static class PortraitImmersiveActivity { public static final String LABEL = "PortraitImmersiveActivity"; public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE, FLICKER_APP_PACKAGE + ".PortraitImmersiveActivity"); } public static class TransparentActivity { public static final String LABEL = "TransparentActivity"; public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE, Loading tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitImmersiveActivity.java 0 → 100644 +20 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.server.wm.flicker.testapp; public class PortraitImmersiveActivity extends GameActivity { } Loading
libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt +1 −1 Original line number Diff line number Diff line Loading @@ -50,7 +50,7 @@ abstract class BaseAppCompat(flicker: LegacyFlickerTest) : BaseTest(flicker) { } @Before fun before() { fun setUp() { Assume.assumeTrue(tapl.isTablet && letterboxRule.isIgnoreOrientationRequest) } Loading
libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt 0 → 100644 +199 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.appcompat import android.os.Build import android.tools.common.datatypes.Rect import android.platform.test.annotations.Postsubmit import android.system.helpers.CommandsHelper import android.tools.common.NavBar import android.tools.common.Rotation import android.tools.common.flicker.assertions.FlickerTest import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder import android.tools.device.flicker.legacy.LegacyFlickerTest import android.tools.device.flicker.legacy.LegacyFlickerTestFactory import android.tools.device.helpers.FIND_TIMEOUT import android.tools.device.traces.parsers.toFlickerComponent import androidx.test.uiautomator.By import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.Until import com.android.server.wm.flicker.helpers.LetterboxAppHelper import com.android.server.wm.flicker.testapp.ActivityOptions import org.junit.Assume import org.junit.Before import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized /** * Test rotating an immersive app in fullscreen. * * To run this test: `atest WMShellFlickerTestsOther:RotateImmersiveAppInFullscreenTest` * * Actions: * ``` * Rotate the device by 90 degrees to trigger a rotation through sensors * Verify that the button exists * ``` * * Notes: * ``` * Some default assertions that are inherited from * the `BaseTest` are ignored due to the nature of the immersive apps. * * This test only works with Cuttlefish devices. * ``` */ @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) class RotateImmersiveAppInFullscreenTest(flicker: LegacyFlickerTest) : BaseAppCompat(flicker) { private val immersiveApp = LetterboxAppHelper(instrumentation, launcherName = ActivityOptions.PortraitImmersiveActivity.LABEL, component = ActivityOptions.PortraitImmersiveActivity.COMPONENT.toFlickerComponent()) private val cmdHelper: CommandsHelper = CommandsHelper.getInstance(instrumentation) private val execAdb: (String) -> String = { cmd -> cmdHelper.executeShellCommand(cmd) } protected val uiDevice: UiDevice = UiDevice.getInstance(instrumentation) private val isCuttlefishDevice: Boolean = Build.MODEL.contains("Cuttlefish") /** {@inheritDoc} */ override val transition: FlickerBuilder.() -> Unit get() = { setup { setStartRotation() immersiveApp.launchViaIntent(wmHelper) startDisplayBounds = wmHelper.currentState.layerState.physicalDisplayBounds ?: error("Display not found") } transitions { if (isCuttlefishDevice) { // Simulates a device rotation through sensors because the rotation button // only appears in a rotation event through sensors execAdb("/vendor/bin/cuttlefish_sensor_injection rotate 0") // verify rotation button existence val rotationButtonSelector = By.res(LAUNCHER_PACKAGE, "rotate_suggestion") uiDevice.wait(Until.hasObject(rotationButtonSelector), FIND_TIMEOUT) uiDevice.findObject(rotationButtonSelector) ?: error("rotation button not found") } } teardown { immersiveApp.exit(wmHelper) } } @Before fun setUpForImmersiveAppTests() { Assume.assumeTrue(isCuttlefishDevice) } /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") override fun taskBarLayerIsVisibleAtStartAndEnd() { } /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") override fun navBarLayerIsVisibleAtStartAndEnd() { } /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") override fun statusBarLayerIsVisibleAtStartAndEnd() { } /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") override fun taskBarWindowIsAlwaysVisible() { } /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") override fun navBarWindowIsAlwaysVisible() { } /** {@inheritDoc} */ @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") override fun statusBarWindowIsAlwaysVisible() { } @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") override fun statusBarLayerPositionAtStartAndEnd() { } @Test @Ignore("Not applicable to this CUJ. App is in immersive mode.") override fun visibleWindowsShownMoreThanOneConsecutiveEntry() { } /** Test that app is fullscreen by checking status bar and task bar visibility. */ @Postsubmit @Test fun appWindowFullScreen() { flicker.assertWmEnd { this.isAppWindowInvisible(ComponentNameMatcher.STATUS_BAR) .isAppWindowInvisible(ComponentNameMatcher.TASK_BAR) .visibleRegion(immersiveApp).coversExactly(startDisplayBounds) } } /** Test that app is in the original rotation we have set up. */ @Postsubmit @Test fun appInOriginalRotation() { flicker.assertWmEnd { this.hasRotation(Rotation.ROTATION_90) } } companion object { private var startDisplayBounds = Rect.EMPTY const val LAUNCHER_PACKAGE = "com.google.android.apps.nexuslauncher" /** * Creates the test configurations. * * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and * navigation modes. */ @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): Collection<FlickerTest> { return LegacyFlickerTestFactory.nonRotationTests( supportedRotations = listOf(Rotation.ROTATION_90), // TODO(b/292403378): 3 button mode not added as rotation button is hidden in taskbar supportedNavigationModes = listOf(NavBar.MODE_GESTURAL) ) } } }
tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml +14 −0 Original line number Diff line number Diff line Loading @@ -102,6 +102,20 @@ <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <activity android:name=".PortraitImmersiveActivity" android:taskAffinity="com.android.server.wm.flicker.testapp.PortraitImmersiveActivity" android:immersive="true" android:resizeableActivity="true" android:screenOrientation="portrait" android:theme="@android:style/Theme.NoTitleBar" android:configChanges="screenSize" android:label="PortraitImmersiveActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <activity android:name=".LaunchTransparentActivity" android:resizeableActivity="false" android:screenOrientation="portrait" Loading
tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java +6 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,12 @@ public class ActivityOptions { FLICKER_APP_PACKAGE + ".NonResizeablePortraitActivity"); } public static class PortraitImmersiveActivity { public static final String LABEL = "PortraitImmersiveActivity"; public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE, FLICKER_APP_PACKAGE + ".PortraitImmersiveActivity"); } public static class TransparentActivity { public static final String LABEL = "TransparentActivity"; public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE, Loading
tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitImmersiveActivity.java 0 → 100644 +20 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.server.wm.flicker.testapp; public class PortraitImmersiveActivity extends GameActivity { }