• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * 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 package com.android.server.wm.flicker.traces.layers
17 
18 import android.graphics.Point
19 import com.android.server.wm.flicker.assertions.Assertion
20 import com.android.server.wm.flicker.assertions.FlickerSubject
21 import com.android.server.wm.flicker.traces.FlickerFailureStrategy
22 import com.android.server.wm.flicker.traces.region.RegionSubject
23 import com.android.server.wm.traces.common.Size
24 import com.android.server.wm.traces.common.layers.Layer
25 import com.google.common.truth.Fact
26 import com.google.common.truth.FailureMetadata
27 import com.google.common.truth.FailureStrategy
28 import com.google.common.truth.StandardSubjectBuilder
29 import com.google.common.truth.Subject.Factory
30 
31 /**
32  * Truth subject for [Layer] objects, used to make assertions over behaviors that occur on a
33  * single layer of a SurfaceFlinger state.
34  *
35  * To make assertions over a layer from a state it is recommended to create a subject
36  * using [LayerTraceEntrySubject.layer](layerName)
37  *
38  * Alternatively, it is also possible to use [LayerSubject.assertThat](myLayer) or
39  * Truth.assertAbout([LayerSubject.getFactory]), however they will provide less debug
40  * information because it uses Truth's default [FailureStrategy].
41  *
42  * Example:
43  *    val trace = LayersTraceParser.parseFromTrace(myTraceFile)
44  *    val subject = LayersTraceSubject.assertThat(trace).first()
45  *        .layer("ValidLayer")
46  *        .exists()
47  *        .hasBufferSize(BUFFER_SIZE)
48  *        .invoke { myCustomAssertion(this) }
49  */
50 class LayerSubject private constructor(
51     fm: FailureMetadata,
52     override val parent: FlickerSubject,
53     override val timestamp: Long,
54     val layer: Layer?,
55     private val layerName: String? = null
56 ) : FlickerSubject(fm, layer) {
57     val isEmpty: Boolean get() = layer == null
58     val isNotEmpty: Boolean get() = !isEmpty
59     val isVisible: Boolean get() = layer?.isVisible == true
60     val isInvisible: Boolean get() = layer?.isVisible == false
61     val name: String get() = layer?.name ?: ""
62 
63     /**
64      * Visible region calculated by the Composition Engine
65      */
66     val visibleRegion: RegionSubject get() =
67         RegionSubject.assertThat(layer?.visibleRegion, this, timestamp)
68 
69     /**
70      * Visible region calculated by the Composition Engine (when available) or calculated
71      * based on the layer bounds and transform
72      */
73     val screenBounds: RegionSubject get() =
74         RegionSubject.assertThat(layer?.screenBounds, this, timestamp)
75 
76     override val selfFacts = if (layer != null) {
77         listOf(Fact.fact("Frame", layer.currFrame), Fact.fact("Layer", layer.name))
78     } else {
79         listOf(Fact.fact("Layer name", layerName))
80     }
81 
82     /**
83      * If the [layer] exists, executes a custom [assertion] on the current subject
84      */
85     operator fun invoke(assertion: Assertion<Layer>): LayerSubject = apply {
86         layer ?: return exists()
87         assertion(this.layer)
88     }
89 
90     /**
91      * Asserts that current subject doesn't exist in the layer hierarchy
92      */
93     fun doesNotExist(): LayerSubject = apply {
94         check("doesNotExist").that(layer).isNull()
95     }
96 
97     /**
98      * Asserts that current subject exists in the layer hierarchy
99      */
100     fun exists(): LayerSubject = apply {
101         check("$layerName does not exists").that(layer).isNotNull()
102     }
103 
104     @Deprecated("Prefer hasBufferSize(bounds)")
105     fun hasBufferSize(size: Point): LayerSubject = apply {
106         val bounds = Size(size.x, size.y)
107         hasBufferSize(bounds)
108     }
109 
110     /**
111      * Asserts that current subject has an [Layer.activeBuffer] with width equals to [Point.x]
112      * and height equals to [Point.y]
113      *
114      * @param size expected buffer size
115      */
116     fun hasBufferSize(size: Size): LayerSubject = apply {
117         layer ?: return exists()
118         val bufferSize = Size(layer.activeBuffer.width, layer.activeBuffer.height)
119         check("Incorrect buffer size").that(bufferSize).isEqualTo(size)
120     }
121 
122     /**
123      * Asserts that current subject has an [Layer.screenBounds] with width equals to [Point.x]
124      * and height equals to [Point.y]
125      *
126      * @param size expected layer bounds size
127      */
128     fun hasLayerSize(size: Point): LayerSubject = apply {
129         layer ?: return exists()
130         val layerSize = Point(layer.screenBounds.width.toInt(), layer.screenBounds.height.toInt())
131         check("Incorrect number of layers").that(layerSize).isEqualTo(size)
132     }
133 
134     /**
135      * Asserts that current subject has an [Layer.effectiveScalingMode] equals to
136      * [expectedScalingMode]
137      */
138     fun hasScalingMode(expectedScalingMode: Int): LayerSubject = apply {
139         layer ?: return exists()
140         val actualScalingMode = layer.effectiveScalingMode
141         check("Incorrect scaling mode").that(actualScalingMode).isEqualTo(expectedScalingMode)
142     }
143 
144     /**
145      * Asserts that current subject has an [Layer.bufferTransform] orientation equals to
146      * [expectedOrientation]
147      */
148     fun hasBufferOrientation(expectedOrientation: Int): LayerSubject = apply {
149         layer ?: return exists()
150         // see Transform::getOrientation
151         val bufferTransformType = layer.bufferTransform.type ?: 0
152         val actualOrientation = (bufferTransformType shr 8) and 0xFF
153         check("hasBufferTransformOrientation()")
154                 .that(actualOrientation).isEqualTo(expectedOrientation)
155     }
156 
157     override fun toString(): String {
158         return "Layer:${layer?.name} frame#${layer?.currFrame}"
159     }
160 
161     companion object {
162         /**
163          * Boiler-plate Subject.Factory for LayerSubject
164          */
165         @JvmStatic
166         fun getFactory(parent: FlickerSubject, timestamp: Long, name: String?) =
167             Factory { fm: FailureMetadata, subject: Layer? ->
168                 LayerSubject(fm, parent, timestamp, subject, name)
169             }
170 
171         /**
172          * User-defined parent point for existing layers
173          */
174         @JvmStatic
175         fun assertThat(
176             layer: Layer?,
177             parent: FlickerSubject,
178             timestamp: Long
179         ): LayerSubject {
180             val strategy = FlickerFailureStrategy()
181             val subject = StandardSubjectBuilder.forCustomFailureStrategy(strategy)
182                 .about(getFactory(parent, timestamp, name = null))
183                 .that(layer) as LayerSubject
184             strategy.init(subject)
185             return subject
186         }
187 
188         /**
189          * User-defined parent point for non existing layers
190          */
191         @JvmStatic
192         internal fun assertThat(
193             name: String,
194             parent: FlickerSubject,
195             timestamp: Long
196         ): LayerSubject {
197             val strategy = FlickerFailureStrategy()
198             val subject = StandardSubjectBuilder.forCustomFailureStrategy(strategy)
199                 .about(getFactory(parent, timestamp, name))
200                 .that(null) as LayerSubject
201             strategy.init(subject)
202             return subject
203         }
204     }
205 }