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.traces.surfaceflinger
18 
19 import android.graphics.Color
20 import android.graphics.RectF
21 import android.graphics.Region
22 import android.tools.datatypes.ActiveBuffer
23 import android.tools.datatypes.isNotEmpty
24 
25 /**
26  * Common properties of a layer that are not related to their position in the hierarchy
27  *
28  * These properties are frequently stable throughout the trace and can be more efficiently cached
29  * than the full layers
30  */
31 interface ILayerProperties {
32     val visibleRegion: Region?
33     val activeBuffer: ActiveBuffer
34     val flags: Int
35     val bounds: RectF
36     val color: Color
37     val isOpaque: Boolean
38     val shadowRadius: Float
39     val cornerRadius: Float
40     val screenBounds: RectF
41     val transform: Transform
42     val effectiveScalingMode: Int
43     val bufferTransform: Transform
44     val hwcCompositionType: HwcCompositionType
45     val backgroundBlurRadius: Int
46     val crop: RectF
47     val isRelativeOf: Boolean
48     val zOrderRelativeOfId: Int
49     val stackId: Int
50     val excludesCompositionState: Boolean
51 
52     val isScaling: Boolean
53         get() = transform.isScaling
54     val isTranslating: Boolean
55         get() = transform.isTranslating
56     val isRotating: Boolean
57         get() = transform.isRotating
58 
59     /**
60      * Checks if the layer's active buffer is empty
61      *
62      * An active buffer is empty if it is not in the proto or if its height or width are 0
63      *
64      * @return
65      */
66     val isActiveBufferEmpty: Boolean
67         get() = activeBuffer.isEmpty
68 
69     /**
70      * Converts flags to human readable tokens.
71      *
72      * @return
73      */
74     val verboseFlags: String
75         get() {
<lambda>null76             val tokens = Flag.values().filter { (it.value and flags) != 0 }.map { it.name }
77 
78             return if (tokens.isEmpty()) {
79                 ""
80             } else {
81                 "${tokens.joinToString("|")} (0x${flags.toString(16)})"
82             }
83         }
84 
85     /**
86      * Checks if the [Layer] has a color
87      *
88      * @return
89      */
90     val fillsColor: Boolean
91         get() = color.isNotEmpty()
92 
93     /**
94      * Checks if the [Layer] draws a shadow
95      *
96      * @return
97      */
98     val drawsShadows: Boolean
99         get() = shadowRadius > 0
100 
101     /**
102      * Checks if the [Layer] has blur
103      *
104      * @return
105      */
106     val hasBlur: Boolean
107         get() = backgroundBlurRadius > 0
108 
109     /**
110      * Checks if the [Layer] has rounded corners
111      *
112      * @return
113      */
114     val hasRoundedCorners: Boolean
115         get() = cornerRadius > 0
116 
117     /**
118      * Checks if the [Layer] draws has effects, which include:
119      * - is a color layer
120      * - is an effects layers which [fillsColor] or [drawsShadows]
121      *
122      * @return
123      */
124     val hasEffects: Boolean
125         get() {
126             return fillsColor || drawsShadows
127         }
128     /**
129      * Checks if the [Layer] has zero requested or inherited alpha
130      *
131      * @return
132      */
133     val hasZeroAlpha: Boolean
134         get() {
135             return color.alpha() == 0f
136         }
137 
isAnimatingnull138     fun isAnimating(prevLayerState: ILayerProperties?): Boolean =
139         when (prevLayerState) {
140             // when there's no previous state, use a heuristic based on the transform
141             null -> !transform.isSimpleRotation
142             else ->
143                 visibleRegion != prevLayerState.visibleRegion ||
144                     transform != prevLayerState.transform ||
145                     color != prevLayerState.color
146         }
147 }
148