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