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