/* * Copyright (C) 2022 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 import android.app.Instrumentation import android.content.Intent import android.platform.test.annotations.Presubmit import android.tools.flicker.junit.FlickerBuilderProvider import android.tools.flicker.FlickerBuilder import android.tools.flicker.FlickerTest import android.tools.flicker.rules.ClearAppCacheRule import android.tools.traces.executeShellCommand import android.util.Log import androidx.test.platform.app.InstrumentationRegistry import com.android.launcher3.tapl.LauncherInstrumentation import com.android.wm.shell.Flags import org.junit.Assume import org.junit.AssumptionViolatedException import org.junit.ClassRule import org.junit.Test /** * Base test class containing common assertions for [ComponentNameMatcher.NAV_BAR], * [ComponentNameMatcher.TASK_BAR], [ComponentNameMatcher.STATUS_BAR], and general assertions * (layers visible in consecutive states, entire screen covered, etc.) */ abstract class BaseTest @JvmOverloads constructor( protected val flicker: FlickerTest, protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(), protected val tapl: LauncherInstrumentation = LauncherInstrumentation() ) { init { tapl.expectedRotationCheckEnabled = false executeShellCommand( "settings put system hide_rotation_lock_toggle_for_accessibility 1" ) } private val logTag = this::class.java.simpleName protected val usesTaskbar: Boolean get() = flicker.scenario.isTablet || Flags.enableTaskbarOnPhones() /** Specification of the test transition to execute */ abstract val transition: FlickerBuilder.() -> Unit protected val broadcastActionTrigger = BroadcastActionTrigger(instrumentation) // Helper class to process test actions by broadcast. protected class BroadcastActionTrigger(private val instrumentation: Instrumentation) { private fun createIntentWithAction(broadcastAction: String): Intent { return Intent(broadcastAction).setFlags(Intent.FLAG_RECEIVER_FOREGROUND) } fun doAction(broadcastAction: String) { instrumentation.context.sendBroadcast(createIntentWithAction(broadcastAction)) } } /** * Entry point for the test runner. It will use this method to initialize and cache flicker * executions */ @FlickerBuilderProvider fun buildFlicker(): FlickerBuilder { return FlickerBuilder(instrumentation).apply { setup { flicker.scenario.setIsTablet(wmHelper.currentState.wmState.isTablet) } transition() } } /** Checks that all parts of the screen are covered during the transition */ @Presubmit @Test open fun entireScreenCovered() = flicker.entireScreenCovered() /** * Checks that the [ComponentNameMatcher.NAV_BAR] layer is visible during the whole transition * * Note: Phones only */ @Presubmit @Test open fun navBarLayerIsVisibleAtStartAndEnd() { Assume.assumeFalse(usesTaskbar) flicker.navBarLayerIsVisibleAtStartAndEnd() } /** * Checks the position of the [ComponentNameMatcher.NAV_BAR] at the start and end of the * transition * * Note: Phones only */ @Presubmit @Test open fun navBarLayerPositionAtStartAndEnd() { Assume.assumeFalse(usesTaskbar) flicker.navBarLayerPositionAtStartAndEnd() } /** * Checks that the [ComponentNameMatcher.NAV_BAR] window is visible during the whole transition * * Note: Phones only */ @Presubmit @Test open fun navBarWindowIsAlwaysVisible() { Assume.assumeFalse(usesTaskbar) Assume.assumeFalse(flicker.scenario.isLandscapeOrSeascapeAtStart) flicker.navBarWindowIsAlwaysVisible() } /** * Checks that the [ComponentNameMatcher.NAV_BAR] window is visible at the start and end of the * transition * * Note: Phones only */ @Presubmit @Test open fun navBarWindowIsVisibleAtStartAndEnd() { Assume.assumeFalse(usesTaskbar) flicker.navBarWindowIsVisibleAtStartAndEnd() } /** * Checks that the [ComponentNameMatcher.TASK_BAR] window is visible at the start and end of the * transition */ @Presubmit @Test open fun taskBarLayerIsVisibleAtStartAndEnd() { Assume.assumeTrue(usesTaskbar) flicker.taskBarLayerIsVisibleAtStartAndEnd() } /** * Checks that the [ComponentNameMatcher.TASK_BAR] window is visible during the whole transition */ @Presubmit @Test open fun taskBarWindowIsAlwaysVisible() { Assume.assumeTrue(usesTaskbar) flicker.taskBarWindowIsAlwaysVisible() } /** * Checks that the [ComponentNameMatcher.STATUS_BAR] layer is visible at the start and end of * the transition */ @Presubmit @Test open fun statusBarLayerIsVisibleAtStartAndEnd() = flicker.statusBarLayerIsVisibleAtStartAndEnd() /** * Checks the position of the [ComponentNameMatcher.STATUS_BAR] at the start and end of the * transition */ @Presubmit @Test open fun statusBarLayerPositionAtStartAndEnd() = flicker.statusBarLayerPositionAtStartAndEnd() /** * Checks that the [ComponentNameMatcher.STATUS_BAR] window is visible during the whole * transition */ @Presubmit @Test open fun statusBarWindowIsAlwaysVisible() = flicker.statusBarWindowIsAlwaysVisible() /** * Checks that all layers that are visible on the trace, are visible for at least 2 consecutive * entries. */ @Presubmit @Test open fun visibleLayersShownMoreThanOneConsecutiveEntry() { flicker.assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry() } } /** * Checks that all windows that are visible on the trace, are visible for at least 2 consecutive * entries. */ @Presubmit @Test open fun visibleWindowsShownMoreThanOneConsecutiveEntry() { flicker.assertWm { this.visibleWindowsShownMoreThanOneConsecutiveEntry() } } open fun cujCompleted() { runAndIgnoreAssumptionViolation { entireScreenCovered() } runAndIgnoreAssumptionViolation { statusBarLayerIsVisibleAtStartAndEnd() } runAndIgnoreAssumptionViolation { statusBarLayerPositionAtStartAndEnd() } runAndIgnoreAssumptionViolation { statusBarWindowIsAlwaysVisible() } runAndIgnoreAssumptionViolation { visibleLayersShownMoreThanOneConsecutiveEntry() } runAndIgnoreAssumptionViolation { visibleWindowsShownMoreThanOneConsecutiveEntry() } runAndIgnoreAssumptionViolation { taskBarLayerIsVisibleAtStartAndEnd() } runAndIgnoreAssumptionViolation { taskBarWindowIsAlwaysVisible() } runAndIgnoreAssumptionViolation { navBarLayerIsVisibleAtStartAndEnd() } runAndIgnoreAssumptionViolation { navBarWindowIsAlwaysVisible() } runAndIgnoreAssumptionViolation { navBarWindowIsVisibleAtStartAndEnd() } } protected fun runAndIgnoreAssumptionViolation(predicate: () -> Unit) { try { predicate() } catch (e: AssumptionViolatedException) { Log.e(logTag, "Assumption violation on CUJ complete", e) } } companion object { @ClassRule @JvmField val clearCache = ClearAppCacheRule() } }