Merge "Create RotateImmeriveAppInFullscreenTest" into main
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
index 77f14f1..adf92d8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
@@ -50,7 +50,7 @@
         }
 
     @Before
-    fun before() {
+    fun setUp() {
         Assume.assumeTrue(tapl.isTablet && letterboxRule.isIgnoreOrientationRequest)
     }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt
new file mode 100644
index 0000000..ba2b3e7
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt
@@ -0,0 +1,199 @@
+/*
+ * 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)
+
+            )
+        }
+    }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index f867c98..9198ae1 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -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"
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 7c5e9a3..8b334c0 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -73,6 +73,12 @@
                 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,
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitImmersiveActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitImmersiveActivity.java
new file mode 100644
index 0000000..0a7f81c
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitImmersiveActivity.java
@@ -0,0 +1,20 @@
+/*
+ * 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 {
+}