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.common.flicker.subject.surfaceflinger 18 19 import android.tools.TestComponents 20 import android.tools.assertFail 21 import android.tools.assertThatErrorContainsDebugInfo 22 import android.tools.assertThrows 23 import android.tools.common.Cache 24 import android.tools.common.datatypes.Rect 25 import android.tools.common.datatypes.Region 26 import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject 27 import android.tools.common.flicker.subject.layers.LayersTraceSubject 28 import android.tools.common.traces.component.ComponentNameMatcher 29 import android.tools.common.traces.component.OrComponentMatcher 30 import android.tools.getLayerTraceReaderFromAsset 31 import android.tools.rules.CleanFlickerEnvironmentRule 32 import android.tools.utils.MockLayerBuilder 33 import android.tools.utils.MockLayerTraceEntryBuilder 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.pb", legacyTrace = true) 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 = 67 getLayerTraceReaderFromAsset("layers_trace_launch_split_screen.pb", legacyTrace = true) 68 val trace = reader.readLayersTrace() ?: error("Unable to read layers trace") 69 LayerTraceEntrySubject(trace.entries.first(), reader) 70 .isVisible(ComponentNameMatcher.NAV_BAR) 71 .notContains(TestComponents.DOCKER_STACK_DIVIDER) 72 .isVisible(TestComponents.LAUNCHER) 73 } 74 75 @Test testCanInspectEndnull76 fun testCanInspectEnd() { 77 val reader = 78 getLayerTraceReaderFromAsset("layers_trace_launch_split_screen.pb", legacyTrace = true) 79 val trace = reader.readLayersTrace() ?: error("Unable to read layers trace") 80 LayerTraceEntrySubject(trace.entries.last(), reader) 81 .isVisible(ComponentNameMatcher.NAV_BAR) 82 .isVisible(TestComponents.DOCKER_STACK_DIVIDER) 83 } 84 85 // b/75276931 86 @Test canDetectUncoveredRegionnull87 fun canDetectUncoveredRegion() { 88 val reader = getLayerTraceReaderFromAsset("layers_trace_emptyregion.pb", legacyTrace = true) 89 val trace = reader.readLayersTrace() ?: error("Unable to read layers trace") 90 val expectedRegion = Region.from(0, 0, 1440, 2960) 91 assertFail("SkRegion((0,0,1440,1440)) should cover at least SkRegion((0,0,1440,2960))") { 92 LayersTraceSubject(trace, reader) 93 .getEntryBySystemUpTime(935346112030, byElapsedTimestamp = true) 94 .visibleRegion() 95 .coversAtLeast(expectedRegion) 96 } 97 } 98 99 // Visible region tests 100 @Test canTestLayerVisibleRegion_layerDoesNotExistnull101 fun canTestLayerVisibleRegion_layerDoesNotExist() { 102 val reader = getLayerTraceReaderFromAsset("layers_trace_emptyregion.pb", legacyTrace = true) 103 val trace = reader.readLayersTrace() ?: error("Unable to read layers trace") 104 val expectedVisibleRegion = Region.from(0, 0, 1, 1) 105 assertFail(TestComponents.IMAGINARY.toWindowIdentifier()) { 106 LayersTraceSubject(trace, reader) 107 .getEntryBySystemUpTime(937229257165, byElapsedTimestamp = true) 108 .visibleRegion(TestComponents.IMAGINARY) 109 .coversExactly(expectedVisibleRegion) 110 } 111 } 112 113 @Test canTestLayerVisibleRegion_layerDoesNotHaveExpectedVisibleRegionnull114 fun canTestLayerVisibleRegion_layerDoesNotHaveExpectedVisibleRegion() { 115 val reader = getLayerTraceReaderFromAsset("layers_trace_emptyregion.pb", legacyTrace = true) 116 val trace = reader.readLayersTrace() ?: error("Unable to read layers trace") 117 val expectedVisibleRegion = Region.from(0, 0, 1, 1) 118 assertFail("[empty] should cover exactly SkRegion((0,0,1,1))") { 119 LayersTraceSubject(trace, reader) 120 .getEntryBySystemUpTime(937126074082, byElapsedTimestamp = true) 121 .visibleRegion(TestComponents.DOCKER_STACK_DIVIDER) 122 .coversExactly(expectedVisibleRegion) 123 } 124 } 125 126 @Test canTestLayerVisibleRegion_layerIsHiddenByParentnull127 fun canTestLayerVisibleRegion_layerIsHiddenByParent() { 128 val reader = getLayerTraceReaderFromAsset("layers_trace_emptyregion.pb", legacyTrace = true) 129 val trace = reader.readLayersTrace() ?: error("Unable to read layers trace") 130 val expectedVisibleRegion = Region.from(0, 0, 1, 1) 131 assertFail("[empty] should cover exactly SkRegion((0,0,1,1))") { 132 LayersTraceSubject(trace, reader) 133 .getEntryBySystemUpTime(935346112030, byElapsedTimestamp = true) 134 .visibleRegion(TestComponents.SIMPLE_APP) 135 .coversExactly(expectedVisibleRegion) 136 } 137 } 138 139 @Test canTestLayerVisibleRegion_incorrectRegionSizenull140 fun canTestLayerVisibleRegion_incorrectRegionSize() { 141 val reader = getLayerTraceReaderFromAsset("layers_trace_emptyregion.pb", legacyTrace = true) 142 val trace = reader.readLayersTrace() ?: error("Unable to read layers trace") 143 val expectedVisibleRegion = Region.from(0, 0, 1440, 99) 144 assertFail("SkRegion((0,0,1440,171)) should cover exactly SkRegion((0,0,1440,99))") { 145 LayersTraceSubject(trace, reader) 146 .getEntryBySystemUpTime(937126074082, byElapsedTimestamp = true) 147 .visibleRegion(ComponentNameMatcher.STATUS_BAR) 148 .coversExactly(expectedVisibleRegion) 149 } 150 } 151 152 @Test canTestLayerVisibleRegionnull153 fun canTestLayerVisibleRegion() { 154 val reader = 155 getLayerTraceReaderFromAsset("layers_trace_launch_split_screen.pb", legacyTrace = true) 156 val trace = reader.readLayersTrace() ?: error("Unable to read layers trace") 157 val expectedVisibleRegion = Region.from(0, 0, 1080, 145) 158 LayersTraceSubject(trace, reader) 159 .getEntryBySystemUpTime(90480846872160, byElapsedTimestamp = true) 160 .visibleRegion(ComponentNameMatcher.STATUS_BAR) 161 .coversExactly(expectedVisibleRegion) 162 } 163 164 @Test canTestLayerVisibleRegion_layerIsNotVisiblenull165 fun canTestLayerVisibleRegion_layerIsNotVisible() { 166 val reader = 167 getLayerTraceReaderFromAsset( 168 "layers_trace_invalid_layer_visibility.pb", 169 legacyTrace = true 170 ) 171 val trace = reader.readLayersTrace() ?: error("Unable to read layers trace") 172 assertFail("Bounds is 0x0") { 173 LayersTraceSubject(trace, reader) 174 .getEntryBySystemUpTime(252794268378458, byElapsedTimestamp = true) 175 .isVisible(TestComponents.SIMPLE_APP) 176 } 177 } 178 179 @Test orComponentMatcher_visibility_oneVisibleOtherInvisiblenull180 fun orComponentMatcher_visibility_oneVisibleOtherInvisible() { 181 val app1Name = "com.simple.test.app1" 182 val app2Name = "com.simple.test.app2" 183 184 val layerTraceEntry = 185 MockLayerTraceEntryBuilder() 186 .addDisplay( 187 rootLayers = 188 listOf( 189 MockLayerBuilder(app1Name) 190 .setContainerLayer() 191 .addChild(MockLayerBuilder(app1Name).setVisible()), 192 MockLayerBuilder(app2Name) 193 .setContainerLayer() 194 .addChild(MockLayerBuilder(app2Name).setInvisible()), 195 ) 196 ) 197 .build() 198 199 val subject = LayerTraceEntrySubject(layerTraceEntry) 200 val component = 201 OrComponentMatcher( 202 arrayOf(ComponentNameMatcher(app1Name), ComponentNameMatcher(app2Name)) 203 ) 204 205 subject.isVisible(ComponentNameMatcher(app1Name)) 206 subject.isInvisible(ComponentNameMatcher(app2Name)) 207 208 subject.isInvisible(component) 209 subject.isVisible(component) 210 } 211 212 @Test orComponentMatcher_visibility_oneVisibleOtherMissingnull213 fun orComponentMatcher_visibility_oneVisibleOtherMissing() { 214 val app1Name = "com.simple.test.app1" 215 val app2Name = "com.simple.test.app2" 216 217 val layerTraceEntry = 218 MockLayerTraceEntryBuilder() 219 .addDisplay( 220 rootLayers = 221 listOf( 222 MockLayerBuilder(app1Name) 223 .setContainerLayer() 224 .addChild(MockLayerBuilder(app1Name).setVisible()) 225 ) 226 ) 227 .build() 228 229 val subject = LayerTraceEntrySubject(layerTraceEntry) 230 val component = 231 OrComponentMatcher( 232 arrayOf(ComponentNameMatcher(app1Name), ComponentNameMatcher(app2Name)) 233 ) 234 235 subject.isVisible(ComponentNameMatcher(app1Name)) 236 subject.notContains(ComponentNameMatcher(app2Name)) 237 238 subject.isInvisible(component) 239 subject.isVisible(component) 240 } 241 242 @Test canUseOrComponentMatcher_visibility_allVisiblenull243 fun canUseOrComponentMatcher_visibility_allVisible() { 244 val app1Name = "com.simple.test.app1" 245 val app2Name = "com.simple.test.app2" 246 247 val layerTraceEntry = 248 MockLayerTraceEntryBuilder() 249 .addDisplay( 250 rootLayers = 251 listOf( 252 MockLayerBuilder(app1Name) 253 .setContainerLayer() 254 .setAbsoluteBounds(Rect.from(0, 0, 200, 200)) 255 .addChild(MockLayerBuilder("$app1Name child").setVisible()), 256 MockLayerBuilder(app2Name) 257 .setContainerLayer() 258 .setAbsoluteBounds(Rect.from(200, 200, 400, 400)) 259 .addChild(MockLayerBuilder("$app2Name child").setVisible()), 260 ) 261 ) 262 .build() 263 264 val subject = LayerTraceEntrySubject(layerTraceEntry) 265 val component = 266 OrComponentMatcher( 267 arrayOf(ComponentNameMatcher(app1Name), ComponentNameMatcher(app2Name)) 268 ) 269 270 subject.isVisible(ComponentNameMatcher(app1Name)) 271 subject.isVisible(ComponentNameMatcher(app2Name)) 272 273 assertThrows<AssertionError> { subject.isInvisible(component) } 274 subject.isVisible(component) 275 } 276 277 @Test canUseOrComponentMatcher_contains_withOneExistsnull278 fun canUseOrComponentMatcher_contains_withOneExists() { 279 val app1Name = "com.simple.test.app1" 280 val app2Name = "com.simple.test.app2" 281 282 val layerTraceEntry = 283 MockLayerTraceEntryBuilder() 284 .addDisplay( 285 rootLayers = 286 listOf( 287 MockLayerBuilder(app1Name) 288 .setContainerLayer() 289 .addChild(MockLayerBuilder(app1Name)) 290 ) 291 ) 292 .build() 293 294 val subject = LayerTraceEntrySubject(layerTraceEntry) 295 val component = 296 OrComponentMatcher( 297 arrayOf(ComponentNameMatcher(app1Name), ComponentNameMatcher(app2Name)) 298 ) 299 300 subject.contains(ComponentNameMatcher(app1Name)) 301 subject.notContains(ComponentNameMatcher(app2Name)) 302 303 subject.contains(component) 304 305 assertFail("Found: com.simple.test.app1") { subject.notContains(component) } 306 } 307 308 @Test canUseOrComponentMatcher_contains_withNoneExistsnull309 fun canUseOrComponentMatcher_contains_withNoneExists() { 310 val app1Name = "com.simple.test.app1" 311 val app2Name = "com.simple.test.app2" 312 313 val layerTraceEntry = MockLayerTraceEntryBuilder().addDisplay(rootLayers = listOf()).build() 314 315 val subject = LayerTraceEntrySubject(layerTraceEntry) 316 val component = 317 OrComponentMatcher( 318 arrayOf(ComponentNameMatcher(app1Name), ComponentNameMatcher(app2Name)) 319 ) 320 321 subject.notContains(ComponentNameMatcher(app1Name)) 322 subject.notContains(ComponentNameMatcher(app2Name)) 323 324 subject.notContains(component) 325 assertThrows<AssertionError> { subject.contains(component) } 326 } 327 328 @Test canUseOrComponentMatcher_contains_withBothExistsnull329 fun canUseOrComponentMatcher_contains_withBothExists() { 330 val app1Name = "com.simple.test.app1" 331 val app2Name = "com.simple.test.app2" 332 333 val layerTraceEntry = 334 MockLayerTraceEntryBuilder() 335 .addDisplay( 336 rootLayers = 337 listOf( 338 MockLayerBuilder(app1Name) 339 .setContainerLayer() 340 .addChild(MockLayerBuilder(app1Name)), 341 MockLayerBuilder(app2Name) 342 .setContainerLayer() 343 .addChild(MockLayerBuilder(app2Name)), 344 ) 345 ) 346 .build() 347 348 val subject = LayerTraceEntrySubject(layerTraceEntry) 349 val component = 350 OrComponentMatcher( 351 arrayOf(ComponentNameMatcher(app1Name), ComponentNameMatcher(app2Name)) 352 ) 353 354 subject.contains(ComponentNameMatcher(app1Name)) 355 subject.contains(ComponentNameMatcher(app2Name)) 356 357 assertThrows<AssertionError> { subject.notContains(component) } 358 subject.contains(component) 359 } 360 361 @Test detectOccludedLayerBecauseOfRoundedCornersnull362 fun detectOccludedLayerBecauseOfRoundedCorners() { 363 val reader = getLayerTraceReaderFromAsset("layers_trace_rounded_corners.winscope") 364 val trace = reader.readLayersTrace() ?: error("Unable to read layers trace") 365 val entry = 366 LayersTraceSubject(trace, reader) 367 .getEntryBySystemUpTime(6216612368228, byElapsedTimestamp = true) 368 val defaultPkg = "com.android.server.wm.flicker.testapp" 369 val simpleActivityMatcher = 370 ComponentNameMatcher(defaultPkg, "$defaultPkg.SimpleActivity#66086") 371 val imeActivityMatcher = ComponentNameMatcher(defaultPkg, "$defaultPkg.ImeActivity#66060") 372 val simpleActivitySubject = 373 entry.layer(simpleActivityMatcher) ?: error("Layer should be available") 374 val imeActivitySubject = 375 entry.layer(imeActivityMatcher) ?: error("Layer should be available") 376 val simpleActivityLayer = simpleActivitySubject.layer 377 val imeActivityLayer = imeActivitySubject.layer 378 // both layers have the same region 379 imeActivitySubject.visibleRegion.coversExactly(simpleActivitySubject.visibleRegion.region) 380 // both are visible 381 entry.isInvisible(simpleActivityMatcher) 382 entry.isVisible(imeActivityMatcher) 383 // and simple activity is partially covered by IME activity 384 Truth.assertWithMessage("IME activity has rounded corners") 385 .that(simpleActivityLayer.occludedBy) 386 .asList() 387 .contains(imeActivityLayer) 388 // because IME activity has rounded corners 389 Truth.assertWithMessage("IME activity has rounded corners") 390 .that(imeActivityLayer.cornerRadius) 391 .isGreaterThan(0) 392 } 393 394 companion object { 395 @ClassRule @JvmField val ENV_CLEANUP = CleanFlickerEnvironmentRule() 396 } 397 } 398