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.view.Display.DEFAULT_DISPLAY;
20 import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
21 import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
22 import static android.window.DisplayAreaOrganizer.FEATURE_RUNTIME_TASK_CONTAINER_FIRST;
23 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
24 
25 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
26 
27 import static com.google.common.truth.Truth.assertThat;
28 
29 import static org.mockito.ArgumentMatchers.any;
30 import static org.mockito.Mockito.doReturn;
31 import static org.mockito.Mockito.mock;
32 import static org.mockito.Mockito.never;
33 import static org.mockito.Mockito.verify;
34 import static org.mockito.Mockito.when;
35 import static org.testng.Assert.assertThrows;
36 
37 import android.content.res.Configuration;
38 import android.graphics.Rect;
39 import android.os.Binder;
40 import android.os.RemoteException;
41 import android.platform.test.annotations.Presubmit;
42 import android.view.SurfaceControl;
43 import android.window.DisplayAreaAppearedInfo;
44 import android.window.DisplayAreaInfo;
45 import android.window.IDisplayAreaOrganizer;
46 
47 import androidx.test.filters.SmallTest;
48 
49 import org.junit.After;
50 import org.junit.Before;
51 import org.junit.Test;
52 import org.junit.runner.RunWith;
53 
54 import java.util.List;
55 
56 /**
57  * Build/Install/Run:
58  *  atest WmTests:DisplayAreaOrganizerTest
59  */
60 @SmallTest
61 @Presubmit
62 @RunWith(WindowTestRunner.class)
63 public class DisplayAreaOrganizerTest extends WindowTestsBase {
64 
65     private DisplayArea mTestDisplayArea;
66     private DisplayAreaOrganizerController mOrganizerController;
67 
68     @Before
setUp()69     public void setUp() {
70         mOrganizerController =
71                 mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController;
72         WindowContainer parentWindow = mDisplayContent.getDefaultTaskDisplayArea().getParent();
73         mTestDisplayArea = new DisplayArea(mWm, DisplayArea.Type.ANY,
74                 "TestDisplayArea", FEATURE_VENDOR_FIRST);
75         parentWindow.addChild(mTestDisplayArea,
76                 parentWindow.mChildren.indexOf(mDisplayContent.getDefaultTaskDisplayArea()) + 1);
77     }
78 
79     @After
tearDown()80     public void tearDown() {
81         mTestDisplayArea.removeImmediately();
82     }
83 
registerMockOrganizer(int feature)84     private IDisplayAreaOrganizer registerMockOrganizer(int feature) {
85         return registerMockOrganizer(feature, new Binder());
86     }
87 
registerMockOrganizer(int feature, Binder binder)88     private IDisplayAreaOrganizer registerMockOrganizer(int feature, Binder binder) {
89         final IDisplayAreaOrganizer organizer = createMockOrganizer(binder);
90         mOrganizerController.registerOrganizer(organizer, feature);
91         return organizer;
92     }
93 
createMockOrganizer(Binder binder)94     private IDisplayAreaOrganizer createMockOrganizer(Binder binder) {
95         final IDisplayAreaOrganizer organizer = mock(IDisplayAreaOrganizer.class);
96         when(organizer.asBinder()).thenReturn(binder);
97         return organizer;
98     }
99 
100     @Test
testRegisterOrganizer()101     public void testRegisterOrganizer() throws RemoteException {
102         final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
103         List<DisplayAreaAppearedInfo> infos = mOrganizerController
104                 .registerOrganizer(organizer, FEATURE_VENDOR_FIRST).getList();
105 
106         // Return a list contains the DA, and no onDisplayAreaAppeared triggered.
107         assertThat(infos).hasSize(1);
108         assertThat(infos.get(0).getDisplayAreaInfo().token)
109                 .isEqualTo(mTestDisplayArea.getDisplayAreaInfo().token);
110         verify(organizer, never()).onDisplayAreaAppeared(any(DisplayAreaInfo.class),
111                 any(SurfaceControl.class));
112     }
113 
114     @Test
testRegisterOrganizer_ignoreUntrustedDisplay()115     public void testRegisterOrganizer_ignoreUntrustedDisplay() throws RemoteException {
116         doReturn(false).when(mDisplayContent).isTrusted();
117 
118         final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
119         List<DisplayAreaAppearedInfo> infos = mOrganizerController
120                 .registerOrganizer(organizer, FEATURE_VENDOR_FIRST).getList();
121 
122         assertThat(infos).isEmpty();
123         verify(organizer, never()).onDisplayAreaAppeared(any(DisplayAreaInfo.class),
124                 any(SurfaceControl.class));
125     }
126 
127     @Test
testCreateTaskDisplayArea_topBelowRoot()128     public void testCreateTaskDisplayArea_topBelowRoot() {
129         final String newTdaName = "testTda";
130         final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
131         final DisplayAreaAppearedInfo tdaInfo = mOrganizerController.createTaskDisplayArea(
132                 organizer, DEFAULT_DISPLAY, FEATURE_ROOT, newTdaName);
133 
134         final int newTdaIndex =
135                 mTestDisplayArea.getParent().mChildren.indexOf(mTestDisplayArea) + 1;
136         final WindowContainer wc = mTestDisplayArea.getParent().getChildAt(newTdaIndex);
137 
138         // A new TaskDisplayArea is created on the top.
139         assertThat(wc).isInstanceOf(TaskDisplayArea.class);
140         assertThat(tdaInfo.getDisplayAreaInfo().displayId).isEqualTo(DEFAULT_DISPLAY);
141         assertThat(tdaInfo.getDisplayAreaInfo().token)
142                 .isEqualTo(wc.mRemoteToken.toWindowContainerToken());
143 
144         final TaskDisplayArea tda = wc.asTaskDisplayArea();
145 
146         assertThat(tda.getName()).isEqualTo(newTdaName);
147         assertThat(tda.mFeatureId).isEqualTo(tdaInfo.getDisplayAreaInfo().featureId);
148         assertThat(tda.mCreatedByOrganizer).isTrue();
149         assertThat(tda.mOrganizer).isEqualTo(organizer);
150     }
151 
152     @Test
testCreateTaskDisplayArea_topBelowAnotherTaskDisplayArea()153     public void testCreateTaskDisplayArea_topBelowAnotherTaskDisplayArea() {
154         final String newTdaName = "testTda";
155         final TaskDisplayArea parentTda = mDisplayContent.getDefaultTaskDisplayArea();
156         final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
157         final DisplayAreaAppearedInfo tdaInfo = mOrganizerController.createTaskDisplayArea(
158                 organizer, DEFAULT_DISPLAY, FEATURE_DEFAULT_TASK_CONTAINER, newTdaName);
159 
160         final WindowContainer wc = parentTda.getChildAt(parentTda.getChildCount() - 1);
161 
162         // A new TaskDisplayArea is created on the top.
163         assertThat(wc).isInstanceOf(TaskDisplayArea.class);
164         assertThat(tdaInfo.getDisplayAreaInfo().displayId).isEqualTo(DEFAULT_DISPLAY);
165         assertThat(tdaInfo.getDisplayAreaInfo().token)
166                 .isEqualTo(wc.mRemoteToken.toWindowContainerToken());
167 
168         final TaskDisplayArea tda = wc.asTaskDisplayArea();
169 
170         assertThat(tda.getName()).isEqualTo(newTdaName);
171         assertThat(tda.mFeatureId).isEqualTo(tdaInfo.getDisplayAreaInfo().featureId);
172         assertThat(tda.mCreatedByOrganizer).isTrue();
173         assertThat(tda.mOrganizer).isEqualTo(organizer);
174     }
175 
176     @Test
testCreateTaskDisplayArea_incrementalTdaFeatureId()177     public void testCreateTaskDisplayArea_incrementalTdaFeatureId() {
178         final String newTdaName = "testTda";
179         final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
180         final DisplayAreaAppearedInfo tdaInfo1 = mOrganizerController.createTaskDisplayArea(
181                 organizer, DEFAULT_DISPLAY, FEATURE_ROOT, newTdaName);
182         final DisplayAreaAppearedInfo tdaInfo2 = mOrganizerController.createTaskDisplayArea(
183                 organizer, DEFAULT_DISPLAY, FEATURE_ROOT, newTdaName);
184 
185         // New created TDA has unique feature id starting from FEATURE_RUNTIME_TASK_CONTAINER_FIRST.
186         assertThat(tdaInfo1.getDisplayAreaInfo().featureId).isEqualTo(
187                 FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
188         assertThat(tdaInfo2.getDisplayAreaInfo().featureId).isEqualTo(
189                 FEATURE_RUNTIME_TASK_CONTAINER_FIRST + 1);
190     }
191 
192 
193     @Test
testCreateTaskDisplayArea_invalidDisplayAndRoot()194     public void testCreateTaskDisplayArea_invalidDisplayAndRoot() {
195         final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
196 
197         assertThrows(IllegalArgumentException.class, () ->
198                 mOrganizerController.createTaskDisplayArea(
199                         organizer, SystemServicesTestRule.sNextDisplayId + 1, FEATURE_ROOT,
200                         "testTda"));
201 
202         assertThrows(IllegalArgumentException.class, () ->
203                 mOrganizerController.createTaskDisplayArea(
204                         organizer, DEFAULT_DISPLAY, FEATURE_ROOT - 1, "testTda"));
205 
206         doReturn(false).when(mDisplayContent).isTrusted();
207         assertThrows(IllegalArgumentException.class, () ->
208                 mOrganizerController.createTaskDisplayArea(
209                         organizer, DEFAULT_DISPLAY, FEATURE_ROOT, "testTda"));
210     }
211 
212     @Test
testDeleteTaskDisplayArea()213     public void testDeleteTaskDisplayArea() {
214         final String newTdaName = "testTda";
215         final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
216         final DisplayAreaAppearedInfo tdaInfo = mOrganizerController.createTaskDisplayArea(
217                 organizer, DEFAULT_DISPLAY, FEATURE_ROOT, newTdaName);
218         final int tdaFeatureId = tdaInfo.getDisplayAreaInfo().featureId;
219 
220         final TaskDisplayArea newTda = mDisplayContent.getItemFromDisplayAreas(
221                 da -> da.mFeatureId == tdaFeatureId ? da.asTaskDisplayArea() : null);
222         spyOn(newTda);
223 
224         mOrganizerController.deleteTaskDisplayArea(newTda.mRemoteToken.toWindowContainerToken());
225 
226         verify(newTda).remove();
227         verify(newTda).removeImmediately();
228         assertThat(newTda.mOrganizer).isNull();
229         assertThat(newTda.isRemoved()).isTrue();
230 
231         final TaskDisplayArea curTda = mDisplayContent.getItemFromDisplayAreas(
232                 da -> da.mFeatureId == tdaFeatureId ? da.asTaskDisplayArea() : null);
233 
234         assertThat(curTda).isNull();
235     }
236 
237     @Test
testUnregisterOrganizer_deleteNewCreatedTaskDisplayArea()238     public void testUnregisterOrganizer_deleteNewCreatedTaskDisplayArea() {
239         final String newTdaName = "testTda";
240         final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
241         final DisplayAreaAppearedInfo tdaInfo = mOrganizerController.createTaskDisplayArea(
242                 organizer, DEFAULT_DISPLAY, FEATURE_ROOT, newTdaName);
243         final int tdaFeatureId = tdaInfo.getDisplayAreaInfo().featureId;
244 
245         final TaskDisplayArea newTda = mDisplayContent.getItemFromDisplayAreas(
246                 da -> da.mFeatureId == tdaFeatureId ? da.asTaskDisplayArea() : null);
247         spyOn(newTda);
248 
249         mOrganizerController.unregisterOrganizer(organizer);
250 
251         verify(newTda).remove();
252         verify(newTda).removeImmediately();
253         assertThat(newTda.mOrganizer).isNull();
254         assertThat(newTda.isRemoved()).isTrue();
255 
256         final TaskDisplayArea curTda = mDisplayContent.getItemFromDisplayAreas(
257                 da -> da.mFeatureId == tdaFeatureId ? da.asTaskDisplayArea() : null);
258 
259         assertThat(curTda).isNull();
260     }
261 
262     @Test
testDeleteTaskDisplayArea_invalidTaskDisplayArea()263     public void testDeleteTaskDisplayArea_invalidTaskDisplayArea() {
264         final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea();
265         assertThrows(IllegalArgumentException.class, () ->
266                 mOrganizerController.deleteTaskDisplayArea(
267                         tda.mRemoteToken.toWindowContainerToken()));
268     }
269 
270     @Test
testAppearedVanished()271     public void testAppearedVanished() throws RemoteException {
272         final IDisplayAreaOrganizer organizer = registerMockOrganizer(FEATURE_VENDOR_FIRST);
273         mOrganizerController.unregisterOrganizer(organizer);
274 
275         verify(organizer).onDisplayAreaVanished(any());
276     }
277 
278     @Test
testChanged()279     public void testChanged() throws RemoteException {
280         final IDisplayAreaOrganizer organizer = registerMockOrganizer(FEATURE_VENDOR_FIRST);
281         mDisplayContent.setBounds(new Rect(0, 0, 1000, 1000));
282 
283         verify(organizer).onDisplayAreaInfoChanged(any());
284 
285         Configuration tmpConfiguration = new Configuration();
286         tmpConfiguration.setTo(mDisplayContent.getRequestedOverrideConfiguration());
287         mDisplayContent.onRequestedOverrideConfigurationChanged(tmpConfiguration);
288 
289         // Ensure it was still only called once if the bounds didn't change
290         verify(organizer).onDisplayAreaInfoChanged(any());
291     }
292 
293     @Test
testUnregisterOrganizer()294     public void testUnregisterOrganizer() {
295         final Binder binder = new Binder();
296         registerMockOrganizer(FEATURE_VENDOR_FIRST, binder);
297 
298         assertThat(mTestDisplayArea.mOrganizer).isNotNull();
299 
300         mOrganizerController.unregisterOrganizer(createMockOrganizer(binder));
301 
302         assertThat(mTestDisplayArea.mOrganizer).isNull();
303     }
304 }
305