1 /*
2  * 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.Rect
20 import android.graphics.Region
21 import android.tools.Cache
22 import android.tools.flicker.subject.layers.LayerTraceEntrySubject
23 import android.tools.flicker.subject.layers.LayersTraceSubject
24 import android.tools.traces.component.ComponentNameMatcher
25 import android.tools.traces.component.OrComponentMatcher
26 import android.tools.utils.CleanFlickerEnvironmentRule
27 import android.tools.utils.MockLayerBuilder
28 import android.tools.utils.MockLayerTraceEntryBuilder
29 import android.tools.utils.TestComponents
30 import android.tools.utils.assertFail
31 import android.tools.utils.assertThatErrorContainsDebugInfo
32 import android.tools.utils.assertThrows
33 import android.tools.utils.getLayerTraceReaderFromAsset
34 import com.google.common.truth.Truth
35 import org.junit.Before
36 import org.junit.ClassRule
37 import org.junit.FixMethodOrder
38 import org.junit.Test
39 import org.junit.runners.MethodSorters
40 
41 /**
42  * Contains [LayerTraceEntrySubject] tests. To run this test: `atest
43  * FlickerLibTest:LayerTraceEntrySubjectTest`
44  */
45 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
46 class LayerTraceEntrySubjectTest {
47     @Before
beforenull48     fun before() {
49         Cache.clear()
50     }
51 
52     @Test
exceptionContainsDebugInfonull53     fun exceptionContainsDebugInfo() {
54         val reader = getLayerTraceReaderFromAsset("layers_trace_emptyregion.perfetto-trace")
55         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
56         val error =
57             assertThrows<AssertionError> {
58                 LayersTraceSubject(trace, reader).first().visibleRegion(TestComponents.IMAGINARY)
59             }
60         assertThatErrorContainsDebugInfo(error)
61         Truth.assertThat(error).hasMessageThat().contains(TestComponents.IMAGINARY.className)
62     }
63 
64     @Test
testCanInspectBeginningnull65     fun testCanInspectBeginning() {
66         val reader = getLayerTraceReaderFromAsset("layers_trace_launch_split_screen.perfetto-trace")
67         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
68         LayerTraceEntrySubject(trace.entries.first(), reader)
69             .isVisible(ComponentNameMatcher.NAV_BAR)
70             .notContains(TestComponents.DOCKER_STACK_DIVIDER)
71             .isVisible(TestComponents.LAUNCHER)
72     }
73 
74     @Test
testCanInspectEndnull75     fun testCanInspectEnd() {
76         val reader = getLayerTraceReaderFromAsset("layers_trace_launch_split_screen.perfetto-trace")
77         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
78         LayerTraceEntrySubject(trace.entries.last(), reader)
79             .isVisible(ComponentNameMatcher.NAV_BAR)
80             .isVisible(TestComponents.DOCKER_STACK_DIVIDER)
81     }
82 
83     // b/75276931
84     @Test
canDetectUncoveredRegionnull85     fun canDetectUncoveredRegion() {
86         val reader = getLayerTraceReaderFromAsset("layers_trace_emptyregion.perfetto-trace")
87         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
88         val expectedRegion = Region(0, 0, 1440, 2960)
89         assertFail("SkRegion((0,0,1440,1440)) should cover at least SkRegion((0,0,1440,2960))") {
90             LayersTraceSubject(trace, reader)
91                 .getEntryBySystemUpTime(935346112030, byElapsedTimestamp = true)
92                 .visibleRegion()
93                 .coversAtLeast(expectedRegion)
94         }
95     }
96 
97     // Visible region tests
98     @Test
canTestLayerVisibleRegion_layerDoesNotExistnull99     fun canTestLayerVisibleRegion_layerDoesNotExist() {
100         val reader = getLayerTraceReaderFromAsset("layers_trace_emptyregion.perfetto-trace")
101         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
102         val expectedVisibleRegion = Region(0, 0, 1, 1)
103         assertFail(TestComponents.IMAGINARY.toWindowIdentifier()) {
104             LayersTraceSubject(trace, reader)
105                 .getEntryBySystemUpTime(937229257165, byElapsedTimestamp = true)
106                 .visibleRegion(TestComponents.IMAGINARY)
107                 .coversExactly(expectedVisibleRegion)
108         }
109     }
110 
111     @Test
canTestLayerVisibleRegion_layerDoesNotHaveExpectedVisibleRegionnull112     fun canTestLayerVisibleRegion_layerDoesNotHaveExpectedVisibleRegion() {
113         val reader = getLayerTraceReaderFromAsset("layers_trace_emptyregion.perfetto-trace")
114         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
115         val expectedVisibleRegion = Region(0, 0, 1, 1)
116         assertFail("SkRegion() should cover exactly SkRegion((0,0,1,1))") {
117             LayersTraceSubject(trace, reader)
118                 .getEntryBySystemUpTime(937126074082, byElapsedTimestamp = true)
119                 .visibleRegion(TestComponents.DOCKER_STACK_DIVIDER)
120                 .coversExactly(expectedVisibleRegion)
121         }
122     }
123 
124     @Test
canTestLayerVisibleRegion_layerIsHiddenByParentnull125     fun canTestLayerVisibleRegion_layerIsHiddenByParent() {
126         val reader = getLayerTraceReaderFromAsset("layers_trace_emptyregion.perfetto-trace")
127         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
128         val expectedVisibleRegion = Region(0, 0, 1, 1)
129         assertFail("SkRegion() should cover exactly SkRegion((0,0,1,1))") {
130             LayersTraceSubject(trace, reader)
131                 .getEntryBySystemUpTime(935346112030, byElapsedTimestamp = true)
132                 .visibleRegion(TestComponents.SIMPLE_APP)
133                 .coversExactly(expectedVisibleRegion)
134         }
135     }
136 
137     @Test
canTestLayerVisibleRegion_incorrectRegionSizenull138     fun canTestLayerVisibleRegion_incorrectRegionSize() {
139         val reader = getLayerTraceReaderFromAsset("layers_trace_emptyregion.perfetto-trace")
140         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
141         val expectedVisibleRegion = Region(0, 0, 1440, 99)
142         assertFail("SkRegion((0,0,1440,171)) should cover exactly SkRegion((0,0,1440,99))") {
143             LayersTraceSubject(trace, reader)
144                 .getEntryBySystemUpTime(937126074082, byElapsedTimestamp = true)
145                 .visibleRegion(ComponentNameMatcher.STATUS_BAR)
146                 .coversExactly(expectedVisibleRegion)
147         }
148     }
149 
150     @Test
canTestLayerVisibleRegionnull151     fun canTestLayerVisibleRegion() {
152         val reader = getLayerTraceReaderFromAsset("layers_trace_launch_split_screen.perfetto-trace")
153         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
154         val expectedVisibleRegion = Region(0, 0, 1080, 145)
155         LayersTraceSubject(trace, reader)
156             .getEntryBySystemUpTime(90480846872160, byElapsedTimestamp = true)
157             .visibleRegion(ComponentNameMatcher.STATUS_BAR)
158             .coversExactly(expectedVisibleRegion)
159     }
160 
161     @Test
canTestLayerVisibleRegion_layerIsNotVisiblenull162     fun canTestLayerVisibleRegion_layerIsNotVisible() {
163         val reader =
164             getLayerTraceReaderFromAsset("layers_trace_invalid_layer_visibility.perfetto-trace")
165         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
166         assertFail("Bounds is 0x0") {
167             LayersTraceSubject(trace, reader)
168                 .getEntryBySystemUpTime(252794268378458, byElapsedTimestamp = true)
169                 .isVisible(TestComponents.SIMPLE_APP)
170         }
171     }
172 
173     @Test
orComponentMatcher_visibility_oneVisibleOtherInvisiblenull174     fun orComponentMatcher_visibility_oneVisibleOtherInvisible() {
175         val app1Name = "com.simple.test.app1"
176         val app2Name = "com.simple.test.app2"
177 
178         val layerTraceEntry =
179             MockLayerTraceEntryBuilder()
180                 .addDisplay(
181                     rootLayers =
182                         listOf(
183                             MockLayerBuilder(app1Name)
184                                 .setContainerLayer()
185                                 .addChild(MockLayerBuilder(app1Name).setVisible()),
186                             MockLayerBuilder(app2Name)
187                                 .setContainerLayer()
188                                 .addChild(MockLayerBuilder(app2Name).setInvisible()),
189                         )
190                 )
191                 .build()
192 
193         val subject = LayerTraceEntrySubject(layerTraceEntry)
194         val component =
195             OrComponentMatcher(
196                 listOf(ComponentNameMatcher(app1Name), ComponentNameMatcher(app2Name))
197             )
198 
199         subject.isVisible(ComponentNameMatcher(app1Name))
200         subject.isInvisible(ComponentNameMatcher(app2Name))
201 
202         subject.isInvisible(component)
203         subject.isVisible(component)
204     }
205 
206     @Test
orComponentMatcher_visibility_oneVisibleOtherMissingnull207     fun orComponentMatcher_visibility_oneVisibleOtherMissing() {
208         val app1Name = "com.simple.test.app1"
209         val app2Name = "com.simple.test.app2"
210 
211         val layerTraceEntry =
212             MockLayerTraceEntryBuilder()
213                 .addDisplay(
214                     rootLayers =
215                         listOf(
216                             MockLayerBuilder(app1Name)
217                                 .setContainerLayer()
218                                 .addChild(MockLayerBuilder(app1Name).setVisible())
219                         )
220                 )
221                 .build()
222 
223         val subject = LayerTraceEntrySubject(layerTraceEntry)
224         val component =
225             OrComponentMatcher(
226                 listOf(ComponentNameMatcher(app1Name), ComponentNameMatcher(app2Name))
227             )
228 
229         subject.isVisible(ComponentNameMatcher(app1Name))
230         subject.notContains(ComponentNameMatcher(app2Name))
231 
232         subject.isInvisible(component)
233         subject.isVisible(component)
234     }
235 
236     @Test
canUseOrComponentMatcher_visibility_allVisiblenull237     fun canUseOrComponentMatcher_visibility_allVisible() {
238         val app1Name = "com.simple.test.app1"
239         val app2Name = "com.simple.test.app2"
240 
241         val layerTraceEntry =
242             MockLayerTraceEntryBuilder()
243                 .addDisplay(
244                     rootLayers =
245                         listOf(
246                             MockLayerBuilder(app1Name)
247                                 .setContainerLayer()
248                                 .setAbsoluteBounds(Rect(0, 0, 200, 200))
249                                 .addChild(MockLayerBuilder("$app1Name child").setVisible()),
250                             MockLayerBuilder(app2Name)
251                                 .setContainerLayer()
252                                 .setAbsoluteBounds(Rect(200, 200, 400, 400))
253                                 .addChild(MockLayerBuilder("$app2Name child").setVisible()),
254                         )
255                 )
256                 .build()
257 
258         val subject = LayerTraceEntrySubject(layerTraceEntry)
259         val component =
260             OrComponentMatcher(
261                 listOf(ComponentNameMatcher(app1Name), ComponentNameMatcher(app2Name))
262             )
263 
264         subject.isVisible(ComponentNameMatcher(app1Name))
265         subject.isVisible(ComponentNameMatcher(app2Name))
266 
267         assertThrows<AssertionError> { subject.isInvisible(component) }
268         subject.isVisible(component)
269     }
270 
271     @Test
canUseOrComponentMatcher_contains_withOneExistsnull272     fun canUseOrComponentMatcher_contains_withOneExists() {
273         val app1Name = "com.simple.test.app1"
274         val app2Name = "com.simple.test.app2"
275 
276         val layerTraceEntry =
277             MockLayerTraceEntryBuilder()
278                 .addDisplay(
279                     rootLayers =
280                         listOf(
281                             MockLayerBuilder(app1Name)
282                                 .setContainerLayer()
283                                 .addChild(MockLayerBuilder(app1Name))
284                         )
285                 )
286                 .build()
287 
288         val subject = LayerTraceEntrySubject(layerTraceEntry)
289         val component =
290             OrComponentMatcher(
291                 listOf(ComponentNameMatcher(app1Name), ComponentNameMatcher(app2Name))
292             )
293 
294         subject.contains(ComponentNameMatcher(app1Name))
295         subject.notContains(ComponentNameMatcher(app2Name))
296 
297         subject.contains(component)
298 
299         assertFail("Found: com.simple.test.app1") { subject.notContains(component) }
300     }
301 
302     @Test
canUseOrComponentMatcher_contains_withNoneExistsnull303     fun canUseOrComponentMatcher_contains_withNoneExists() {
304         val app1Name = "com.simple.test.app1"
305         val app2Name = "com.simple.test.app2"
306 
307         val layerTraceEntry = MockLayerTraceEntryBuilder().addDisplay(rootLayers = listOf()).build()
308 
309         val subject = LayerTraceEntrySubject(layerTraceEntry)
310         val component =
311             OrComponentMatcher(
312                 listOf(ComponentNameMatcher(app1Name), ComponentNameMatcher(app2Name))
313             )
314 
315         subject.notContains(ComponentNameMatcher(app1Name))
316         subject.notContains(ComponentNameMatcher(app2Name))
317 
318         subject.notContains(component)
319         assertThrows<AssertionError> { subject.contains(component) }
320     }
321 
322     @Test
canUseOrComponentMatcher_contains_withBothExistsnull323     fun canUseOrComponentMatcher_contains_withBothExists() {
324         val app1Name = "com.simple.test.app1"
325         val app2Name = "com.simple.test.app2"
326 
327         val layerTraceEntry =
328             MockLayerTraceEntryBuilder()
329                 .addDisplay(
330                     rootLayers =
331                         listOf(
332                             MockLayerBuilder(app1Name)
333                                 .setContainerLayer()
334                                 .addChild(MockLayerBuilder(app1Name)),
335                             MockLayerBuilder(app2Name)
336                                 .setContainerLayer()
337                                 .addChild(MockLayerBuilder(app2Name)),
338                         )
339                 )
340                 .build()
341 
342         val subject = LayerTraceEntrySubject(layerTraceEntry)
343         val component =
344             OrComponentMatcher(
345                 listOf(ComponentNameMatcher(app1Name), ComponentNameMatcher(app2Name))
346             )
347 
348         subject.contains(ComponentNameMatcher(app1Name))
349         subject.contains(ComponentNameMatcher(app2Name))
350 
351         assertThrows<AssertionError> { subject.notContains(component) }
352         subject.contains(component)
353     }
354 
355     @Test
detectOccludedLayerBecauseOfRoundedCornersnull356     fun detectOccludedLayerBecauseOfRoundedCorners() {
357         val reader = getLayerTraceReaderFromAsset("layers_trace_rounded_corners.perfetto-trace")
358         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
359         val entry =
360             LayersTraceSubject(trace, reader)
361                 .getEntryBySystemUpTime(6216612368228, byElapsedTimestamp = true)
362         val defaultPkg = "com.android.server.wm.flicker.testapp"
363         val simpleActivityMatcher =
364             ComponentNameMatcher(defaultPkg, "$defaultPkg.SimpleActivity#66086")
365         val imeActivityMatcher = ComponentNameMatcher(defaultPkg, "$defaultPkg.ImeActivity#66060")
366         val simpleActivitySubject =
367             entry.layer(simpleActivityMatcher) ?: error("Layer should be available")
368         val imeActivitySubject =
369             entry.layer(imeActivityMatcher) ?: error("Layer should be available")
370         val simpleActivityLayer = simpleActivitySubject.layer
371         val imeActivityLayer = imeActivitySubject.layer
372         // both layers have the same region
373         imeActivitySubject.visibleRegion.coversExactly(simpleActivitySubject.visibleRegion.region)
374         // both are visible
375         entry.isInvisible(simpleActivityMatcher)
376         entry.isVisible(imeActivityMatcher)
377         // and simple activity is partially covered by IME activity
378         Truth.assertWithMessage("IME activity has rounded corners")
379             .that(simpleActivityLayer.occludedBy)
380             .contains(imeActivityLayer)
381         // because IME activity has rounded corners
382         Truth.assertWithMessage("IME activity has rounded corners")
383             .that(imeActivityLayer.cornerRadius)
384             .isGreaterThan(0)
385     }
386 
387     @Test
canDetectInvisibleLayerOutOfScreennull388     fun canDetectInvisibleLayerOutOfScreen() {
389         val reader =
390             getLayerTraceReaderFromAsset("layers_trace_visible_outside_bounds.perfetto-trace")
391         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
392         val subject =
393             LayersTraceSubject(trace, reader)
394                 .getEntryBySystemUpTime(1253267561044, byElapsedTimestamp = true)
395         val region = subject.visibleRegion(ComponentNameMatcher.IME_SNAPSHOT)
396         region.isEmpty()
397         subject.isInvisible(ComponentNameMatcher.IME_SNAPSHOT)
398     }
399 
400     @Test
canDetectInvisibleLayerOutOfScreen_ConsecutiveLayersnull401     fun canDetectInvisibleLayerOutOfScreen_ConsecutiveLayers() {
402         val reader =
403             getLayerTraceReaderFromAsset("layers_trace_visible_outside_bounds.perfetto-trace")
404         val trace = reader.readLayersTrace() ?: error("Unable to read layers trace")
405         val subject = LayersTraceSubject(trace, reader)
406         subject.visibleLayersShownMoreThanOneConsecutiveEntry()
407     }
408 
409     companion object {
410         @ClassRule @JvmField val ENV_CLEANUP = CleanFlickerEnvironmentRule()
411     }
412 }
413