Add tests for new task animation

We now want to make sure that the wallpaper is not visible in task transitions and instead that a solid color is shown

Test: atest FlickerTests:TaskTransitionTest
Bug: 199507257
Change-Id: I4f8676620d436b37072219d79f6ddbfef728ea68
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
new file mode 100644
index 0000000..be68704
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 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.helpers
+
+import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.parser.toFlickerComponent
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+
+class NewTasksAppHelper @JvmOverloads constructor(
+    instr: Instrumentation,
+    launcherName: String = ActivityOptions.LAUNCH_NEW_TASK_ACTIVITY_LAUNCHER_NAME,
+    component: FlickerComponentName =
+        ActivityOptions.LAUNCH_NEW_TASK_ACTIVITY_COMPONENT_NAME.toFlickerComponent(),
+    launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+        .getInstance(instr)
+        .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+    fun openNewTask(device: UiDevice, wmHelper: WindowManagerStateHelper) {
+        val button = device.wait(
+            Until.findObject(By.res(getPackage(), "launch_new_task")),
+            FIND_TIMEOUT)
+
+        require(button != null) {
+            "Button not found, this usually happens when the device " +
+                    "was left in an unknown state (e.g. in split screen)"
+        }
+        button.click()
+        wmHelper.waitForAppTransitionIdle()
+        wmHelper.waitForFullScreenApp(component)
+    }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
new file mode 100644
index 0000000..495e2d6
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2021 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.launch
+
+import android.app.Instrumentation
+import android.app.WallpaperManager
+import android.platform.test.annotations.Postsubmit
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.LAUNCHER_COMPONENT
+import com.android.server.wm.flicker.annotation.Group4
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.entireScreenCovered
+import com.android.server.wm.flicker.helpers.NewTasksAppHelper
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.navBarLayerIsVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.server.wm.flicker.testapp.ActivityOptions.LAUNCH_NEW_TASK_ACTIVITY_COMPONENT_NAME
+import com.android.server.wm.flicker.testapp.ActivityOptions.SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME
+import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.common.FlickerComponentName.Companion.SPLASH_SCREEN
+import com.android.server.wm.traces.common.FlickerComponentName.Companion.WALLPAPER_BBQ_WRAPPER
+import com.android.server.wm.traces.parser.toFlickerComponent
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test the back and forward transition between 2 activities.
+ *
+ * To run this test: `atest FlickerTests:ActivitiesTransitionTest`
+ *
+ * Actions:
+ *     Launch the NewTaskLauncherApp [mTestApp]
+ *     Open a new task (SimpleActivity) from the NewTaskLauncherApp [mTestApp]
+ *     Go back to the NewTaskLauncherApp [mTestApp]
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group4
+class TaskTransitionTest(val testSpec: FlickerTestParameter) {
+    val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    private val mTestApp: NewTasksAppHelper = NewTasksAppHelper(instrumentation)
+
+    @FlickerBuilderProvider
+    fun buildFlicker(): FlickerBuilder {
+        return FlickerBuilder(instrumentation).apply {
+            withTestName { testSpec.name }
+            repeat { testSpec.config.repetitions }
+            setup {
+                eachRun {
+                    mTestApp.launchViaIntent(wmHelper)
+                    wmHelper.waitForFullScreenApp(mTestApp.component)
+                }
+            }
+            teardown {
+                test {
+                    mTestApp.exit()
+                }
+            }
+            transitions {
+                mTestApp.openNewTask(device, wmHelper)
+                device.pressBack()
+                wmHelper.waitForAppTransitionIdle()
+                wmHelper.waitForFullScreenApp(mTestApp.component)
+            }
+        }
+    }
+
+    /**
+     * Checks that the wallpaper window is never visible when performing task transitions.
+     * A solid color background should be shown instead.
+     */
+    @Postsubmit
+    @Test
+    fun wallpaperWindowIsNeverVisible() {
+        testSpec.assertWm {
+            this.isNonAppWindowInvisible(WALLPAPER)
+        }
+    }
+
+    /**
+     * Checks that the wallpaper layer is never visible when performing task transitions.
+     * A solid color background should be shown instead.
+     */
+    @Postsubmit
+    @Test
+    fun wallpaperLayerIsNeverVisible() {
+        testSpec.assertLayers {
+            this.isInvisible(WALLPAPER)
+            this.isInvisible(WALLPAPER_BBQ_WRAPPER)
+        }
+    }
+
+    /**
+     * Check that the launcher window is never visible when performing task transitions.
+     * A solid color background should be shown above it.
+     */
+    @Postsubmit
+    @Test
+    fun launcherWindowIsNeverVisible() {
+        testSpec.assertWm {
+            this.isAppWindowInvisible(LAUNCHER_COMPONENT)
+        }
+    }
+
+    /**
+     * Checks that the launcher layer is never visible when performing task transitions.
+     * A solid color background should be shown above it.
+     */
+    @Postsubmit
+    @Test
+    fun launcherLayerIsNeverVisible() {
+        testSpec.assertLayers {
+            this.isInvisible(LAUNCHER_COMPONENT)
+        }
+    }
+
+    /**
+     * Checks that a color background is visible while the task transition is occurring.
+     */
+    @Postsubmit
+    @Test
+    fun colorLayerIsVisibleDuringTransition() {
+        val bgColorLayer = FlickerComponentName("", "colorBackgroundLayer")
+        val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+
+        testSpec.assertLayers {
+            this.coversExactly(displayBounds, LAUNCH_NEW_TASK_ACTIVITY)
+                .isInvisible(bgColorLayer)
+                .then()
+                // Transitioning
+                .isVisible(bgColorLayer)
+                .then()
+                // Fully transitioned to simple SIMPLE_ACTIVITY
+                .coversExactly(displayBounds, SIMPLE_ACTIVITY)
+                .isInvisible(bgColorLayer)
+                .then()
+                // Transitioning back
+                .isVisible(bgColorLayer)
+                .then()
+                // Fully transitioned back to LAUNCH_NEW_TASK_ACTIVITY
+                .isInvisible(bgColorLayer)
+                .coversExactly(displayBounds, LAUNCH_NEW_TASK_ACTIVITY)
+        }
+    }
+
+    /**
+     * Checks that we start with the LaunchNewTask activity on top and then open up
+     * the SimpleActivity and then go back to the LaunchNewTask activity.
+     */
+    @Postsubmit
+    @Test
+    fun newTaskOpensOnTopAndThenCloses() {
+        testSpec.assertWm {
+            this.isAppWindowOnTop(LAUNCH_NEW_TASK_ACTIVITY)
+                    .then()
+                    .isAppWindowOnTop(SPLASH_SCREEN, isOptional = true)
+                    .then()
+                    .isAppWindowOnTop(SIMPLE_ACTIVITY)
+                    .then()
+                    .isAppWindowOnTop(SPLASH_SCREEN, isOptional = true)
+                    .then()
+                    .isAppWindowOnTop(LAUNCH_NEW_TASK_ACTIVITY)
+        }
+    }
+
+    /**
+     * Checks that all parts of the screen are covered at the start and end of the transition
+     */
+    @Postsubmit
+    @Test
+    fun entireScreenCovered() = testSpec.entireScreenCovered()
+
+    /**
+     * Checks that the navbar window is visible throughout the transition
+     */
+    @Postsubmit
+    @Test
+    fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
+
+    /**
+     * Checks that the navbar layer is visible throughout the transition
+     */
+    @Postsubmit
+    @Test
+    fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
+
+    /**
+     * Checks that the status bar window is visible throughout the transition
+     */
+    @Postsubmit
+    @Test
+    fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
+
+    /**
+     * Checks that the status bar layer is visible throughout the transition
+     */
+    @Postsubmit
+    @Test
+    fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
+
+    companion object {
+        private val WALLPAPER = getWallpaperPackage(InstrumentationRegistry.getInstrumentation())
+        private val LAUNCH_NEW_TASK_ACTIVITY =
+                LAUNCH_NEW_TASK_ACTIVITY_COMPONENT_NAME.toFlickerComponent()
+        private val SIMPLE_ACTIVITY = SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME.toFlickerComponent()
+
+        private fun getWallpaperPackage(instrumentation: Instrumentation): FlickerComponentName {
+            val wallpaperManager = WallpaperManager.getInstance(instrumentation.targetContext)
+
+            return wallpaperManager.wallpaperInfo.component.toFlickerComponent()
+        }
+
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams(): Collection<FlickerTestParameter> {
+            return FlickerTestParameterFactory.getInstance()
+                    .getConfigNonRotationTests(repetitions = 5)
+        }
+    }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 3b9f33a..cb37fc7 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -80,5 +80,15 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+        <activity android:name=".LaunchNewTaskActivity"
+                  android:taskAffinity="com.android.server.wm.flicker.testapp.LaunchNewTaskActivity"
+                  android:configChanges="orientation|screenSize"
+                  android:label="LaunchNewTaskActivity"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml
new file mode 100644
index 0000000..8f75d17
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2018 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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@android:color/holo_orange_light">
+    <Button
+        android:id="@+id/launch_new_task"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="New task" />
+</LinearLayout>
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 224d2ac..baf36ab 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
@@ -51,4 +51,9 @@
     public static final ComponentName BUTTON_ACTIVITY_COMPONENT_NAME =
             new ComponentName(FLICKER_APP_PACKAGE,
                     FLICKER_APP_PACKAGE + ".ButtonActivity");
+
+    public static final String LAUNCH_NEW_TASK_ACTIVITY_LAUNCHER_NAME = "LaunchNewTaskApp";
+    public static final ComponentName LAUNCH_NEW_TASK_ACTIVITY_COMPONENT_NAME =
+            new ComponentName(FLICKER_APP_PACKAGE,
+                    FLICKER_APP_PACKAGE + ".LaunchNewTaskActivity");
 }
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java
new file mode 100644
index 0000000..1809781
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.WindowManager;
+import android.widget.Button;
+
+public class LaunchNewTaskActivity extends Activity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        WindowManager.LayoutParams p = getWindow().getAttributes();
+        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
+                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+        getWindow().setAttributes(p);
+        setContentView(R.layout.task_button);
+
+        Button button = findViewById(R.id.launch_new_task);
+        button.setOnClickListener(v -> {
+            Intent intent = new Intent(LaunchNewTaskActivity.this, SimpleActivity.class);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK);
+            startActivity(intent);
+        });
+    }
+}