WindowTestsBase.java revision 153badbf417c3b32fb2702c723185882ca1b3ba2
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
17package com.android.server.wm;
18
19import static android.view.Display.DEFAULT_DISPLAY;
20import static android.view.View.VISIBLE;
21
22import android.graphics.Rect;
23import android.hardware.display.DisplayManagerGlobal;
24import android.view.Display;
25import android.view.DisplayInfo;
26import org.junit.Assert;
27import org.junit.After;
28import org.junit.Before;
29import org.mockito.MockitoAnnotations;
30
31import android.content.Context;
32import android.support.test.InstrumentationRegistry;
33import android.view.IWindow;
34import android.view.WindowManager;
35
36import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
37import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
38import static android.app.AppOpsManager.OP_NONE;
39import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
40import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
41import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
42import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
43import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
44import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
45import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
46import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
47import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
48import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
49import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
50import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
51import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
52import static org.mockito.Mockito.mock;
53
54import com.android.server.AttributeCache;
55
56import java.util.HashSet;
57import java.util.LinkedList;
58
59/**
60 * Common base class for window manager unit test classes.
61 */
62class 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
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
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
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. */
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     */
163    void waitUntilHandlersIdle() {
164        sWm.mH.runWithScissors(() -> { }, 0);
165        sWm.mAnimationHandler.runWithScissors(() -> { }, 0);
166    }
167
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
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
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
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
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
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
211    static WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
212        return createWindow(parent, type, token, name, false /* ownerCanAddInternalSystemWindow */);
213    }
214
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}. */
229    TaskStack createTaskStackOnDisplay(DisplayContent dc) {
230        return createStackControllerOnDisplay(dc).mContainer;
231    }
232
233    StackWindowController createStackControllerOnDisplay(DisplayContent dc) {
234        final int stackId = ++sNextStackId;
235        return createStackControllerOnStackOnDisplay(stackId, dc);
236    }
237
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}. */
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. */
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} */
258    WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs,
259            WindowToken token) {
260        return new WindowTestUtils.TestWindowState(sWm, sMockSession, sIWindow, attrs, token);
261    }
262
263}
264