1 /*
<lambda>null2  * 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.flicker.config.splitscreen
18 
19 import android.tools.flicker.ScenarioInstance
20 import android.tools.flicker.assertors.ComponentTemplate
21 import android.tools.flicker.config.ScenarioId
22 import android.tools.traces.component.ComponentNameMatcher
23 import android.tools.traces.component.FullComponentIdMatcher
24 import android.tools.traces.component.IComponentMatcher
25 import android.tools.traces.surfaceflinger.LayersTrace
26 import android.tools.traces.wm.Transition
27 
28 object Components {
29     val SPLIT_SCREEN_DIVIDER =
30         ComponentTemplate("SplitScreenDivider") {
31             ComponentNameMatcher("", "StageCoordinatorSplitDivider#")
32         }
33     val SPLIT_SCREEN_PRIMARY_APP =
34         ComponentTemplate("SPLIT_SCREEN_PRIMARY_APP") { scenarioInstance: ScenarioInstance ->
35             val associatedTransition =
36                 scenarioInstance.associatedTransition
37                     ?: error(
38                         "Can only extract SPLIT_SCREEN_PRIMARY_APP from scenario with transition"
39                     )
40             val layersTrace =
41                 scenarioInstance.reader.readLayersTrace() ?: error("Missing layers trace")
42 
43             when (scenarioInstance.type) {
44                 ScenarioId("SPLIT_SCREEN_ENTER") -> {
45                     getSplitscreenOpeningComponentMatchers(associatedTransition, layersTrace)
46                         .first()
47                 }
48                 ScenarioId("SPLIT_SCREEN_EXIT") -> {
49                     TODO(
50                         "Not implemented :: ${scenarioInstance.type} :: " +
51                             "${scenarioInstance.associatedTransition}"
52                     )
53                 }
54                 ScenarioId("SPLIT_SCREEN_RESIZE") -> {
55                     val change = associatedTransition.changes.first()
56                     FullComponentIdMatcher(change.windowId, change.layerId)
57                 }
58                 else -> error("Unsupported transition type")
59             }
60         }
61     val SPLIT_SCREEN_SECONDARY_APP =
62         ComponentTemplate("SPLIT_SCREEN_SECONDARY_APP") { scenarioInstance: ScenarioInstance ->
63             val associatedTransition =
64                 scenarioInstance.associatedTransition
65                     ?: error(
66                         "Can only extract SPLIT_SCREEN_SECONDARY_APP from scenario with transition"
67                     )
68             val layersTrace =
69                 scenarioInstance.reader.readLayersTrace() ?: error("Missing layers trace")
70 
71             when (scenarioInstance.type) {
72                 ScenarioId("SPLIT_SCREEN_ENTER") -> {
73                     getSplitscreenOpeningComponentMatchers(associatedTransition, layersTrace)[1]
74                 }
75                 ScenarioId("SPLIT_SCREEN_EXIT") -> {
76                     TODO(
77                         "Not implemented :: ${scenarioInstance.type} :: " +
78                             "${scenarioInstance.associatedTransition}"
79                     )
80                 }
81                 ScenarioId("SPLIT_SCREEN_RESIZE") -> {
82                     val change = associatedTransition.changes.last()
83                     FullComponentIdMatcher(change.windowId, change.layerId)
84                 }
85                 else -> error("Unsupported transition type")
86             }
87         }
88 
89     private fun getSplitscreenOpeningComponentMatchers(
90         associatedTransition: Transition,
91         layersTrace: LayersTrace
92     ): List<IComponentMatcher> {
93         // Task (part of changes)
94         // - Task (part of changes)
95         //   - SplitDecorManager
96         //   - Task for app (part of changes)
97         // - Task (part of changes)
98         //   - SplitDecorManager
99         //   - Task for app (part of changes)
100         // - SplitWindowManager
101         //   - StageCoordinatorSplitDividerLeash#1378
102 
103         val layerIds = associatedTransition.changes.map { it.layerId }
104         val layers =
105             associatedTransition.changes.map { change ->
106                 layersTrace.entries.last().flattenedLayers.first { it.id == change.layerId }
107             }
108 
109         val appIds = layers.filter { layerIds.contains(it.parent?.parent?.id) }.map { it.id }
110 
111         val componentMatchers =
112             associatedTransition.changes
113                 .filter { appIds.contains(it.layerId) }
114                 .map { FullComponentIdMatcher(it.windowId, it.layerId) }
115 
116         require(componentMatchers.size == 2) {
117             "Expected to get 2 splitscreen apps but got ${componentMatchers.size}"
118         }
119 
120         return componentMatchers
121     }
122 }
123