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 
55     val isTranslating: Boolean
56         get() = transform.isTranslating
57 
58     val isRotating: Boolean
59         get() = transform.isRotating
60 
61     /**
62      * Checks if the layer's active buffer is empty
63      *
64      * An active buffer is empty if it is not in the proto or if its height or width are 0
65      *
66      * @return
67      */
68     val isActiveBufferEmpty: Boolean
69         get() = activeBuffer.isEmpty
70 
71     /**
72      * Converts flags to human readable tokens.
73      *
74      * @return
75      */
76     val verboseFlags: String
77         get() {
<lambda>null78             val tokens = Flag.values().filter { (it.value and flags) != 0 }.map { it.name }
79 
80             return if (tokens.isEmpty()) {
81                 ""
82             } else {
83                 "${tokens.joinToString("|")} (0x${flags.toString(16)})"
84             }
85         }
86 
87     /**
88      * Checks if the [Layer] has a color
89      *
90      * @return
91      */
92     val fillsColor: Boolean
93         get() = color.isNotEmpty()
94 
95     /**
96      * Checks if the [Layer] draws a shadow
97      *
98      * @return
99      */
100     val drawsShadows: Boolean
101         get() = shadowRadius > 0
102 
103     /**
104      * Checks if the [Layer] has blur
105      *
106      * @return
107      */
108     val hasBlur: Boolean
109         get() = backgroundBlurRadius > 0
110 
111     /**
112      * Checks if the [Layer] has rounded corners
113      *
114      * @return
115      */
116     val hasRoundedCorners: Boolean
117         get() = cornerRadius > 0
118 
119     /**
120      * Checks if the [Layer] draws has effects, which include:
121      * - is a color layer
122      * - is an effects layers which [fillsColor] or [drawsShadows]
123      *
124      * @return
125      */
126     val hasEffects: Boolean
127         get() {
128             return fillsColor || drawsShadows
129         }
130 
131     /**
132      * Checks if the [Layer] has zero requested or inherited alpha
133      *
134      * @return
135      */
136     val hasZeroAlpha: Boolean
137         get() {
138             return color.alpha() == 0f
139         }
140 
isAnimatingnull141     fun isAnimating(prevLayerState: ILayerProperties?): Boolean =
142         when (prevLayerState) {
143             // when there's no previous state, use a heuristic based on the transform
144             null -> !transform.isSimpleRotation
145             else ->
146                 visibleRegion != prevLayerState.visibleRegion ||
147                     transform != prevLayerState.transform ||
148                     color != prevLayerState.color
149         }
150 }
151