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 }