1 /*
2  * Copyright (C) 2020 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;
18 
19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
20 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
21 import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
22 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
23 
24 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
25 import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS;
26 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
27 import static com.android.server.wm.WindowContainer.POSITION_TOP;
28 
29 import static org.junit.Assert.assertEquals;
30 import static org.junit.Assert.assertNotNull;
31 import static org.junit.Assert.assertNull;
32 import static org.junit.Assert.assertTrue;
33 import static org.mockito.Mockito.mock;
34 
35 import android.platform.test.annotations.Presubmit;
36 import android.util.Pair;
37 import android.view.Display;
38 import android.view.DisplayInfo;
39 
40 import androidx.test.filters.SmallTest;
41 
42 import com.android.server.wm.DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot;
43 
44 import com.google.android.collect.Lists;
45 
46 import org.junit.Test;
47 import org.junit.runner.RunWith;
48 
49 import java.util.ArrayList;
50 import java.util.Collections;
51 import java.util.List;
52 import java.util.Optional;
53 
54 /**
55  * Tests for the {@link DisplayAreaPolicy}.
56  *
57  * Build/Install/Run:
58  *  atest WmTests:DisplayAreaPolicyTests
59  */
60 @SmallTest
61 @Presubmit
62 @RunWith(WindowTestRunner.class)
63 public class DisplayAreaPolicyTests extends WindowTestsBase {
64 
65     @Test
testGetDefaultTaskDisplayArea()66     public void testGetDefaultTaskDisplayArea() {
67         final Pair<DisplayAreaPolicy, List<TaskDisplayArea>> result =
68                 createPolicyWith2TaskDisplayAreas();
69         final DisplayAreaPolicy policy = result.first;
70         final TaskDisplayArea taskDisplayArea1 = result.second.get(0);
71         assertEquals(taskDisplayArea1, policy.getDefaultTaskDisplayArea());
72     }
73 
74     @Test
testTaskDisplayArea_taskPositionChanged_updatesTaskDisplayAreaPosition()75     public void testTaskDisplayArea_taskPositionChanged_updatesTaskDisplayAreaPosition() {
76         final Pair<DisplayAreaPolicy, List<TaskDisplayArea>> result =
77                 createPolicyWith2TaskDisplayAreas();
78         final DisplayAreaPolicy policy = result.first;
79         final TaskDisplayArea taskDisplayArea1 = result.second.get(0);
80         final TaskDisplayArea taskDisplayArea2 = result.second.get(1);
81         final Task stack1 = taskDisplayArea1.createRootTask(
82                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
83         final Task stack2 = taskDisplayArea2.createRootTask(
84                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
85 
86         // Initial order
87         assertTaskDisplayAreasOrder(policy, taskDisplayArea1, taskDisplayArea2);
88 
89         // Move stack in tda1 to top
90         stack1.getParent().positionChildAt(POSITION_TOP, stack1, true /* includingParents */);
91 
92         assertTaskDisplayAreasOrder(policy, taskDisplayArea2, taskDisplayArea1);
93 
94         // Move stack in tda2 to top, but not including parents
95         stack2.getParent().positionChildAt(POSITION_TOP, stack2, false /* includingParents */);
96 
97         assertTaskDisplayAreasOrder(policy, taskDisplayArea2, taskDisplayArea1);
98 
99         // Move stack in tda1 to bottom
100         stack1.getParent().positionChildAt(POSITION_BOTTOM, stack1, true /* includingParents */);
101 
102         assertTaskDisplayAreasOrder(policy, taskDisplayArea1, taskDisplayArea2);
103 
104         // Move stack in tda2 to bottom, but not including parents
105         stack2.getParent().positionChildAt(POSITION_BOTTOM, stack2, false /* includingParents */);
106 
107         assertTaskDisplayAreasOrder(policy, taskDisplayArea1, taskDisplayArea2);
108     }
109 
110     @Test
testEmptyFeaturesOnUntrustedDisplay()111     public void testEmptyFeaturesOnUntrustedDisplay() {
112         final DisplayInfo info = new DisplayInfo(mDisplayInfo);
113         info.flags &= ~Display.FLAG_TRUSTED;
114         final DisplayContent untrustedDisplay = new TestDisplayContent.Builder(mAtm, info).build();
115 
116         assertTrue(untrustedDisplay.mFeatures.isEmpty());
117         assertNotNull(untrustedDisplay.getWindowingLayer());
118     }
119 
120     @Test
testDisplayAreaGroup_taskPositionChanged_updatesDisplayAreaGroupPosition()121     public void testDisplayAreaGroup_taskPositionChanged_updatesDisplayAreaGroupPosition() {
122         final WindowManagerService wms = mWm;
123         final DisplayContent displayContent = mock(DisplayContent.class);
124         doReturn(true).when(displayContent).isTrusted();
125         final RootDisplayArea root = new SurfacelessDisplayAreaRoot(wms);
126         final RootDisplayArea group1 = new SurfacelessDisplayAreaRoot(wms, "group1",
127                 FEATURE_VENDOR_FIRST + 1);
128         final RootDisplayArea group2 = new SurfacelessDisplayAreaRoot(wms, "group2",
129                 FEATURE_VENDOR_FIRST + 2);
130         final TaskDisplayArea taskDisplayArea1 = new TaskDisplayArea(displayContent, wms, "Tasks1",
131                 FEATURE_DEFAULT_TASK_CONTAINER);
132         final TaskDisplayArea taskDisplayArea2 = new TaskDisplayArea(displayContent, wms, "Tasks2",
133                 FEATURE_VENDOR_FIRST + 3);
134         final TaskDisplayArea taskDisplayArea3 = new TaskDisplayArea(displayContent, wms, "Tasks3",
135                 FEATURE_VENDOR_FIRST + 4);
136         final TaskDisplayArea taskDisplayArea4 = new TaskDisplayArea(displayContent, wms, "Tasks4",
137                 FEATURE_VENDOR_FIRST + 5);
138         final TaskDisplayArea taskDisplayArea5 = new TaskDisplayArea(displayContent, wms, "Tasks5",
139                 FEATURE_VENDOR_FIRST + 6);
140         final DisplayArea.Tokens ime = new DisplayArea.Tokens(wms, ABOVE_TASKS, "Ime");
141         final DisplayAreaPolicy policy = new DisplayAreaPolicyBuilder()
142                 .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(root)
143                         .setImeContainer(ime)
144                         .setTaskDisplayAreas(Lists.newArrayList(taskDisplayArea1, taskDisplayArea2))
145                 )
146                 .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(group1)
147                         .setTaskDisplayAreas(Lists.newArrayList(taskDisplayArea3, taskDisplayArea4))
148                 )
149                 .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(group2)
150                         .setTaskDisplayAreas(Lists.newArrayList(taskDisplayArea5)))
151                 .build(wms);
152         final Task stack1 = taskDisplayArea1.createRootTask(
153                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
154         final Task stack3 = taskDisplayArea3.createRootTask(
155                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
156         final Task stack4 = taskDisplayArea4.createRootTask(
157                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
158 
159         // Initial order
160         assertTaskDisplayAreasOrder(policy, taskDisplayArea1, taskDisplayArea2, taskDisplayArea3,
161                 taskDisplayArea4, taskDisplayArea5);
162 
163         // Move bottom stack in tda1 to top
164         stack1.getParent().positionChildAt(POSITION_TOP, stack1, true /* includingParents */);
165 
166         assertTaskDisplayAreasOrder(policy, taskDisplayArea2, taskDisplayArea3, taskDisplayArea4,
167                 taskDisplayArea5, taskDisplayArea1);
168 
169         // Move bottom stack in tda2 to top
170         stack3.getParent().positionChildAt(POSITION_TOP, stack3, true /* includingParents */);
171 
172         assertTaskDisplayAreasOrder(policy, taskDisplayArea2, taskDisplayArea5, taskDisplayArea1,
173                 taskDisplayArea4, taskDisplayArea3);
174 
175         // Move bottom stack in tda2 to top
176         stack4.getParent().positionChildAt(POSITION_TOP, stack4, true /* includingParents */);
177 
178         assertTaskDisplayAreasOrder(policy, taskDisplayArea2, taskDisplayArea5, taskDisplayArea1,
179                 taskDisplayArea3, taskDisplayArea4);
180 
181         // Move top stack in tda2 to bottom
182         stack4.getParent().positionChildAt(POSITION_BOTTOM, stack4, true /* includingParents */);
183 
184         assertTaskDisplayAreasOrder(policy, taskDisplayArea4, taskDisplayArea3, taskDisplayArea2,
185                 taskDisplayArea5, taskDisplayArea1);
186     }
187 
188     @Test
testTaskDisplayAreasCanHostHomeTask()189     public void testTaskDisplayAreasCanHostHomeTask() {
190         final WindowManagerService wms = mWm;
191         final DisplayContent displayContent = mock(DisplayContent.class);
192         doReturn(true).when(displayContent).isTrusted();
193         doReturn(true).when(displayContent).supportsSystemDecorations();
194         final RootDisplayArea root = new SurfacelessDisplayAreaRoot(wms);
195         final TaskDisplayArea taskDisplayAreaWithHome = new TaskDisplayArea(displayContent, wms,
196                 "Tasks1", FEATURE_DEFAULT_TASK_CONTAINER);
197         final TaskDisplayArea taskDisplayAreaWithNoHome = new TaskDisplayArea(displayContent, wms,
198                 "Tasks2", FEATURE_VENDOR_FIRST + 1, false, false);
199         final DisplayArea.Tokens ime = new DisplayArea.Tokens(wms, ABOVE_TASKS, "Ime");
200         final DisplayAreaPolicy policy = new DisplayAreaPolicyBuilder()
201                 .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(root)
202                         .setImeContainer(ime)
203                         .setTaskDisplayAreas(Lists.newArrayList(taskDisplayAreaWithHome,
204                                 taskDisplayAreaWithNoHome))
205                 )
206                 .build(wms);
207         assertTaskDisplayAreaPresentAndCanHaveHome(policy, FEATURE_DEFAULT_TASK_CONTAINER, true);
208         assertTaskDisplayAreaPresentAndCanHaveHome(policy, FEATURE_VENDOR_FIRST + 1, false);
209         final Task stackHome = taskDisplayAreaWithHome.getOrCreateRootHomeTask(true);
210         final Task stackNoHome = taskDisplayAreaWithNoHome.getOrCreateRootHomeTask(true);
211         assertNotNull(stackHome);
212         assertNull(stackNoHome);
213     }
214 
assertTaskDisplayAreaPresentAndCanHaveHome(DisplayAreaPolicy policy, int featureId, boolean canHaveHome)215     private void assertTaskDisplayAreaPresentAndCanHaveHome(DisplayAreaPolicy policy,
216                                                             int featureId,
217                                                             boolean canHaveHome) {
218         Optional<DisplayArea> optionalDisplayArea = policy.mRoot.mChildren
219                 .stream().filter(displayArea -> displayArea.mFeatureId == featureId)
220                 .findAny();
221         assertTrue(optionalDisplayArea.isPresent());
222         assertEquals(canHaveHome, optionalDisplayArea.get().asTaskDisplayArea().canHostHomeTask());
223     }
224 
assertTaskDisplayAreasOrder(DisplayAreaPolicy policy, TaskDisplayArea... expectTdaOrder)225     private void assertTaskDisplayAreasOrder(DisplayAreaPolicy policy,
226             TaskDisplayArea... expectTdaOrder) {
227         List<TaskDisplayArea> expectOrder = new ArrayList<>();
228         Collections.addAll(expectOrder, expectTdaOrder);
229 
230         // Verify hierarchy
231         List<TaskDisplayArea> actualOrder = new ArrayList<>();
232         policy.mRoot.forAllTaskDisplayAreas(taskDisplayArea -> {
233             actualOrder.add(taskDisplayArea);
234         }, false /* traverseTopToBottom */);
235         assertEquals(expectOrder, actualOrder);
236     }
237 
createPolicyWith2TaskDisplayAreas()238     private Pair<DisplayAreaPolicy, List<TaskDisplayArea>> createPolicyWith2TaskDisplayAreas() {
239         final SurfacelessDisplayAreaRoot root = new SurfacelessDisplayAreaRoot(mWm);
240         final DisplayArea.Tokens ime = new DisplayArea.Tokens(mWm, ABOVE_TASKS, "Ime");
241         final DisplayContent displayContent = mock(DisplayContent.class);
242         doReturn(true).when(displayContent).isTrusted();
243         final TaskDisplayArea taskDisplayArea1 = new TaskDisplayArea(displayContent, mWm, "Tasks1",
244                 FEATURE_DEFAULT_TASK_CONTAINER);
245         final TaskDisplayArea taskDisplayArea2 = new TaskDisplayArea(displayContent, mWm, "Tasks2",
246                 FEATURE_VENDOR_FIRST);
247         final List<TaskDisplayArea> taskDisplayAreaList = new ArrayList<>();
248         taskDisplayAreaList.add(taskDisplayArea1);
249         taskDisplayAreaList.add(taskDisplayArea2);
250 
251         return Pair.create(new DisplayAreaPolicyBuilder()
252                 .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(root)
253                         .setImeContainer(ime)
254                         .setTaskDisplayAreas(taskDisplayAreaList))
255                 .build(mWm), taskDisplayAreaList);
256     }
257 }
258