1 /* 2 * Copyright (C) 2020 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 com.android.server.wm.traces.common.layers 18 19 import com.android.server.wm.traces.common.Buffer 20 import com.android.server.wm.traces.common.Color 21 import com.android.server.wm.traces.common.Rect 22 import com.android.server.wm.traces.common.RectF 23 import com.android.server.wm.traces.common.Region 24 import com.android.server.wm.traces.common.layers.Transform.Companion.isFlagSet 25 26 /** 27 * Represents a single layer with links to its parent and child layers. 28 * 29 * This is a generic object that is reused by both Flicker and Winscope and cannot 30 * access internal Java/Android functionality 31 * 32 **/ 33 data class Layer( 34 val name: String, 35 val id: Int, 36 val parentId: Int, 37 val z: Int, 38 val visibleRegion: Region?, 39 val activeBuffer: Buffer, 40 val flags: Int, 41 val bounds: RectF, 42 val color: Color, 43 private val _isOpaque: Boolean, 44 val shadowRadius: Float, 45 val cornerRadius: Float, 46 val type: String, 47 private val _screenBounds: RectF?, 48 val transform: Transform, 49 val sourceBounds: RectF, 50 val currFrame: Long, 51 val effectiveScalingMode: Int, 52 val bufferTransform: Transform, 53 val hwcCompositionType: Int, 54 val hwcCrop: RectF, 55 val hwcFrame: Rect, 56 val backgroundBlurRadius: Int, 57 val crop: Rect?, 58 val isRelativeOf: Boolean, 59 val zOrderRelativeOfId: Int 60 ) { 61 val stableId: String = "$type $id $name" 62 var parent: Layer? = null 63 var zOrderRelativeOf: Layer? = null 64 var zOrderRelativeParentOf: Int = 0 65 66 /** 67 * Checks if the [Layer] is a root layer in the hierarchy 68 * 69 * @return 70 */ 71 val isRootLayer: Boolean get() = parent == null 72 73 private val _children = mutableListOf<Layer>() 74 private val _occludedBy = mutableListOf<Layer>() 75 private val _partiallyOccludedBy = mutableListOf<Layer>() 76 private val _coveredBy = mutableListOf<Layer>() 77 val children: Array<Layer> 78 get() = _children.toTypedArray() 79 val occludedBy: Array<Layer> 80 get() = _occludedBy.toTypedArray() 81 val partiallyOccludedBy: Array<Layer> 82 get() = _partiallyOccludedBy.toTypedArray() 83 val coveredBy: Array<Layer> 84 get() = _coveredBy.toTypedArray() 85 var isMissing: Boolean = false 86 internal set 87 88 val isScaling: Boolean 89 get() = isTransformFlagSet(Transform.SCALE_VAL) 90 val isTranslating: Boolean 91 get() = isTransformFlagSet(Transform.TRANSLATE_VAL) 92 val isRotating: Boolean 93 get() = isTransformFlagSet(Transform.ROTATE_VAL) 94 isTransformFlagSetnull95 private fun isTransformFlagSet(transform: Int): Boolean = 96 this.transform.type?.isFlagSet(transform) ?: false 97 98 /** 99 * Checks if the layer's active buffer is empty 100 * 101 * An active buffer is empty if it is not in the proto or if its height or width are 0 102 * 103 * @return 104 */ 105 val isActiveBufferEmpty: Boolean get() = activeBuffer.isEmpty 106 107 /** 108 * Checks if the layer is hidden, that is, if its flags contain 0x1 (FLAG_HIDDEN) 109 * 110 * @return 111 */ 112 val isHiddenByPolicy: Boolean 113 get() { 114 return (flags and /* FLAG_HIDDEN */0x1) != 0x0 || 115 // offscreen layer root has a unique layer id 116 id == 0x7FFFFFFD 117 } 118 119 /** 120 * Checks if the layer is visible. 121 * 122 * A layer is visible if: 123 * - it has an active buffer or has effects 124 * - is not hidden 125 * - is not transparent 126 * - not occluded by other layers 127 * 128 * @return 129 */ 130 val isVisible: Boolean 131 get() { 132 return when { 133 isHiddenByParent -> false 134 isHiddenByPolicy -> false 135 isActiveBufferEmpty && !hasEffects -> false 136 !fillsColor -> false 137 occludedBy.isNotEmpty() -> false 138 visibleRegion?.isEmpty ?: false -> false 139 else -> !bounds.isEmpty 140 } 141 } 142 143 val isOpaque: Boolean = if (color.a != 1.0f) false else _isOpaque 144 145 /** 146 * Checks if the [Layer] has a color 147 * 148 * @return 149 */ 150 val fillsColor: Boolean get() = color.isNotEmpty 151 152 /** 153 * Checks if the [Layer] draws a shadow 154 * 155 * @return 156 */ 157 val drawsShadows: Boolean get() = shadowRadius > 0 158 159 /** 160 * Checks if the [Layer] has blur 161 * 162 * @return 163 */ 164 val hasBlur: Boolean get() = backgroundBlurRadius > 0 165 166 /** 167 * Checks if the [Layer] has rounded corners 168 * 169 * @return 170 */ 171 val hasRoundedCorners: Boolean get() = cornerRadius > 0 172 173 /** 174 * Checks if the [Layer] draws has effects, which include: 175 * - is a color layer 176 * - is an effects layers which [fillsColor] or [drawsShadows] 177 * 178 * @return 179 */ 180 val hasEffects: Boolean 181 get() { 182 // Support previous color layer 183 if (isColorLayer) { 184 return true 185 } 186 187 // Support newer effect layer 188 return isEffectLayer && (fillsColor || drawsShadows) 189 } 190 191 /** 192 * Checks if the [Layer] type is BufferStateLayer or BufferQueueLayer 193 * 194 * @return 195 */ 196 val isBufferLayer: Boolean 197 get() = type == "BufferStateLayer" || type == "BufferQueueLayer" 198 199 /** 200 * Checks if the [Layer] type is ColorLayer 201 * 202 * @return 203 */ 204 val isColorLayer: Boolean get() = type == "ColorLayer" 205 206 /** 207 * Checks if the [Layer] type is ContainerLayer 208 * 209 * @return 210 */ 211 val isContainerLayer: Boolean get() = type == "ContainerLayer" 212 213 /** 214 * Checks if the [Layer] type is EffectLayer 215 * 216 * @return 217 */ 218 val isEffectLayer: Boolean get() = type == "EffectLayer" 219 220 /** 221 * Checks if the [Layer] is hidden by its parent 222 * 223 * @return 224 */ 225 val isHiddenByParent: Boolean 226 get() = !isRootLayer && 227 (parent?.isHiddenByPolicy == true || parent?.isHiddenByParent == true) 228 229 /** 230 * Gets a description of why the layer is (in)visible 231 * 232 * @return 233 */ 234 val visibilityReason: String 235 get() { 236 return when { 237 isVisible -> "" 238 isContainerLayer -> "ContainerLayer" 239 isHiddenByPolicy -> "Flag is hidden" 240 isHiddenByParent -> "Hidden by parent ${parent?.name}" 241 isBufferLayer && isActiveBufferEmpty -> "Buffer is empty" 242 color.isEmpty -> "Alpha is 0" 243 crop?.isEmpty ?: false -> "Crop is 0x0" 244 bounds.isEmpty -> "Bounds is 0x0" 245 !transform.isValid -> "Transform is invalid" 246 isRelativeOf && zOrderRelativeOf == null -> "RelativeOf layer has been removed" 247 isEffectLayer && !fillsColor && !drawsShadows && !hasBlur -> 248 "Effect layer does not have color fill, shadow or blur" 249 _occludedBy.isNotEmpty() -> { <lambda>null250 val occludedByIds = _occludedBy.joinToString(", ") { it.id.toString() } 251 "Layer is occluded by: $occludedByIds" 252 } 253 visibleRegion?.isEmpty ?: false -> 254 "Visible region calculated by Composition Engine is empty" 255 else -> "Unknown" 256 } 257 } 258 259 val screenBounds: RectF = when { 260 visibleRegion?.isNotEmpty == true -> visibleRegion.toRectF() 261 _screenBounds != null -> _screenBounds 262 else -> transform.apply(bounds) 263 } 264 265 val absoluteZ: String 266 get() { 267 val zOrderRelativeOf = zOrderRelativeOf <lambda>null268 return buildString { 269 when { 270 zOrderRelativeOf != null -> append(zOrderRelativeOf.absoluteZ).append(",") 271 parent != null -> append(parent?.absoluteZ).append(",") 272 } 273 append(z) 274 } 275 } 276 containsnull277 fun contains(innerLayer: Layer): Boolean { 278 return if (!this.transform.isSimpleRotation || !innerLayer.transform.isSimpleRotation) { 279 false 280 } else { 281 this.screenBounds.contains(innerLayer.screenBounds) 282 } 283 } 284 addChildnull285 fun addChild(childLayer: Layer) { 286 _children.add(childLayer) 287 } 288 addOccludedBynull289 fun addOccludedBy(layers: Array<Layer>) { 290 _occludedBy.addAll(layers) 291 } 292 addPartiallyOccludedBynull293 fun addPartiallyOccludedBy(layers: Array<Layer>) { 294 _partiallyOccludedBy.addAll(layers) 295 } 296 addCoveredBynull297 fun addCoveredBy(layers: Array<Layer>) { 298 _coveredBy.addAll(layers) 299 } 300 overlapsnull301 fun overlaps(other: Layer): Boolean = 302 !this.screenBounds.intersection(other.screenBounds).isEmpty 303 304 override fun toString(): String { 305 return buildString { 306 append(name) 307 308 if (activeBuffer.isNotEmpty) { 309 append(" buffer:$activeBuffer") 310 append(" frame#$currFrame") 311 } 312 313 if (isVisible) { 314 append(" visible:$visibleRegion") 315 } 316 } 317 } 318 equalsnull319 override fun equals(other: Any?): Boolean { 320 if (this === other) return true 321 if (other !is Layer) return false 322 323 if (name != other.name) return false 324 if (id != other.id) return false 325 if (parentId != other.parentId) return false 326 if (z != other.z) return false 327 if (visibleRegion != other.visibleRegion) return false 328 if (activeBuffer != other.activeBuffer) return false 329 if (flags != other.flags) return false 330 if (bounds != other.bounds) return false 331 if (color != other.color) return false 332 if (shadowRadius != other.shadowRadius) return false 333 if (cornerRadius != other.cornerRadius) return false 334 if (type != other.type) return false 335 if (transform != other.transform) return false 336 if (sourceBounds != other.sourceBounds) return false 337 if (currFrame != other.currFrame) return false 338 if (effectiveScalingMode != other.effectiveScalingMode) return false 339 if (bufferTransform != other.bufferTransform) return false 340 if (hwcCompositionType != other.hwcCompositionType) return false 341 if (hwcCrop != other.hwcCrop) return false 342 if (hwcFrame != other.hwcFrame) return false 343 if (backgroundBlurRadius != other.backgroundBlurRadius) return false 344 if (crop != other.crop) return false 345 if (isRelativeOf != other.isRelativeOf) return false 346 if (zOrderRelativeOfId != other.zOrderRelativeOfId) return false 347 if (stableId != other.stableId) return false 348 if (parent != other.parent) return false 349 if (zOrderRelativeOf != other.zOrderRelativeOf) return false 350 if (zOrderRelativeParentOf != other.zOrderRelativeParentOf) return false 351 if (isMissing != other.isMissing) return false 352 if (isOpaque != other.isOpaque) return false 353 if (screenBounds != other.screenBounds) return false 354 355 return true 356 } 357 hashCodenull358 override fun hashCode(): Int { 359 var result = name.hashCode() 360 result = 31 * result + id 361 result = 31 * result + parentId 362 result = 31 * result + z 363 result = 31 * result + (visibleRegion?.hashCode() ?: 0) 364 result = 31 * result + activeBuffer.hashCode() 365 result = 31 * result + flags 366 result = 31 * result + bounds.hashCode() 367 result = 31 * result + color.hashCode() 368 result = 31 * result + shadowRadius.hashCode() 369 result = 31 * result + cornerRadius.hashCode() 370 result = 31 * result + type.hashCode() 371 result = 31 * result + transform.hashCode() 372 result = 31 * result + sourceBounds.hashCode() 373 result = 31 * result + currFrame.hashCode() 374 result = 31 * result + effectiveScalingMode 375 result = 31 * result + bufferTransform.hashCode() 376 result = 31 * result + hwcCompositionType 377 result = 31 * result + hwcCrop.hashCode() 378 result = 31 * result + hwcFrame.hashCode() 379 result = 31 * result + backgroundBlurRadius 380 result = 31 * result + (crop?.hashCode() ?: 0) 381 result = 31 * result + isRelativeOf.hashCode() 382 result = 31 * result + zOrderRelativeOfId 383 result = 31 * result + stableId.hashCode() 384 result = 31 * result + (parent?.hashCode() ?: 0) 385 result = 31 * result + (zOrderRelativeOf?.hashCode() ?: 0) 386 result = 31 * result + zOrderRelativeParentOf 387 result = 31 * result + isMissing.hashCode() 388 result = 31 * result + isOpaque.hashCode() 389 result = 31 * result + screenBounds.hashCode() 390 return result 391 } 392 }