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.view.Display.DEFAULT_DISPLAY;
20 import static android.view.View.VISIBLE;
21 
22 import android.graphics.Rect;
23 import android.hardware.display.DisplayManagerGlobal;
24 import android.view.Display;
25 import android.view.DisplayInfo;
26 import org.junit.Assert;
27 import org.junit.After;
28 import org.junit.Before;
29 import org.mockito.MockitoAnnotations;
30 
31 import android.content.Context;
32 import android.support.test.InstrumentationRegistry;
33 import android.view.IWindow;
34 import android.view.WindowManager;
35 
36 import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
37 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
38 import static android.app.AppOpsManager.OP_NONE;
39 import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
40 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
41 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
42 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
43 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
44 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
45 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
46 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
47 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
48 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
49 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
50 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
51 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
52 import static org.mockito.Mockito.mock;
53 
54 import com.android.server.AttributeCache;
55 
56 import java.util.HashSet;
57 import java.util.LinkedList;
58 
59 /**
60  * Common base class for window manager unit test classes.
61  */
62 class WindowTestsBase {
63     static WindowManagerService sWm = null;
64     private static final IWindow sIWindow = new TestIWindow();
65     private static final Session sMockSession = mock(Session.class);
66     // The default display is removed in {@link #setUp} and then we iterate over all displays to
67     // make sure we don't collide with any existing display. If we run into no other display, the
68     // added display should be treated as default. This cannot be the default display
69     private static int sNextDisplayId = DEFAULT_DISPLAY + 1;
70     private static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
71 
72     private static boolean sOneTimeSetupDone = false;
73     DisplayContent mDisplayContent;
74     DisplayInfo mDisplayInfo = new DisplayInfo();
75     WindowLayersController mLayersController;
76     WindowState mWallpaperWindow;
77     WindowState mImeWindow;
78     WindowState mImeDialogWindow;
79     WindowState mStatusBarWindow;
80     WindowState mDockedDividerWindow;
81     WindowState mNavBarWindow;
82     WindowState mAppWindow;
83     WindowState mChildAppWindowAbove;
84     WindowState mChildAppWindowBelow;
85     HashSet<WindowState> mCommonWindows;
86 
87     @Before
setUp()88     public void setUp() throws Exception {
89         if (!sOneTimeSetupDone) {
90             sOneTimeSetupDone = true;
91             MockitoAnnotations.initMocks(this);
92         }
93 
94         final Context context = InstrumentationRegistry.getTargetContext();
95         AttributeCache.init(context);
96         sWm = TestWindowManagerPolicy.getWindowManagerService(context);
97         mLayersController = new WindowLayersController(sWm);
98 
99         context.getDisplay().getDisplayInfo(mDisplayInfo);
100         mDisplayContent = createNewDisplay();
101         sWm.mDisplayEnabled = true;
102         sWm.mDisplayReady = true;
103 
104         // Set-up some common windows.
105         mCommonWindows = new HashSet();
106         mWallpaperWindow = createCommonWindow(null, TYPE_WALLPAPER, "wallpaperWindow");
107         mImeWindow = createCommonWindow(null, TYPE_INPUT_METHOD, "mImeWindow");
108         sWm.mInputMethodWindow = mImeWindow;
109         mImeDialogWindow = createCommonWindow(null, TYPE_INPUT_METHOD_DIALOG, "mImeDialogWindow");
110         mStatusBarWindow = createCommonWindow(null, TYPE_STATUS_BAR, "mStatusBarWindow");
111         mNavBarWindow = createCommonWindow(null, TYPE_NAVIGATION_BAR, "mNavBarWindow");
112         mDockedDividerWindow = createCommonWindow(null, TYPE_DOCK_DIVIDER, "mDockedDividerWindow");
113         mAppWindow = createCommonWindow(null, TYPE_BASE_APPLICATION, "mAppWindow");
114         mChildAppWindowAbove = createCommonWindow(mAppWindow, TYPE_APPLICATION_ATTACHED_DIALOG,
115                 "mChildAppWindowAbove");
116         mChildAppWindowBelow = createCommonWindow(mAppWindow, TYPE_APPLICATION_MEDIA_OVERLAY,
117                 "mChildAppWindowBelow");
118 
119         // Adding a display will cause freezing the display. Make sure to wait until it's unfrozen
120         // to not run into race conditions with the tests.
121         waitUntilHandlersIdle();
122     }
123 
124     @After
tearDown()125     public void tearDown() throws Exception {
126         final LinkedList<WindowState> nonCommonWindows = new LinkedList();
127 
128         synchronized (sWm.mWindowMap) {
129             sWm.mRoot.forAllWindows(w -> {
130                 if (!mCommonWindows.contains(w)) {
131                     nonCommonWindows.addLast(w);
132                 }
133             }, true /* traverseTopToBottom */);
134 
135             while (!nonCommonWindows.isEmpty()) {
136                 nonCommonWindows.pollLast().removeImmediately();
137             }
138 
139             mDisplayContent.removeImmediately();
140             sWm.mInputMethodTarget = null;
141         }
142 
143         // Wait until everything is really cleaned up.
144         waitUntilHandlersIdle();
145     }
146 
createCommonWindow(WindowState parent, int type, String name)147     private WindowState createCommonWindow(WindowState parent, int type, String name) {
148         final WindowState win = createWindow(parent, type, name);
149         mCommonWindows.add(win);
150         // Prevent common windows from been IMe targets
151         win.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
152         return win;
153     }
154 
155     /** Asserts that the first entry is greater than the second entry. */
assertGreaterThan(int first, int second)156     void assertGreaterThan(int first, int second) throws Exception {
157         Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second);
158     }
159 
160     /**
161      * Waits until the main handler for WM has processed all messages.
162      */
waitUntilHandlersIdle()163     void waitUntilHandlersIdle() {
164         sWm.mH.runWithScissors(() -> { }, 0);
165         sWm.mAnimationHandler.runWithScissors(() -> { }, 0);
166     }
167 
createWindowToken(DisplayContent dc, int stackId, int type)168     private WindowToken createWindowToken(DisplayContent dc, int stackId, int type) {
169         if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
170             return new WindowTestUtils.TestWindowToken(type, dc);
171         }
172 
173         final TaskStack stack = stackId == INVALID_STACK_ID
174                 ? createTaskStackOnDisplay(dc)
175                 : createStackControllerOnStackOnDisplay(stackId, dc).mContainer;
176         final Task task = createTaskInStack(stack, 0 /* userId */);
177         final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(dc);
178         task.addChild(token, 0);
179         return token;
180     }
181 
createWindow(WindowState parent, int type, String name)182     WindowState createWindow(WindowState parent, int type, String name) {
183         return (parent == null)
184                 ? createWindow(parent, type, mDisplayContent, name)
185                 : createWindow(parent, type, parent.mToken, name);
186     }
187 
createWindowOnStack(WindowState parent, int stackId, int type, DisplayContent dc, String name)188     WindowState createWindowOnStack(WindowState parent, int stackId, int type,
189             DisplayContent dc, String name) {
190         final WindowToken token = createWindowToken(dc, stackId, type);
191         return createWindow(parent, type, token, name);
192     }
193 
createAppWindow(Task task, int type, String name)194     WindowState createAppWindow(Task task, int type, String name) {
195         final AppWindowToken token = new WindowTestUtils.TestAppWindowToken(mDisplayContent);
196         task.addChild(token, 0);
197         return createWindow(null, type, token, name);
198     }
199 
createWindow(WindowState parent, int type, DisplayContent dc, String name)200     WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
201         final WindowToken token = createWindowToken(dc, INVALID_STACK_ID, type);
202         return createWindow(parent, type, token, name);
203     }
204 
createWindow(WindowState parent, int type, DisplayContent dc, String name, boolean ownerCanAddInternalSystemWindow)205     WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name,
206             boolean ownerCanAddInternalSystemWindow) {
207         final WindowToken token = createWindowToken(dc, INVALID_STACK_ID, type);
208         return createWindow(parent, type, token, name, ownerCanAddInternalSystemWindow);
209     }
210 
createWindow(WindowState parent, int type, WindowToken token, String name)211     static WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
212         return createWindow(parent, type, token, name, false /* ownerCanAddInternalSystemWindow */);
213     }
214 
createWindow(WindowState parent, int type, WindowToken token, String name, boolean ownerCanAddInternalSystemWindow)215     static WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
216             boolean ownerCanAddInternalSystemWindow) {
217         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
218         attrs.setTitle(name);
219 
220         final WindowState w = new WindowState(sWm, sMockSession, sIWindow, token, parent, OP_NONE,
221                 0, attrs, VISIBLE, 0, ownerCanAddInternalSystemWindow);
222         // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
223         // adding it to the token...
224         token.addWindow(w);
225         return w;
226     }
227 
228     /** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */
createTaskStackOnDisplay(DisplayContent dc)229     TaskStack createTaskStackOnDisplay(DisplayContent dc) {
230         return createStackControllerOnDisplay(dc).mContainer;
231     }
232 
createStackControllerOnDisplay(DisplayContent dc)233     StackWindowController createStackControllerOnDisplay(DisplayContent dc) {
234         final int stackId = ++sNextStackId;
235         return createStackControllerOnStackOnDisplay(stackId, dc);
236     }
237 
createStackControllerOnStackOnDisplay(int stackId, DisplayContent dc)238     StackWindowController createStackControllerOnStackOnDisplay(int stackId,
239             DisplayContent dc) {
240         return new StackWindowController(stackId, null, dc.getDisplayId(),
241                 true /* onTop */, new Rect(), sWm);
242     }
243 
244     /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
createTaskInStack(TaskStack stack, int userId)245     Task createTaskInStack(TaskStack stack, int userId) {
246         return WindowTestUtils.createTaskInStack(sWm, stack, userId);
247     }
248 
249     /** Creates a {@link DisplayContent} and adds it to the system. */
createNewDisplay()250     DisplayContent createNewDisplay() {
251         final int displayId = sNextDisplayId++;
252         final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
253                 mDisplayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
254         return new DisplayContent(display, sWm, mLayersController, new WallpaperController(sWm));
255     }
256 
257     /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
createWindowState(WindowManager.LayoutParams attrs, WindowToken token)258     WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs,
259             WindowToken token) {
260         return new WindowTestUtils.TestWindowState(sWm, sMockSession, sIWindow, attrs, token);
261     }
262 
263 }
264