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 17 package com.android.server.wm.traces.common.layers 18 19 import com.android.server.wm.traces.common.ITraceEntry 20 import com.android.server.wm.traces.common.prettyTimestamp 21 22 /** 23 * Represents a single Layer trace entry. 24 * 25 * This is a generic object that is reused by both Flicker and Winscope and cannot 26 * access internal Java/Android functionality 27 * 28 **/ 29 open class LayerTraceEntry constructor( 30 override val timestamp: Long, 31 val hwcBlob: String, 32 val where: String, 33 val displays: Array<Display>, 34 _rootLayers: Array<Layer> 35 ) : ITraceEntry { 36 val isVisible = true 37 val stableId: String get() = this::class.simpleName ?: error("Unable to determine class") 38 val name: String get() = prettyTimestamp(timestamp) 39 40 val flattenedLayers: Array<Layer> = fillFlattenedLayers(_rootLayers) 41 val children: Array<Layer> get() = flattenedLayers.filter { it.isRootLayer }.toTypedArray() 42 43 private fun fillFlattenedLayers(rootLayers: Array<Layer>): Array<Layer> { 44 val opaqueLayers = mutableListOf<Layer>() 45 val transparentLayers = mutableListOf<Layer>() 46 val layers = mutableListOf<Layer>() 47 val roots = rootLayers.fillOcclusionState( 48 opaqueLayers, transparentLayers).toMutableList() 49 while (roots.isNotEmpty()) { 50 val layer = roots.removeAt(0) 51 layers.add(layer) 52 roots.addAll(layer.children) 53 } 54 return layers.toTypedArray() 55 } 56 57 private fun Array<Layer>.topDownTraversal(): List<Layer> { 58 return this 59 .sortedBy { it.z } 60 .flatMap { it.topDownTraversal() } 61 } 62 63 val visibleLayers: Array<Layer> 64 get() = flattenedLayers.filter { it.isVisible }.toTypedArray() 65 66 private fun Layer.topDownTraversal(): List<Layer> { 67 val traverseList = mutableListOf(this) 68 69 this.children.sortedBy { it.z } 70 .forEach { childLayer -> 71 traverseList.addAll(childLayer.topDownTraversal()) 72 } 73 74 return traverseList 75 } 76 77 private fun Array<Layer>.fillOcclusionState( 78 opaqueLayers: MutableList<Layer>, 79 transparentLayers: MutableList<Layer> 80 ): Array<Layer> { 81 val traversalList = topDownTraversal().reversed() 82 83 traversalList.forEach { layer -> 84 val visible = layer.isVisible 85 86 if (visible) { 87 val occludedBy = opaqueLayers 88 .filter { it.contains(layer) && !it.hasRoundedCorners }.toTypedArray() 89 layer.addOccludedBy(occludedBy) 90 val partiallyOccludedBy = opaqueLayers 91 .filter { it.overlaps(layer) && it !in layer.occludedBy } 92 .toTypedArray() 93 layer.addPartiallyOccludedBy(partiallyOccludedBy) 94 val coveredBy = transparentLayers.filter { it.overlaps(layer) }.toTypedArray() 95 layer.addCoveredBy(coveredBy) 96 97 if (layer.isOpaque) { 98 opaqueLayers.add(layer) 99 } else { 100 transparentLayers.add(layer) 101 } 102 } 103 } 104 105 return this 106 } 107 108 fun getLayerWithBuffer(name: String): Layer? { 109 return flattenedLayers.firstOrNull { 110 it.name.contains(name) && it.activeBuffer.isNotEmpty 111 } 112 } 113 114 fun getLayerById(layerId: Int): Layer? = this.flattenedLayers.firstOrNull { it.id == layerId } 115 116 /** 117 * Checks the transform of any layer is not a simple rotation 118 */ 119 fun isAnimating(windowName: String = ""): Boolean { 120 val layers = visibleLayers.filter { it.name.contains(windowName) } 121 return layers.any { layer -> !layer.transform.isSimpleRotation } 122 } 123 124 /** 125 * Check if at least one window which matches provided window name is visible. 126 */ 127 fun isVisible(windowName: String): Boolean = 128 visibleLayers.any { it.name.contains(windowName) } 129 130 fun asTrace(): LayersTrace = LayersTrace(arrayOf(this), source = "") 131 132 override fun toString(): String { 133 return "${prettyTimestamp(timestamp)} (timestamp=$timestamp)" 134 } 135 136 override fun equals(other: Any?): Boolean { 137 return other is LayerTraceEntry && other.timestamp == this.timestamp 138 } 139 140 override fun hashCode(): Int { 141 var result = timestamp.hashCode() 142 result = 31 * result + hwcBlob.hashCode() 143 result = 31 * result + where.hashCode() 144 result = 31 * result + displays.contentHashCode() 145 result = 31 * result + isVisible.hashCode() 146 result = 31 * result + flattenedLayers.contentHashCode() 147 return result 148 } 149 }