• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
18 
19 import android.app.Instrumentation
20 import android.platform.test.rule.NavigationModeRule
21 import android.platform.test.rule.PressHomeRule
22 import android.platform.test.rule.UnlockScreenRule
23 import android.view.Surface
24 import android.view.WindowManagerPolicyConstants
25 import androidx.annotation.VisibleForTesting
26 import com.android.server.wm.flicker.assertions.AssertionData
27 import com.android.server.wm.flicker.assertions.FlickerSubject
28 import com.android.server.wm.flicker.dsl.AssertionTag
29 import com.android.server.wm.flicker.dsl.FlickerBuilder
30 import com.android.server.wm.flicker.helpers.SampleAppHelper
31 import com.android.server.wm.flicker.rules.ChangeDisplayOrientationRule
32 import com.android.server.wm.flicker.rules.LaunchAppRule
33 import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule
34 import com.android.server.wm.flicker.traces.eventlog.EventLogSubject
35 import com.android.server.wm.flicker.traces.layers.LayerTraceEntrySubject
36 import com.android.server.wm.flicker.traces.layers.LayersTraceSubject
37 import com.android.server.wm.flicker.traces.region.RegionTraceSubject
38 import com.android.server.wm.flicker.traces.windowmanager.WindowManagerStateSubject
39 import com.android.server.wm.flicker.traces.windowmanager.WindowManagerTraceSubject
40 import com.android.server.wm.traces.common.FlickerComponentName
41 import org.junit.rules.RuleChain
42 import org.junit.rules.TestRule
43 
44 /**
45  * Specification of a flicker test for JUnit ParameterizedRunner class
46  */
47 data class FlickerTestParameter(
48     @JvmField val config: MutableMap<String, Any?>,
49     private val nameOverride: String? = null
50 ) {
51     private var internalFlicker: Flicker? = null
52 
53     private val flicker: Flicker get() = internalFlicker ?: error("Flicker not initialized")
54     private val name: String get() = nameOverride ?: defaultName(this)
55 
56     internal val isInitialized: Boolean get() = internalFlicker != null
57     internal val result: FlickerResult? get() = internalFlicker?.result
58 
59     /**
60      * If the initial screen rotation is 90 (landscape) or 180 (seascape) degrees
61      */
62     val isLandscapeOrSeascapeAtStart: Boolean
63         get() = startRotation == Surface.ROTATION_90 || startRotation == Surface.ROTATION_270
64 
65     /**
66      * Initial screen rotation (see [Surface] for values)
67      *
68      * Defaults to [Surface.ROTATION_0]
69      */
70     val startRotation: Int
71         get() = config.getOrDefault(START_ROTATION, Surface.ROTATION_0) as Int
72 
73     /**
74      * Final screen rotation (see [Surface] for values)
75      *
76      * Defaults to [startRotation]
77      */
78     val endRotation: Int
79         get() = config.getOrDefault(END_ROTATION, startRotation) as Int
80 
81     /**
82      * Navigation mode, such as 3 button or gestural.
83      *
84      * See [WindowManagerPolicyConstants].NAV_BAR_MODE_* for possible values
85      *
86      * Defaults to [WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY]
87      */
88     val navBarMode: String
89         get() = config.getOrDefault(NAV_BAR_MODE,
90             WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY) as String
91 
92     val navBarModeName
93         get() = when (this.navBarMode) {
94             WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY -> "3_BUTTON_NAV"
95             WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY -> "2_BUTTON_NAV"
96             WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY -> "GESTURAL_NAV"
97             else -> "UNKNOWN_NAV_BAR_MODE(${this.navBarMode}"
98         }
99 
100     val isGesturalNavigation =
101         navBarMode == WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
102 
103     /**
104      * Clean the internal flicker reference (cache)
105      */
clearnull106     fun clear() {
107         internalFlicker?.clear()
108     }
109 
110     /**
111      * Builds a flicker object and assigns it to the test parameters
112      */
initializenull113     fun initialize(builder: FlickerBuilder, testName: String) {
114         internalFlicker = builder
115             .withTestName { "${testName}_$name" }
116             .repeat { config.getOrDefault(REPETITIONS, 1) as Int }
117             .build(TransitionRunnerWithRules(getTestSetupRules(builder.instrumentation)))
118     }
119 
120     /**
121      * Execute [assertion] on the initial state of a WM trace (before transition)
122      *
123      * @param assertion Assertion predicate
124      */
assertWmStartnull125     fun assertWmStart(assertion: WindowManagerStateSubject.() -> Unit) {
126         val assertionData = buildWmStartAssertion(assertion)
127         this.flicker.checkAssertion(assertionData)
128     }
129 
130     /**
131      * Execute [assertion] on the final state of a WM trace (after transition)
132      *
133      * @param assertion Assertion predicate
134      */
assertWmEndnull135     fun assertWmEnd(assertion: WindowManagerStateSubject.() -> Unit) {
136         val assertionData = buildWmEndAssertion(assertion)
137         this.flicker.checkAssertion(assertionData)
138     }
139 
140     /**
141      * Execute [assertion] on a WM trace
142      *
143      * @param assertion Assertion predicate
144      */
assertWmnull145     fun assertWm(assertion: WindowManagerTraceSubject.() -> Unit) {
146         val assertionData = buildWMAssertion(assertion)
147         this.flicker.checkAssertion(assertionData)
148     }
149 
150     /**
151      * Execute [assertion] on a user defined moment ([tag]) of a WM trace
152      *
153      * @param assertion Assertion predicate
154      */
assertWmTagnull155     fun assertWmTag(tag: String, assertion: WindowManagerStateSubject.() -> Unit) {
156         val assertionData = buildWMTagAssertion(tag, assertion)
157         this.flicker.checkAssertion(assertionData)
158     }
159 
160     /**
161      * Execute [assertion] on the visible region of a component on the WM trace
162      *
163      * @param component The component for which we want to get the visible region for to run the
164      *                  assertion on
165      * @param assertion Assertion predicate
166      */
assertWmVisibleRegionnull167     fun assertWmVisibleRegion(
168         vararg components: FlickerComponentName,
169         assertion: RegionTraceSubject.() -> Unit
170     ) {
171         val assertionData = buildWmVisibleRegionAssertion(components = components, assertion)
172         this.flicker.checkAssertion(assertionData)
173     }
174 
175     /**
176      * Execute [assertion] on the initial state of a SF trace (before transition)
177      *
178      * @param assertion Assertion predicate
179      */
assertLayersStartnull180     fun assertLayersStart(assertion: LayerTraceEntrySubject.() -> Unit) {
181         val assertionData = buildLayersStartAssertion(assertion)
182         this.flicker.checkAssertion(assertionData)
183     }
184 
185     /**
186      * Execute [assertion] on the final state of a SF trace (after transition)
187      *
188      * @param assertion Assertion predicate
189      */
assertLayersEndnull190     fun assertLayersEnd(assertion: LayerTraceEntrySubject.() -> Unit) {
191         val assertionData = buildLayersEndAssertion(assertion)
192         this.flicker.checkAssertion(assertionData)
193     }
194 
195     /**
196      * Execute [assertion] on a SF trace
197      *
198      * @param assertion Assertion predicate
199      */
assertLayersnull200     fun assertLayers(assertion: LayersTraceSubject.() -> Unit) {
201         val assertionData = buildLayersAssertion(assertion)
202         this.flicker.checkAssertion(assertionData)
203     }
204 
205     /**
206      * Execute [assertion] on a user defined moment ([tag]) of a SF trace
207      *
208      * @param assertion Assertion predicate
209      */
assertLayersTagnull210     fun assertLayersTag(tag: String, assertion: LayerTraceEntrySubject.() -> Unit) {
211         val assertionData = buildLayersTagAssertion(tag, assertion)
212         this.flicker.checkAssertion(assertionData)
213     }
214 
215     /**
216      * Execute [assertion] on the visible region of a component on the layers trace
217      *
218      * @param components The components for which we want to get the visible region for to run the
219      *   assertion on. The assertion will run on the union of the regions of these components.
220      * @param useCompositionEngineRegionOnly If true, uses only the region calculated from the
221      *   Composition Engine (CE) -- visibleRegion in the proto definition. Otherwise calculates
222      *   the visible region when the information is not available from the CE
223      * @param assertion Assertion predicate
224      */
225     @JvmOverloads
assertLayersVisibleRegionnull226     fun assertLayersVisibleRegion(
227         vararg components: FlickerComponentName,
228         useCompositionEngineRegionOnly: Boolean = true,
229         assertion: RegionTraceSubject.() -> Unit
230     ) {
231         val assertionData = buildLayersVisibleRegionAssertion(
232                 components = components, useCompositionEngineRegionOnly, assertion)
233         this.flicker.checkAssertion(assertionData)
234     }
235 
236     /**
237      * Execute [assertion] on a sequence of event logs
238      *
239      * @param assertion Assertion predicate
240      */
assertEventLognull241     fun assertEventLog(assertion: EventLogSubject.() -> Unit) {
242         val assertionData = buildEventLogAssertion(assertion)
243         this.flicker.checkAssertion(assertionData)
244     }
245 
246     /**
247      * Create the default flicker test setup rules. In order:
248      *   - unlock device
249      *   - change orientation
250      *   - change navigation mode
251      *   - launch an app
252      *   - remove all apps
253      *   - go to home screen
254      *
255      * (b/186740751) An app should be launched because, after changing the navigation mode,
256      * the first app launch is handled as a screen size change (similar to a rotation), this
257      * causes different problems during testing (e.g. IME now shown on app launch)
258      */
getTestSetupRulesnull259     fun getTestSetupRules(instrumentation: Instrumentation): TestRule =
260         RuleChain.outerRule(UnlockScreenRule())
261             .around(NavigationModeRule(navBarMode))
262             .around(LaunchAppRule(SampleAppHelper(instrumentation)))
263             .around(RemoveAllTasksButHomeRule())
264             .around(ChangeDisplayOrientationRule(startRotation))
265             .around(PressHomeRule())
266 
267     override fun toString(): String = name
268 
269     companion object {
270         internal const val REPETITIONS = "repetitions"
271         internal const val START_ROTATION = "startRotation"
272         internal const val END_ROTATION = "endRotation"
273         internal const val NAV_BAR_MODE = "navBarMode"
274 
275         @VisibleForTesting
276         @JvmStatic
277         fun buildWmStartAssertion(assertion: WindowManagerStateSubject.() -> Unit): AssertionData =
278             AssertionData(tag = AssertionTag.START,
279                 expectedSubjectClass = WindowManagerStateSubject::class,
280                 assertion = assertion as FlickerSubject.() -> Unit)
281 
282         @VisibleForTesting
283         @JvmStatic
284         fun buildWmEndAssertion(assertion: WindowManagerStateSubject.() -> Unit): AssertionData =
285             AssertionData(tag = AssertionTag.END,
286                 expectedSubjectClass = WindowManagerStateSubject::class,
287                 assertion = assertion as FlickerSubject.() -> Unit)
288 
289         @VisibleForTesting
290         @JvmStatic
291         fun buildWMAssertion(assertion: WindowManagerTraceSubject.() -> Unit): AssertionData {
292             val closedAssertion: WindowManagerTraceSubject.() -> Unit = {
293                 this.clear()
294                 assertion()
295                 this.forAllEntries()
296             }
297             return AssertionData(tag = AssertionTag.ALL,
298                 expectedSubjectClass = WindowManagerTraceSubject::class,
299                 assertion = closedAssertion as FlickerSubject.() -> Unit)
300         }
301 
302         @VisibleForTesting
303         @JvmStatic
304         fun buildWMTagAssertion(
305             tag: String,
306             assertion: WindowManagerStateSubject.() -> Unit
307         ): AssertionData = AssertionData(tag = tag,
308             expectedSubjectClass = WindowManagerStateSubject::class,
309             assertion = assertion as FlickerSubject.() -> Unit)
310 
311         @VisibleForTesting
312         @JvmStatic
313         fun buildWmVisibleRegionAssertion(
314             vararg components: FlickerComponentName,
315             assertion: RegionTraceSubject.() -> Unit
316         ): AssertionData {
317             val closedAssertion: WindowManagerTraceSubject.() -> Unit = {
318                 this.clear()
319                 // convert WindowManagerTraceSubject to RegionTraceSubject
320                 val regionTraceSubject = visibleRegion(*components)
321                 // add assertions to the regionTraceSubject's AssertionChecker
322                 assertion(regionTraceSubject)
323                 // loop through all entries to validate assertions
324                 regionTraceSubject.forAllEntries()
325             }
326 
327             return AssertionData(tag = AssertionTag.ALL,
328                 expectedSubjectClass = WindowManagerTraceSubject::class,
329                 assertion = closedAssertion as FlickerSubject.() -> Unit)
330         }
331 
332         @VisibleForTesting
333         @JvmStatic
334         fun buildLayersStartAssertion(assertion: LayerTraceEntrySubject.() -> Unit): AssertionData =
335             AssertionData(tag = AssertionTag.START,
336                 expectedSubjectClass = LayerTraceEntrySubject::class,
337                 assertion = assertion as FlickerSubject.() -> Unit)
338 
339         @VisibleForTesting
340         @JvmStatic
341         fun buildLayersEndAssertion(assertion: LayerTraceEntrySubject.() -> Unit): AssertionData =
342             AssertionData(tag = AssertionTag.END,
343                 expectedSubjectClass = LayerTraceEntrySubject::class,
344                 assertion = assertion as FlickerSubject.() -> Unit)
345 
346         @VisibleForTesting
347         @JvmStatic
348         fun buildLayersAssertion(assertion: LayersTraceSubject.() -> Unit): AssertionData {
349             val closedAssertion: LayersTraceSubject.() -> Unit = {
350                 this.clear()
351                 assertion()
352                 this.forAllEntries()
353             }
354 
355             return AssertionData(tag = AssertionTag.ALL,
356                 expectedSubjectClass = LayersTraceSubject::class,
357                 assertion = closedAssertion as FlickerSubject.() -> Unit)
358         }
359 
360         @VisibleForTesting
361         @JvmStatic
362         fun buildLayersTagAssertion(
363             tag: String,
364             assertion: LayerTraceEntrySubject.() -> Unit
365         ): AssertionData = AssertionData(tag = tag,
366             expectedSubjectClass = LayerTraceEntrySubject::class,
367             assertion = assertion as FlickerSubject.() -> Unit)
368 
369         @VisibleForTesting
370         @JvmOverloads
371         @JvmStatic
372         fun buildLayersVisibleRegionAssertion(
373             vararg components: FlickerComponentName,
374             useCompositionEngineRegionOnly: Boolean = true,
375             assertion: RegionTraceSubject.() -> Unit
376         ): AssertionData {
377             val closedAssertion: LayersTraceSubject.() -> Unit = {
378                 this.clear()
379                 // convert LayersTraceSubject to RegionTraceSubject
380                 val regionTraceSubject =
381                         visibleRegion(components = components, useCompositionEngineRegionOnly)
382 
383                 // add assertions to the regionTraceSubject's AssertionChecker
384                 assertion(regionTraceSubject)
385                 // loop through all entries to validate assertions
386                 regionTraceSubject.forAllEntries()
387             }
388 
389             return AssertionData(tag = AssertionTag.ALL,
390                     expectedSubjectClass = LayersTraceSubject::class,
391                     assertion = closedAssertion as FlickerSubject.() -> Unit)
392         }
393 
394         @JvmStatic
395         fun buildEventLogAssertion(assertion: EventLogSubject.() -> Unit): AssertionData =
396             AssertionData(tag = AssertionTag.ALL,
397                 expectedSubjectClass = EventLogSubject::class,
398                 assertion = assertion as FlickerSubject.() -> Unit)
399 
400         fun defaultName(test: FlickerTestParameter) = buildString {
401             append(Surface.rotationToString(test.startRotation))
402             if (test.endRotation != test.startRotation) {
403                 append("_${Surface.rotationToString(test.endRotation)}")
404             }
405             if (test.navBarMode.isNotEmpty()) {
406                 append("_${test.navBarModeName}")
407             }
408         }
409     }
410 }