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
18 
19 import com.android.server.wm.traces.common.layers.Layer
20 import com.android.server.wm.traces.common.layers.LayerTraceEntry
21 import com.android.server.wm.traces.common.layers.Transform
22 import com.android.server.wm.traces.common.layers.Transform.Companion.isFlagSet
23 import com.android.server.wm.traces.common.service.PlatformConsts
24 import com.android.server.wm.traces.common.windowmanager.WindowManagerState
25 import com.android.server.wm.traces.common.windowmanager.windows.WindowState
26 
27 object WindowManagerConditionsFactory {
28     private val navBarWindowName = FlickerComponentName.NAV_BAR.toWindowName()
29     private val navBarLayerName = FlickerComponentName.NAV_BAR.toLayerName()
30     private val statusBarWindowName = FlickerComponentName.STATUS_BAR.toWindowName()
31     private val statusBarLayerName = FlickerComponentName.STATUS_BAR.toLayerName()
32 
33     /**
34      * Condition to check if the nav bar window is visible
35      */
36     fun isNavBarVisible(): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
37         ConditionList(listOf(
38             isNavBarWindowVisible(), isNavBarLayerVisible(), isNavBarLayerOpaque()))
39 
40     /**
41      * Condition to check if the nav bar window is visible
42      */
43     fun isNavBarWindowVisible(): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
44         Condition("isNavBarWindowVisible") {
45             it.wmState.isWindowVisible(navBarWindowName)
46         }
47 
48     /**
49      * Condition to check if the nav bar layer is visible
50      */
51     fun isNavBarLayerVisible(): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
52         isLayerVisible(navBarLayerName)
53 
54     /**
55      * Condition to check if the nav bar layer is opaque
56      */
57     fun isNavBarLayerOpaque(): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
58         Condition("isNavBarLayerOpaque") {
59             it.layerState.getLayerWithBuffer(navBarLayerName)
60                 ?.color?.a ?: 0f == 1f
61         }
62 
63     /**
64      * Condition to check if the status bar window is visible
65      */
66     fun isStatusBarVisible(): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
67         ConditionList(listOf(
68             isStatusBarWindowVisible(), isStatusBarLayerVisible(), isStatusBarLayerOpaque()))
69 
70     /**
71      * Condition to check if the nav bar window is visible
72      */
73     fun isStatusBarWindowVisible():
74         Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
75         Condition("isStatusBarWindowVisible") {
76             it.wmState.isWindowVisible(statusBarWindowName)
77         }
78 
79     /**
80      * Condition to check if the nav bar layer is visible
81      */
82     fun isStatusBarLayerVisible(): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
83         isLayerVisible(statusBarLayerName)
84 
85     /**
86      * Condition to check if the nav bar layer is opaque
87      */
88     fun isStatusBarLayerOpaque(): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
89         Condition("isStatusBarLayerOpaque") {
90             it.layerState.getLayerWithBuffer(statusBarLayerName)
91                 ?.color?.a ?: 0f == 1f
92         }
93 
94     fun isHomeActivityVisible(): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
95         Condition("isHomeActivityVisible") {
96             it.wmState.homeActivity?.isVisible == true
97         }
98 
99     fun isAppTransitionIdle(
100         displayId: Int
101     ): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
102         Condition("isAppTransitionIdle[$displayId]") {
103             it.wmState.getDisplay(displayId)
104                 ?.appTransitionState == WindowManagerState.APP_STATE_IDLE
105         }
106 
107     fun containsActivity(
108         component: FlickerComponentName
109     ): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
110         Condition("containsActivity[${component.toActivityName()}]") {
111             it.wmState.containsActivity(component.toActivityName())
112         }
113 
114     fun containsWindow(
115         component: FlickerComponentName
116     ): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
117         Condition("containsWindow[${component.toWindowName()}]") {
118             it.wmState.containsWindow(component.toWindowName())
119         }
120 
121     fun isWindowSurfaceShown(
122         windowName: String
123     ): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
124         Condition("isWindowSurfaceShown[$windowName]") {
125             it.wmState.isWindowSurfaceShown(windowName)
126         }
127 
128     fun isWindowSurfaceShown(
129         component: FlickerComponentName
130     ): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
131         isWindowSurfaceShown(component.toWindowName())
132 
133     fun isActivityVisible(
134         component: FlickerComponentName
135     ): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
136         Condition("isActivityVisible") {
137             it.wmState.isActivityVisible(component.toActivityName())
138         }
139 
140     fun isWMStateComplete(): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
141         Condition("isWMStateComplete") {
142             it.wmState.isComplete()
143         }
144 
145     fun hasRotation(
146         expectedRotation: Int,
147         displayId: Int
148     ): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> {
149         val hasRotationCondition = Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>>(
150             "hasRotation[$expectedRotation, display=$displayId]") {
151             val currRotation = it.wmState.getRotation(displayId)
152             currRotation == expectedRotation
153         }
154         return ConditionList(listOf(
155             hasRotationCondition,
156             isLayerVisible(FlickerComponentName.ROTATION).negate(),
157             isLayerVisible(FlickerComponentName.BACK_SURFACE).negate(),
158             hasLayersAnimating().negate()
159         ))
160     }
161 
162     fun isLayerVisible(
163         layerName: String
164     ): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
165         Condition("isLayerVisible[$layerName]") {
166             it.layerState.isVisible(layerName)
167         }
168 
169     fun isLayerVisible(
170         layerId: Int
171     ): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
172         Condition("isLayerVisible[$layerId]") {
173             it.layerState.getLayerById(layerId)?.isVisible ?: false
174         }
175 
176     fun isLayerColorAlphaOne(
177         component: FlickerComponentName
178     ): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
179         Condition("isLayerColorAlphaOne[${component.toLayerName()}]") {
180             val layers = it.layerState.getVisibleLayersByName(component)
181             layers.any { layer -> layer.color.a == 1.0f }
182         }
183 
184     fun isLayerColorAlphaOne(
185         layerId: Int
186     ): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
187         Condition("isLayerColorAlphaOne[$layerId]") {
188             val layer = it.layerState.getLayerById(layerId)
189             layer?.color?.a == 1.0f
190         }
191 
192     fun isLayerTransformFlagSet(
193         component: FlickerComponentName,
194         transform: Int
195     ): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
196         Condition("isLayerTransformFlagSet[" +
197             "${component.toLayerName()},transform=$transform]") {
198             val layers = it.layerState.getVisibleLayersByName(component)
199             layers.any { layer -> isTransformFlagSet(layer, transform) }
200         }
201 
202     fun isLayerTransformFlagSet(
203         layerId: Int,
204         transform: Int
205     ): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
206         Condition("isLayerTransformFlagSet[$layerId, $transform]") {
207             val layer = it.layerState.getLayerById(layerId)
208             layer?.transform?.type?.isFlagSet(transform) ?: false
209         }
210 
211     fun isLayerTransformIdentity(
212         layerId: Int
213     ): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
214         ConditionList(listOf(
215             isLayerTransformFlagSet(layerId, Transform.SCALE_VAL).negate(),
216             isLayerTransformFlagSet(layerId, Transform.TRANSLATE_VAL).negate(),
217             isLayerTransformFlagSet(layerId, Transform.ROTATE_VAL).negate()
218         ))
219 
220     private fun isTransformFlagSet(layer: Layer, transform: Int): Boolean =
221         layer.transform.type?.isFlagSet(transform) ?: false
222 
223     fun LayerTraceEntry.getVisibleLayersByName(
224         component: FlickerComponentName
225     ): List<Layer> = visibleLayers.filter { it.name.contains(component.toLayerName()) }
226 
227     fun isLayerVisible(
228         component: FlickerComponentName
229     ): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
230         isLayerVisible(component.toLayerName())
231 
232     fun hasLayersAnimating(): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
233         Condition("hasLayersAnimating") {
234             it.layerState.isAnimating()
235         }
236 
237     fun isPipWindowLayerSizeMatch(
238         layerId: Int
239     ): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
240         Condition("isPipWindowLayerSizeMatch") {
241             val pipWindow = it.wmState.pinnedWindows.firstOrNull { it.layerId == layerId }
242                 ?: error("Unable to find window with layerId $layerId")
243             val windowHeight = pipWindow.frame.height.toFloat()
244             val windowWidth = pipWindow.frame.width.toFloat()
245 
246             val pipLayer = it.layerState.getLayerById(layerId)
247             val layerHeight = pipLayer?.sourceBounds?.height
248                 ?: error("Unable to find layer with id $layerId")
249             val layerWidth = pipLayer.sourceBounds.width
250 
251             windowHeight == layerHeight && windowWidth == layerWidth
252         }
253 
254     fun hasPipWindow(): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
255         Condition("hasPipWindow") {
256             it.wmState.hasPipWindow()
257         }
258 
259     fun isImeShown(
260         displayId: Int
261     ): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
262         ConditionList(listOf(
263             isImeOnDisplay(displayId),
264             isLayerVisible(FlickerComponentName.IME),
265             isImeSurfaceShown(),
266             isWindowSurfaceShown(FlickerComponentName.IME.toWindowName())
267         ))
268 
269     private fun isImeOnDisplay(
270         displayId: Int
271     ): Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
272         Condition("isImeOnDisplay[$displayId]") {
273             it.wmState.inputMethodWindowState?.displayId == displayId
274         }
275 
276     private fun isImeSurfaceShown():
277         Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
278         Condition("isImeSurfaceShown") {
279             it.wmState.inputMethodWindowState?.isSurfaceShown == true
280         }
281 
282     fun isAppLaunchEnded(taskId: Int):
283         Condition<DeviceStateDump<WindowManagerState, LayerTraceEntry>> =
284         Condition("containsVisibleAppLaunchWindow[$taskId]") { dump ->
285             val windowStates = dump.wmState.getRootTask(taskId)?.activities?.flatMap {
286                 it.children.filterIsInstance<WindowState>()
287             }
288             windowStates != null && windowStates.none { window ->
289                 window.attributes.type == PlatformConsts.TYPE_APPLICATION_STARTING &&
290                     window.isVisible
291             }
292         }
293 }