1 /*
2  * Copyright (C) 2016 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.view.Display.DEFAULT_DISPLAY;
22 import static android.view.View.VISIBLE;
23 
24 import android.content.res.Configuration;
25 import android.graphics.Rect;
26 import android.hardware.display.DisplayManagerGlobal;
27 import android.testing.DexmakerShareClassLoaderRule;
28 import android.util.Log;
29 import android.view.Display;
30 import android.view.DisplayInfo;
31 import org.junit.Assert;
32 import org.junit.After;
33 import org.junit.Before;
34 import org.junit.Rule;
35 
36 import android.content.Context;
37 import android.support.test.InstrumentationRegistry;
38 import android.view.IWindow;
39 import android.view.WindowManager;
40 
41 import static android.app.AppOpsManager.OP_NONE;
42 import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
43 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
44 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
45 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
46 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
47 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
48 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
49 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
50 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
51 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
52 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
53 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
54 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
55 import static org.mockito.Mockito.mock;
56 
57 import com.android.server.AttributeCache;
58 
59 import java.util.HashSet;
60 import java.util.LinkedList;
61 
62 /**
63  * Common base class for window manager unit test classes.
64  *
65  * Make sure any requests to WM hold the WM lock if needed b/73966377
66  */
67 class WindowTestsBase {
68     private static final String TAG = WindowTestsBase.class.getSimpleName();
69     WindowManagerService sWm = null;  // TODO(roosa): rename to mWm in follow-up CL
70     private final IWindow mIWindow = new TestIWindow();
71     private Session mMockSession;
72     // The default display is removed in {@link #setUp} and then we iterate over all displays to
73     // make sure we don't collide with any existing display. If we run into no other display, the
74     // added display should be treated as default. This cannot be the default display
75     private static int sNextDisplayId = DEFAULT_DISPLAY + 1;
76     static int sNextStackId = 1000;
77 
78     DisplayContent mDisplayContent;
79     DisplayInfo mDisplayInfo = new DisplayInfo();
80     WindowState mWallpaperWindow;
81     WindowState mImeWindow;
82     WindowState mImeDialogWindow;
83     WindowState mStatusBarWindow;
84     WindowState mDockedDividerWindow;
85     WindowState mNavBarWindow;
86     WindowState mAppWindow;
87     WindowState mChildAppWindowAbove;
88     WindowState mChildAppWindowBelow;
89     HashSet<WindowState> mCommonWindows;
90     WallpaperController mWallpaperController;
91 
92     @Rule
93     public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
94             new DexmakerShareClassLoaderRule();
95 
96     @Rule
97     public final WindowManagerServiceRule mWmRule = new WindowManagerServiceRule();
98 
99     static WindowState.PowerManagerWrapper mPowerManagerWrapper;  // TODO(roosa): make non-static.
100 
101     @Before
setUp()102     public void setUp() throws Exception {
103         // If @Before throws an exception, the error isn't logged. This will make sure any failures
104         // in the set up are clear. This can be removed when b/37850063 is fixed.
105         try {
106             mMockSession = mock(Session.class);
107             mPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
108 
109             final Context context = InstrumentationRegistry.getTargetContext();
110             AttributeCache.init(context);
111 
112             sWm = mWmRule.getWindowManagerService();
113             beforeCreateDisplay();
114 
115             mWallpaperController = new WallpaperController(sWm);
116 
117             context.getDisplay().getDisplayInfo(mDisplayInfo);
118             mDisplayContent = createNewDisplay();
119             sWm.mDisplayEnabled = true;
120             sWm.mDisplayReady = true;
121 
122             // Set-up some common windows.
123             mCommonWindows = new HashSet();
124             synchronized (sWm.mWindowMap) {
125                 mWallpaperWindow = createCommonWindow(null, TYPE_WALLPAPER, "wallpaperWindow");
126                 mImeWindow = createCommonWindow(null, TYPE_INPUT_METHOD, "mImeWindow");
127                 sWm.mInputMethodWindow = mImeWindow;
128                 mImeDialogWindow = createCommonWindow(null, TYPE_INPUT_METHOD_DIALOG,
129                         "mImeDialogWindow");
130                 mStatusBarWindow = createCommonWindow(null, TYPE_STATUS_BAR, "mStatusBarWindow");
131                 mNavBarWindow = createCommonWindow(null, TYPE_NAVIGATION_BAR, "mNavBarWindow");
132                 mDockedDividerWindow = createCommonWindow(null, TYPE_DOCK_DIVIDER,
133                         "mDockedDividerWindow");
134                 mAppWindow = createCommonWindow(null, TYPE_BASE_APPLICATION, "mAppWindow");
135                 mChildAppWindowAbove = createCommonWindow(mAppWindow,
136                         TYPE_APPLICATION_ATTACHED_DIALOG,
137                         "mChildAppWindowAbove");
138                 mChildAppWindowBelow = createCommonWindow(mAppWindow,
139                         TYPE_APPLICATION_MEDIA_OVERLAY,
140                         "mChildAppWindowBelow");
141             }
142             // Adding a display will cause freezing the display. Make sure to wait until it's
143             // unfrozen to not run into race conditions with the tests.
144             waitUntilHandlersIdle();
145         } catch (Exception e) {
146             Log.e(TAG, "Failed to set up test", e);
147             throw e;
148         }
149     }
150 
beforeCreateDisplay()151     void beforeCreateDisplay() {
152         // Called before display is created.
153     }
154 
155     @After
tearDown()156     public void tearDown() throws Exception {
157         // If @After throws an exception, the error isn't logged. This will make sure any failures
158         // in the tear down are clear. This can be removed when b/37850063 is fixed.
159         try {
160             final LinkedList<WindowState> nonCommonWindows = new LinkedList();
161 
162             synchronized (sWm.mWindowMap) {
163                 sWm.mRoot.forAllWindows(w -> {
164                     if (!mCommonWindows.contains(w)) {
165                         nonCommonWindows.addLast(w);
166                     }
167                 }, true /* traverseTopToBottom */);
168 
169                 while (!nonCommonWindows.isEmpty()) {
170                     nonCommonWindows.pollLast().removeImmediately();
171                 }
172 
173                 mDisplayContent.removeImmediately();
174                 sWm.mInputMethodTarget = null;
175                 sWm.mClosingApps.clear();
176                 sWm.mOpeningApps.clear();
177             }
178 
179             // Wait until everything is really cleaned up.
180             waitUntilHandlersIdle();
181         } catch (Exception e) {
182             Log.e(TAG, "Failed to tear down test", e);
183             throw e;
184         }
185     }
186 
187     /**
188      * @return A SurfaceBuilderFactory to inject in to the WindowManagerService during
189      *         set-up (or null).
190      */
getSurfaceBuilderFactory()191     SurfaceBuilderFactory getSurfaceBuilderFactory() {
192         return null;
193     }
194 
createCommonWindow(WindowState parent, int type, String name)195     private WindowState createCommonWindow(WindowState parent, int type, String name) {
196         synchronized (sWm.mWindowMap) {
197             final WindowState win = createWindow(parent, type, name);
198             mCommonWindows.add(win);
199             // Prevent common windows from been IMe targets
200             win.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
201             return win;
202         }
203     }
204 
205     /** Asserts that the first entry is greater than the second entry. */
assertGreaterThan(int first, int second)206     void assertGreaterThan(int first, int second) throws Exception {
207         Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second);
208     }
209 
210     /** Asserts that the first entry is greater than the second entry. */
assertLessThan(int first, int second)211     void assertLessThan(int first, int second) throws Exception {
212         Assert.assertTrue("Excepted " + first + " to be less than " + second, first < second);
213     }
214 
215     /**
216      * Waits until the main handler for WM has processed all messages.
217      */
waitUntilHandlersIdle()218     void waitUntilHandlersIdle() {
219         mWmRule.waitUntilWindowManagerHandlersIdle();
220     }
221 
createWindowToken( DisplayContent dc, int windowingMode, int activityType, int type)222     private WindowToken createWindowToken(
223             DisplayContent dc, int windowingMode, int activityType, int type) {
224         synchronized (sWm.mWindowMap) {
225             if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
226                 return WindowTestUtils.createTestWindowToken(type, dc);
227             }
228 
229             return createAppWindowToken(dc, windowingMode, activityType);
230         }
231     }
232 
createAppWindowToken(DisplayContent dc, int windowingMode, int activityType)233     AppWindowToken createAppWindowToken(DisplayContent dc, int windowingMode, int activityType) {
234         final TaskStack stack = createStackControllerOnStackOnDisplay(windowingMode, activityType,
235                 dc).mContainer;
236         final Task task = createTaskInStack(stack, 0 /* userId */);
237         final WindowTestUtils.TestAppWindowToken appWindowToken =
238                 WindowTestUtils.createTestAppWindowToken(dc);
239         task.addChild(appWindowToken, 0);
240         return appWindowToken;
241     }
242 
createWindow(WindowState parent, int type, String name)243     WindowState createWindow(WindowState parent, int type, String name) {
244         synchronized (sWm.mWindowMap) {
245             return (parent == null)
246                     ? createWindow(parent, type, mDisplayContent, name)
247                     : createWindow(parent, type, parent.mToken, name);
248         }
249     }
250 
createWindowOnStack(WindowState parent, int windowingMode, int activityType, int type, DisplayContent dc, String name)251     WindowState createWindowOnStack(WindowState parent, int windowingMode, int activityType,
252             int type, DisplayContent dc, String name) {
253         synchronized (sWm.mWindowMap) {
254             final WindowToken token = createWindowToken(dc, windowingMode, activityType, type);
255             return createWindow(parent, type, token, name);
256         }
257     }
258 
createAppWindow(Task task, int type, String name)259     WindowState createAppWindow(Task task, int type, String name) {
260         synchronized (sWm.mWindowMap) {
261             final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
262             task.addChild(token, 0);
263             return createWindow(null, type, token, name);
264         }
265     }
266 
createWindow(WindowState parent, int type, DisplayContent dc, String name)267     WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
268         synchronized (sWm.mWindowMap) {
269             final WindowToken token = createWindowToken(
270                     dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
271             return createWindow(parent, type, token, name);
272         }
273     }
274 
createWindow(WindowState parent, int type, DisplayContent dc, String name, boolean ownerCanAddInternalSystemWindow)275     WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name,
276             boolean ownerCanAddInternalSystemWindow) {
277         synchronized (sWm.mWindowMap) {
278             final WindowToken token = createWindowToken(
279                     dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
280             return createWindow(parent, type, token, name, 0 /* ownerId */,
281                     ownerCanAddInternalSystemWindow);
282         }
283     }
284 
createWindow(WindowState parent, int type, WindowToken token, String name)285     WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
286         synchronized (sWm.mWindowMap) {
287             return createWindow(parent, type, token, name, 0 /* ownerId */,
288                     false /* ownerCanAddInternalSystemWindow */);
289         }
290     }
291 
createWindow(WindowState parent, int type, WindowToken token, String name, int ownerId, boolean ownerCanAddInternalSystemWindow)292     WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
293             int ownerId, boolean ownerCanAddInternalSystemWindow) {
294         return createWindow(parent, type, token, name, ownerId, ownerCanAddInternalSystemWindow,
295                 sWm, mMockSession, mIWindow);
296     }
297 
createWindow(WindowState parent, int type, WindowToken token, String name, int ownerId, boolean ownerCanAddInternalSystemWindow, WindowManagerService service, Session session, IWindow iWindow)298     static WindowState createWindow(WindowState parent, int type, WindowToken token,
299             String name, int ownerId, boolean ownerCanAddInternalSystemWindow,
300             WindowManagerService service, Session session, IWindow iWindow) {
301         synchronized (service.mWindowMap) {
302             final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
303             attrs.setTitle(name);
304 
305             final WindowState w = new WindowState(service, session, iWindow, token, parent,
306                     OP_NONE,
307                     0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow,
308                     mPowerManagerWrapper);
309             // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
310             // adding it to the token...
311             token.addWindow(w);
312             return w;
313         }
314     }
315 
316     /** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */
createTaskStackOnDisplay(DisplayContent dc)317     TaskStack createTaskStackOnDisplay(DisplayContent dc) {
318         synchronized (sWm.mWindowMap) {
319             return createStackControllerOnDisplay(dc).mContainer;
320         }
321     }
322 
createStackControllerOnDisplay(DisplayContent dc)323     StackWindowController createStackControllerOnDisplay(DisplayContent dc) {
324         synchronized (sWm.mWindowMap) {
325             return createStackControllerOnStackOnDisplay(
326                     WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
327         }
328     }
329 
createStackControllerOnStackOnDisplay( int windowingMode, int activityType, DisplayContent dc)330     StackWindowController createStackControllerOnStackOnDisplay(
331             int windowingMode, int activityType, DisplayContent dc) {
332         synchronized (sWm.mWindowMap) {
333             final Configuration overrideConfig = new Configuration();
334             overrideConfig.windowConfiguration.setWindowingMode(windowingMode);
335             overrideConfig.windowConfiguration.setActivityType(activityType);
336             final int stackId = ++sNextStackId;
337             final StackWindowController controller = new StackWindowController(stackId, null,
338                     dc.getDisplayId(), true /* onTop */, new Rect(), sWm);
339             controller.onOverrideConfigurationChanged(overrideConfig);
340             return controller;
341         }
342     }
343 
344     /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
createTaskInStack(TaskStack stack, int userId)345     Task createTaskInStack(TaskStack stack, int userId) {
346         return WindowTestUtils.createTaskInStack(sWm, stack, userId);
347     }
348 
349     /** Creates a {@link DisplayContent} and adds it to the system. */
createNewDisplay()350     DisplayContent createNewDisplay() {
351         final int displayId = sNextDisplayId++;
352         final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
353                 mDisplayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
354         synchronized (sWm.mWindowMap) {
355             return new DisplayContent(display, sWm, mWallpaperController,
356                     mock(DisplayWindowController.class));
357         }
358     }
359 
360     /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
createWindowState(WindowManager.LayoutParams attrs, WindowToken token)361     WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs,
362             WindowToken token) {
363         synchronized (sWm.mWindowMap) {
364             return new WindowTestUtils.TestWindowState(sWm, mMockSession, mIWindow, attrs, token);
365         }
366     }
367 
368 }
369