1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wm.flicker.quickswitch 18 19 import android.graphics.Rect 20 import android.platform.test.annotations.Presubmit 21 import android.tools.NavBar 22 import android.tools.flicker.junit.FlickerParametersRunnerFactory 23 import android.tools.flicker.legacy.FlickerBuilder 24 import android.tools.flicker.legacy.LegacyFlickerTest 25 import android.tools.flicker.legacy.LegacyFlickerTestFactory 26 import android.tools.traces.component.ComponentNameMatcher 27 import androidx.test.filters.FlakyTest 28 import com.android.server.wm.flicker.BaseTest 29 import com.android.server.wm.flicker.helpers.NonResizeableAppHelper 30 import com.android.server.wm.flicker.helpers.SimpleAppHelper 31 import org.junit.FixMethodOrder 32 import org.junit.Ignore 33 import org.junit.Test 34 import org.junit.runner.RunWith 35 import org.junit.runners.MethodSorters 36 import org.junit.runners.Parameterized 37 38 /** 39 * Test quick switching back to previous app from last opened app 40 * 41 * To run this test: `atest FlickerTestsQuickswitch:QuickSwitchBetweenTwoAppsBackTest` 42 * 43 * Actions: 44 * ``` 45 * Launch an app [testApp1] 46 * Launch another app [testApp2] 47 * Swipe right from the bottom of the screen to quick switch back to the first app [testApp1] 48 * ``` 49 */ 50 @RunWith(Parameterized::class) 51 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) 52 @FixMethodOrder(MethodSorters.NAME_ASCENDING) 53 class QuickSwitchBetweenTwoAppsBackTest(flicker: LegacyFlickerTest) : BaseTest(flicker) { 54 private val testApp1 = SimpleAppHelper(instrumentation) 55 private val testApp2 = NonResizeableAppHelper(instrumentation) 56 57 /** {@inheritDoc} */ <lambda>null58 override val transition: FlickerBuilder.() -> Unit = { 59 setup { 60 tapl.setExpectedRotation(flicker.scenario.startRotation.value) 61 tapl.setIgnoreTaskbarVisibility(true) 62 testApp1.launchViaIntent(wmHelper) 63 testApp2.launchViaIntent(wmHelper) 64 startDisplayBounds = 65 wmHelper.currentState.layerState.physicalDisplayBounds ?: error("Display not found") 66 } 67 transitions { 68 tapl.launchedAppState.quickSwitchToPreviousApp() 69 wmHelper 70 .StateSyncBuilder() 71 .withFullScreenApp(testApp1) 72 .withNavOrTaskBarVisible() 73 .withStatusBarVisible() 74 .waitForAndVerify() 75 } 76 77 teardown { 78 testApp1.exit(wmHelper) 79 testApp2.exit(wmHelper) 80 } 81 } 82 83 /** 84 * Checks that the transition starts with [testApp2]'s windows filling/covering exactly the 85 * entirety of the display. 86 */ 87 @Presubmit 88 @Test startsWithApp2WindowsCoverFullScreennull89 open fun startsWithApp2WindowsCoverFullScreen() { 90 flicker.assertWmStart { this.visibleRegion(testApp2).coversExactly(startDisplayBounds) } 91 } 92 93 /** 94 * Checks that the transition starts with [testApp2]'s layers filling/covering exactly the 95 * entirety of the display. 96 */ 97 @FlakyTest(bugId = 250520840) 98 @Test startsWithApp2LayersCoverFullScreennull99 open fun startsWithApp2LayersCoverFullScreen() { 100 flicker.assertLayersStart { this.visibleRegion(testApp2).coversExactly(startDisplayBounds) } 101 } 102 103 /** Checks that the transition starts with [testApp2] being the top window. */ 104 @Presubmit 105 @Test startsWithApp2WindowBeingOnTopnull106 open fun startsWithApp2WindowBeingOnTop() { 107 flicker.assertWmStart { this.isAppWindowOnTop(testApp2) } 108 } 109 110 /** 111 * Checks that [testApp1] windows fill the entire screen (i.e. is "fullscreen") at the end of 112 * the transition once we have fully quick switched from [testApp2] back to the [testApp1]. 113 */ 114 @Presubmit 115 @Test endsWithApp1WindowsCoveringFullScreennull116 open fun endsWithApp1WindowsCoveringFullScreen() { 117 flicker.assertWmEnd { this.visibleRegion(testApp1).coversExactly(startDisplayBounds) } 118 } 119 120 /** 121 * Checks that [testApp1] layers fill the entire screen (i.e. is "fullscreen") at the end of the 122 * transition once we have fully quick switched from [testApp2] back to the [testApp1]. 123 */ 124 @Presubmit 125 @Test endsWithApp1LayersCoveringFullScreennull126 fun endsWithApp1LayersCoveringFullScreen() { 127 flicker.assertLayersEnd { this.visibleRegion(testApp1).coversExactly(startDisplayBounds) } 128 } 129 130 /** 131 * Checks that [testApp1] is the top window at the end of the transition once we have fully 132 * quick switched from [testApp2] back to the [testApp1]. 133 */ 134 @Presubmit 135 @Test endsWithApp1BeingOnTopnull136 open fun endsWithApp1BeingOnTop() { 137 flicker.assertWmEnd { this.isAppWindowOnTop(testApp1) } 138 } 139 140 /** 141 * Checks that [testApp1]'s window starts off invisible and becomes visible at some point before 142 * the end of the transition and then stays visible until the end of the transition. 143 */ 144 @Presubmit 145 @Test app1WindowBecomesAndStaysVisiblenull146 open fun app1WindowBecomesAndStaysVisible() { 147 flicker.assertWm { 148 this.isAppWindowInvisible(testApp1) 149 .then() 150 .isAppWindowVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true) 151 .then() 152 .isAppWindowVisible(testApp1) 153 } 154 } 155 156 /** 157 * Checks that [testApp1]'s layer starts off invisible and becomes visible at some point before 158 * the end of the transition and then stays visible until the end of the transition. 159 */ 160 @Presubmit 161 @Test app1LayerBecomesAndStaysVisiblenull162 open fun app1LayerBecomesAndStaysVisible() { 163 flicker.assertLayers { this.isInvisible(testApp1).then().isVisible(testApp1) } 164 } 165 166 /** 167 * Checks that [testApp2]'s window starts off visible and becomes invisible at some point before 168 * the end of the transition and then stays invisible until the end of the transition. 169 */ 170 @Presubmit 171 @Test app2WindowBecomesAndStaysInvisiblenull172 open fun app2WindowBecomesAndStaysInvisible() { 173 flicker.assertWm { this.isAppWindowVisible(testApp2).then().isAppWindowInvisible(testApp2) } 174 } 175 176 /** 177 * Checks that [testApp2]'s layer starts off visible and becomes invisible at some point before 178 * the end of the transition and then stays invisible until the end of the transition. 179 */ 180 @Presubmit 181 @Test app2LayerBecomesAndStaysInvisiblenull182 open fun app2LayerBecomesAndStaysInvisible() { 183 flicker.assertLayers { this.isVisible(testApp2).then().isInvisible(testApp2) } 184 } 185 186 /** 187 * Checks that [testApp2]'s window is visible at least until [testApp1]'s window is visible. 188 * Ensures that at any point, either [testApp1] or [testApp2]'s windows are at least partially 189 * visible. 190 */ 191 @Presubmit 192 @Test app1WindowIsVisibleOnceApp2WindowIsInvisiblenull193 open fun app1WindowIsVisibleOnceApp2WindowIsInvisible() { 194 flicker.assertWm { 195 this.isAppWindowVisible(testApp2) 196 .then() 197 // TODO: Do we actually want to test this? Seems too implementation specific... 198 .isAppWindowVisible(ComponentNameMatcher.LAUNCHER, isOptional = true) 199 .then() 200 .isAppWindowVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true) 201 .then() 202 .isAppWindowVisible(testApp1) 203 } 204 } 205 206 /** 207 * Checks that [testApp2]'s layer is visible at least until [testApp1]'s window is visible. 208 * Ensures that at any point, either [testApp1] or [testApp2]'s windows are at least partially 209 * visible. 210 */ 211 @Presubmit 212 @Test app1LayerIsVisibleOnceApp2LayerIsInvisiblenull213 open fun app1LayerIsVisibleOnceApp2LayerIsInvisible() { 214 flicker.assertLayers { 215 this.isVisible(testApp2) 216 .then() 217 .isVisible(ComponentNameMatcher.LAUNCHER, isOptional = true) 218 .then() 219 .isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true) 220 .then() 221 .isVisible(testApp1) 222 } 223 } 224 225 /** {@inheritDoc} */ 226 @Ignore("Nav bar window becomes invisible during quick switch") 227 @Test navBarWindowIsAlwaysVisiblenull228 override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible() 229 230 @FlakyTest(bugId = 246284708) 231 @Test 232 override fun visibleLayersShownMoreThanOneConsecutiveEntry() = 233 super.visibleLayersShownMoreThanOneConsecutiveEntry() 234 235 @FlakyTest(bugId = 250518877) 236 @Test 237 override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd() 238 239 companion object { 240 private var startDisplayBounds = Rect() 241 242 @Parameterized.Parameters(name = "{0}") 243 @JvmStatic 244 fun getParams() = 245 LegacyFlickerTestFactory.nonRotationTests( 246 supportedNavigationModes = listOf(NavBar.MODE_GESTURAL) 247 ) 248 } 249 } 250