1 /*
<lambda>null2  * Copyright (C) 2023 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 android.tools.flicker.subject.surfaceflinger
18 
19 import android.graphics.Region
20 import android.tools.Cache
21 import android.tools.CleanFlickerEnvironmentRuleWithDataStore
22 import android.tools.ScenarioBuilder
23 import android.tools.Timestamps
24 import android.tools.flicker.legacy.LegacyFlickerTest
25 import android.tools.flicker.subject.layers.LayersTraceSubject
26 import android.tools.flicker.subject.region.RegionSubject
27 import android.tools.io.Reader
28 import android.tools.traces.component.ComponentNameMatcher
29 import android.tools.traces.io.IResultData
30 import android.tools.utils.TestComponents
31 import android.tools.utils.assertFail
32 import android.tools.utils.assertThatErrorContainsDebugInfo
33 import android.tools.utils.assertThrows
34 import android.tools.utils.getLayerTraceReaderFromAsset
35 import androidx.test.filters.FlakyTest
36 import com.google.common.truth.Truth
37 import org.junit.Before
38 import org.junit.ClassRule
39 import org.junit.FixMethodOrder
40 import org.junit.Test
41 import org.junit.runners.MethodSorters
42 import org.mockito.Mockito
43 
44 /**
45  * Contains [LayersTraceSubject] tests. To run this test: `atest
46  * FlickerLibTest:LayersTraceSubjectTest`
47  */
48 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
49 class LayersTraceSubjectTest {
50     @Before
51     fun before() {
52         Cache.clear()
53     }
54 
55     @Test
56     fun exceptionContainsDebugInfo() {
57         val reader = getLayerTraceReaderFromAsset("layers_trace_launch_split_screen.perfetto-trace")
58         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
59         val error = assertThrows<AssertionError> { LayersTraceSubject(trace, reader).isEmpty() }
60         assertThatErrorContainsDebugInfo(error)
61     }
62 
63     @Test
64     fun testCanDetectEmptyRegionFromLayerTrace() {
65         val reader = getLayerTraceReaderFromAsset("layers_trace_emptyregion.perfetto-trace")
66         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
67         assertFail("SkRegion((0,0,1440,1440)) should cover at least SkRegion((0,0,1440,2880))") {
68             LayersTraceSubject(trace, reader)
69                 .visibleRegion()
70                 .coversAtLeast(DISPLAY_REGION)
71                 .forAllEntries()
72             error("Assertion should not have passed")
73         }
74     }
75 
76     @Test
77     fun testCanInspectBeginning() {
78         val reader = getLayerTraceReaderFromAsset("layers_trace_launch_split_screen.perfetto-trace")
79         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
80         LayersTraceSubject(trace, reader)
81             .first()
82             .isVisible(ComponentNameMatcher.NAV_BAR)
83             .notContains(TestComponents.DOCKER_STACK_DIVIDER)
84             .isVisible(TestComponents.LAUNCHER)
85     }
86 
87     @Test
88     fun testCanInspectEnd() {
89         val reader = getLayerTraceReaderFromAsset("layers_trace_launch_split_screen.perfetto-trace")
90         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
91         LayersTraceSubject(trace, reader)
92             .last()
93             .isVisible(ComponentNameMatcher.NAV_BAR)
94             .isVisible(TestComponents.DOCKER_STACK_DIVIDER)
95     }
96 
97     @Test
98     fun testAssertionsOnRange() {
99         val reader = getLayerTraceReaderFromAsset("layers_trace_launch_split_screen.perfetto-trace")
100         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
101 
102         LayersTraceSubject(trace, reader)
103             .isVisible(ComponentNameMatcher.NAV_BAR)
104             .isInvisible(TestComponents.DOCKER_STACK_DIVIDER)
105             .forSystemUpTimeRange(90480846872160L, 90480994138424L)
106 
107         LayersTraceSubject(trace, reader)
108             .isVisible(ComponentNameMatcher.NAV_BAR)
109             .isVisible(TestComponents.DOCKER_STACK_DIVIDER)
110             .forSystemUpTimeRange(90491795074136L, 90493757372977L)
111     }
112 
113     @Test
114     fun testCanDetectChangingAssertions() {
115         val reader = getLayerTraceReaderFromAsset("layers_trace_launch_split_screen.perfetto-trace")
116         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
117         LayersTraceSubject(trace, reader)
118             .isVisible(ComponentNameMatcher.NAV_BAR)
119             .notContains(TestComponents.DOCKER_STACK_DIVIDER)
120             .then()
121             .isVisible(ComponentNameMatcher.NAV_BAR)
122             .isInvisible(TestComponents.DOCKER_STACK_DIVIDER)
123             .then()
124             .isVisible(ComponentNameMatcher.NAV_BAR)
125             .isVisible(TestComponents.DOCKER_STACK_DIVIDER)
126             .forAllEntries()
127     }
128 
129     @FlakyTest
130     @Test
131     fun testCanDetectIncorrectVisibilityFromLayerTrace() {
132         val reader =
133             getLayerTraceReaderFromAsset("layers_trace_invalid_layer_visibility.perfetto-trace")
134         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
135         val error =
136             assertThrows<AssertionError> {
137                 LayersTraceSubject(trace, reader)
138                     .isVisible(TestComponents.SIMPLE_APP)
139                     .then()
140                     .isInvisible(TestComponents.SIMPLE_APP)
141                     .forAllEntries()
142             }
143 
144         Truth.assertThat(error)
145             .hasMessageThat()
146             .contains("layers_trace_invalid_layer_visibility.perfetto-trace")
147         Truth.assertThat(error).hasMessageThat().contains("2d22h13m14s303ms")
148         Truth.assertThat(error).hasMessageThat().contains("!isVisible")
149         Truth.assertThat(error)
150             .hasMessageThat()
151             .contains(
152                 "com.android.server.wm.flicker.testapp/" +
153                     "com.android.server.wm.flicker.testapp.SimpleActivity#0 is visible"
154             )
155     }
156 
157     @Test
158     fun testCanDetectInvalidVisibleLayerForMoreThanOneConsecutiveEntry() {
159         val reader =
160             getLayerTraceReaderFromAsset("layers_trace_invalid_visible_layers.perfetto-trace")
161         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
162         val error =
163             assertThrows<AssertionError> {
164                 LayersTraceSubject(trace, reader)
165                     .visibleLayersShownMoreThanOneConsecutiveEntry()
166                     .forAllEntries()
167                 error("Assertion should not have passed")
168             }
169 
170         Truth.assertThat(error).hasMessageThat().contains("2d18h35m56s397ms")
171         Truth.assertThat(error).hasMessageThat().contains("StatusBar#0")
172         Truth.assertThat(error).hasMessageThat().contains("is not visible for 2 entries")
173     }
174 
175     private fun testCanDetectVisibleLayersMoreThanOneConsecutiveEntry(reader: Reader) {
176         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
177         LayersTraceSubject(trace, reader)
178             .visibleLayersShownMoreThanOneConsecutiveEntry()
179             .forAllEntries()
180     }
181 
182     @Test
183     fun testCanDetectVisibleLayersMoreThanOneConsecutiveEntry() {
184         testCanDetectVisibleLayersMoreThanOneConsecutiveEntry(
185             getLayerTraceReaderFromAsset("layers_trace_snapshot_visible.perfetto-trace")
186         )
187     }
188 
189     @Test
190     fun testCanIgnoreLayerEqualNameInVisibleLayersMoreThanOneConsecutiveEntry() {
191         val reader =
192             getLayerTraceReaderFromAsset("layers_trace_invalid_visible_layers.perfetto-trace")
193         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
194         LayersTraceSubject(trace, reader)
195             .visibleLayersShownMoreThanOneConsecutiveEntry(listOf(ComponentNameMatcher.STATUS_BAR))
196             .forAllEntries()
197     }
198 
199     @Test
200     fun testCanIgnoreLayerShorterNameInVisibleLayersMoreThanOneConsecutiveEntry() {
201         val reader = getLayerTraceReaderFromAsset("one_visible_layer_launcher_trace.perfetto-trace")
202         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
203         val launcherComponent =
204             ComponentNameMatcher(
205                 "com.google.android.apps.nexuslauncher",
206                 "com.google.android.apps.nexuslauncher.NexusLauncherActivity#1"
207             )
208         LayersTraceSubject(trace, reader)
209             .visibleLayersShownMoreThanOneConsecutiveEntry(listOf(launcherComponent))
210             .forAllEntries()
211     }
212 
213     private fun detectRootLayer(fileName: String) {
214         val reader = getLayerTraceReaderFromAsset(fileName)
215         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
216         for (entry in trace.entries) {
217             val rootLayers = entry.children
218             Truth.assertWithMessage("Does not have any root layer")
219                 .that(rootLayers.size)
220                 .isGreaterThan(0)
221             val firstParentId = rootLayers.first().parentId
222             Truth.assertWithMessage("Has multiple root layers")
223                 .that(rootLayers.all { it.parentId == firstParentId })
224                 .isTrue()
225         }
226     }
227 
228     @Test
229     fun testCanDetectRootLayer() {
230         detectRootLayer("layers_trace_root.perfetto-trace")
231     }
232 
233     @Test
234     fun testCanDetectRootLayerAOSP() {
235         detectRootLayer("layers_trace_root_aosp.perfetto-trace")
236     }
237 
238     @Test
239     fun canTestLayerOccludedBySplashScreenLayerIsNotVisible() {
240         val reader = getLayerTraceReaderFromAsset("layers_trace_occluded.perfetto-trace")
241         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
242         val entry =
243             LayersTraceSubject(trace, reader)
244                 .getEntryBySystemUpTime(1700382131522L, byElapsedTimestamp = true)
245         entry.isInvisible(TestComponents.SIMPLE_APP)
246         entry.isVisible(ComponentNameMatcher.SPLASH_SCREEN)
247     }
248 
249     @Test
250     fun testCanDetectLayerExpanding() {
251         val reader = getLayerTraceReaderFromAsset("layers_trace_openchrome.perfetto-trace")
252         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
253         val animation =
254             LayersTraceSubject(trace, reader).layers("animation-leash of app_transition#0")
255         // Obtain the area of each layer and checks if the next area is
256         // greater or equal to the previous one
257         val areas =
258             animation.map {
259                 val region = it.layer.visibleRegion ?: Region()
260                 val bounds = region.bounds
261                 val area = bounds.width() * bounds.height()
262                 area
263             }
264         val expanding = areas.zipWithNext { currentArea, nextArea -> nextArea >= currentArea }
265 
266         Truth.assertWithMessage("Animation leash should be expanding")
267             .that(expanding.all { it })
268             .isTrue()
269     }
270 
271     @Test
272     fun checkVisibleRegionAppMinusPipLayer() {
273         val reader = getLayerTraceReaderFromAsset("layers_trace_pip_wmshell.perfetto-trace")
274         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
275         val subject = LayersTraceSubject(trace, reader).last()
276 
277         try {
278             subject.visibleRegion(TestComponents.FIXED_APP).coversExactly(DISPLAY_REGION_ROTATED)
279             error(
280                 "Layer is partially covered by a Pip layer and should not cover the device screen"
281             )
282         } catch (e: AssertionError) {
283             val pipRegion = subject.visibleRegion(TestComponents.PIP_APP).region
284             val expectedWithoutPip = DISPLAY_REGION_ROTATED.minus(pipRegion)
285             subject.visibleRegion(TestComponents.FIXED_APP).coversExactly(expectedWithoutPip)
286         }
287     }
288 
289     @Test
290     fun checkVisibleRegionAppPlusPipLayer() {
291         val reader = getLayerTraceReaderFromAsset("layers_trace_pip_wmshell.perfetto-trace")
292         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
293         val subject = LayersTraceSubject(trace, reader).last()
294         val pipRegion = subject.visibleRegion(TestComponents.PIP_APP).region
295         subject
296             .visibleRegion(TestComponents.FIXED_APP)
297             .plus(pipRegion)
298             .coversExactly(DISPLAY_REGION_ROTATED)
299     }
300 
301     @Test
302     fun checkCanDetectSplashScreen() {
303         val reader = getLayerTraceReaderFromAsset("layers_trace_splashscreen.perfetto-trace")
304         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
305         LayersTraceSubject(trace, reader)
306             .isVisible(TestComponents.LAUNCHER)
307             .then()
308             .isSplashScreenVisibleFor(TestComponents.SIMPLE_APP, isOptional = false)
309             .then()
310             .isVisible(TestComponents.SIMPLE_APP)
311             .forAllEntries()
312 
313         assertFail("SimpleActivity# should be visible") {
314             LayersTraceSubject(trace, reader)
315                 .isVisible(TestComponents.LAUNCHER)
316                 .then()
317                 .isVisible(TestComponents.SIMPLE_APP)
318                 .forAllEntries()
319         }
320     }
321 
322     @Test
323     fun checkCanDetectMissingSplashScreen() {
324         val reader = getLayerTraceReaderFromAsset("layers_trace_splashscreen.perfetto-trace")
325         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
326 
327         // No splashscreen because no matching activity record
328         assertFail("SimpleActivity# should exist") {
329             LayersTraceSubject(trace, reader)
330                 .first()
331                 .isSplashScreenVisibleFor(TestComponents.SIMPLE_APP)
332         }
333     }
334 
335     @Test
336     fun snapshotStartingWindowLayerCoversExactlyApp() {
337         val reader =
338             getLayerTraceReaderFromAsset(
339                 "layers_trace_snapshotStartingWindowLayerCoversExactlyApp.perfetto-trace",
340                 from = Timestamps.from(systemUptimeNanos = 1688243428961872440),
341                 to = Timestamps.from(systemUptimeNanos = 1688243432147782644)
342             )
343         val component =
344             ComponentNameMatcher(FLICKER_APP_PACKAGE, "$FLICKER_APP_PACKAGE.ImeActivity")
345         val builder = ScenarioBuilder()
346         val flicker = LegacyFlickerTest(builder, { _ -> reader })
347         val scenario = flicker.initialize("test")
348         val result = Mockito.mock(IResultData::class.java)
349         android.tools.flicker.datastore.DataStore.addResult(scenario, result)
350         flicker.assertLayers {
351             invoke("snapshotStartingWindowLayerCoversExactlyOnApp") {
352                 val snapshotLayers =
353                     it.subjects.filter { subject ->
354                         ComponentNameMatcher.SNAPSHOT.layerMatchesAnyOf(subject.layer) &&
355                             subject.isVisible
356                     }
357                 val visibleAreas =
358                     snapshotLayers.mapNotNull { snapshotLayer -> snapshotLayer.layer.visibleRegion }
359                 val snapshotRegion = RegionSubject(visibleAreas, timestamp)
360                 // Verify the size of snapshotRegion covers appVisibleRegion exactly in animation.
361                 if (!snapshotRegion.region.isEmpty) {
362                     val appVisibleRegion = it.visibleRegion(component)
363                     snapshotRegion.coversExactly(appVisibleRegion.region)
364                 }
365             }
366         }
367     }
368 
369     companion object {
370         private const val LABEL = "ImeActivity"
371         private const val FLICKER_APP_PACKAGE = "com.android.server.wm.flicker.testapp"
372 
373         private val DISPLAY_REGION = Region(0, 0, 1440, 2880)
374         private val DISPLAY_REGION_ROTATED = Region(0, 0, 2160, 1080)
375 
376         @ClassRule @JvmField val ENV_CLEANUP = CleanFlickerEnvironmentRuleWithDataStore()
377 
378         private fun Region.minus(other: Region): Region {
379             val thisRegion = Region(this)
380             thisRegion.op(other, Region.Op.XOR)
381             return thisRegion
382         }
383     }
384 }
385