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 0000000000000..be68704fc32d5 --- /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 0000000000000..495e2d62a11d7 --- /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 { + 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 3b9f33aaded18..cb37fc7b47e9d 100644 --- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml +++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml @@ -80,5 +80,15 @@ + + + + + + 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 0000000000000..8f75d175d00aa --- /dev/null +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml @@ -0,0 +1,27 @@ + + + +