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