WindowTestsBase.java revision ed7993b5d147a6741d26fe0b16cc9fa5e34ceaee
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.View.VISIBLE;
20
21import android.app.ActivityManager.TaskDescription;
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    static TestWindowManagerPolicy sPolicy = null;
65    private final static IWindow sIWindow = new TestIWindow();
66    private final static Session sMockSession = mock(Session.class);
67    // The default display is removed in {@link #setUp} and then we iterate over all displays to
68    // make sure we don't collide with any existing display. If we run into no other display, the
69    // added display should be treated as default. This cannot be the default display
70    private static int sNextDisplayId = Display.DEFAULT_DISPLAY + 1;
71    private static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
72
73    private static boolean sOneTimeSetupDone = false;
74    static DisplayContent sDisplayContent;
75    static DisplayInfo sDisplayInfo = new DisplayInfo();
76    static WindowLayersController sLayersController;
77    static WindowState sWallpaperWindow;
78    static WindowState sImeWindow;
79    static WindowState sImeDialogWindow;
80    static WindowState sStatusBarWindow;
81    static WindowState sDockedDividerWindow;
82    static WindowState sNavBarWindow;
83    static WindowState sAppWindow;
84    static WindowState sChildAppWindowAbove;
85    static WindowState sChildAppWindowBelow;
86    static HashSet<WindowState> sCommonWindows;
87
88    @Before
89    public void setUp() throws Exception {
90        if (sOneTimeSetupDone) {
91            return;
92        }
93        sOneTimeSetupDone = true;
94        MockitoAnnotations.initMocks(this);
95        final Context context = InstrumentationRegistry.getTargetContext();
96        AttributeCache.init(context);
97        sWm = TestWindowManagerPolicy.getWindowManagerService(context);
98        sPolicy = (TestWindowManagerPolicy) sWm.mPolicy;
99        sLayersController = new WindowLayersController(sWm);
100
101        // Make sure that display ids don't overlap, so there won't be several displays with same
102        // ids among RootWindowContainer children.
103        for (DisplayContent dc : sWm.mRoot.mChildren) {
104            if (dc.getDisplayId() >= sNextDisplayId) {
105                sNextDisplayId = dc.getDisplayId() + 1;
106            }
107
108            // The default display must be preserved as some tests require it to function
109            // (such as policy rotation).
110            if (dc.getDisplayId() != Display.DEFAULT_DISPLAY) {
111                // It is safe to remove these displays as new displays will always be created with
112                // new ids.
113                dc.removeImmediately();
114            }
115        }
116
117        context.getDisplay().getDisplayInfo(sDisplayInfo);
118        sDisplayContent = createNewDisplay();
119        sWm.mDisplayEnabled = true;
120        sWm.mDisplayReady = true;
121
122        // Set-up some common windows.
123        sCommonWindows = new HashSet();
124        sWallpaperWindow = createCommonWindow(null, TYPE_WALLPAPER, "wallpaperWindow");
125        sImeWindow = createCommonWindow(null, TYPE_INPUT_METHOD, "sImeWindow");
126        sWm.mInputMethodWindow = sImeWindow;
127        sImeDialogWindow = createCommonWindow(null, TYPE_INPUT_METHOD_DIALOG, "sImeDialogWindow");
128        sStatusBarWindow = createCommonWindow(null, TYPE_STATUS_BAR, "sStatusBarWindow");
129        sNavBarWindow = createCommonWindow(null, TYPE_NAVIGATION_BAR, "sNavBarWindow");
130        sDockedDividerWindow = createCommonWindow(null, TYPE_DOCK_DIVIDER, "sDockedDividerWindow");
131        sAppWindow = createCommonWindow(null, TYPE_BASE_APPLICATION, "sAppWindow");
132        sChildAppWindowAbove = createCommonWindow(sAppWindow, TYPE_APPLICATION_ATTACHED_DIALOG,
133                "sChildAppWindowAbove");
134        sChildAppWindowBelow = createCommonWindow(sAppWindow, TYPE_APPLICATION_MEDIA_OVERLAY,
135                "sChildAppWindowBelow");
136    }
137
138    @After
139    public void tearDown() throws Exception {
140        final LinkedList<WindowState> nonCommonWindows = new LinkedList();
141        sWm.mRoot.forAllWindows(w -> {
142            if (!sCommonWindows.contains(w)) {
143                nonCommonWindows.addLast(w);
144            }
145        }, true /* traverseTopToBottom */);
146
147        while (!nonCommonWindows.isEmpty()) {
148            nonCommonWindows.pollLast().removeImmediately();
149        }
150
151        sWm.mInputMethodTarget = null;
152    }
153
154    private static WindowState createCommonWindow(WindowState parent, int type, String name) {
155        final WindowState win = createWindow(parent, type, name);
156        sCommonWindows.add(win);
157        // Prevent common windows from been IMe targets
158        win.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
159        return win;
160    }
161
162    /** Asserts that the first entry is greater than the second entry. */
163    void assertGreaterThan(int first, int second) throws Exception {
164        Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second);
165    }
166
167    /**
168     * Waits until the main handler for WM has processed all messages.
169     */
170    void waitUntilHandlersIdle() {
171        sWm.mH.runWithScissors(() -> { }, 0);
172        sWm.mAnimationHandler.runWithScissors(() -> { }, 0);
173    }
174
175    private static WindowToken createWindowToken(DisplayContent dc, int stackId, int type) {
176        if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
177            return new WindowTestUtils.TestWindowToken(type, dc);
178        }
179
180        final TaskStack stack = stackId == INVALID_STACK_ID
181                ? createTaskStackOnDisplay(dc)
182                : createStackControllerOnStackOnDisplay(stackId, dc).mContainer;
183        final Task task = createTaskInStack(stack, 0 /* userId */);
184        final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(dc);
185        task.addChild(token, 0);
186        return token;
187    }
188
189    static WindowState createWindow(WindowState parent, int type, String name) {
190        return (parent == null)
191                ? createWindow(parent, type, sDisplayContent, name)
192                : createWindow(parent, type, parent.mToken, name);
193    }
194
195    static WindowState createWindowOnStack(WindowState parent, int stackId, int type,
196            DisplayContent dc, String name) {
197        final WindowToken token = createWindowToken(dc, stackId, type);
198        return createWindow(parent, type, token, name);
199    }
200
201    WindowState createAppWindow(Task task, int type, String name) {
202        final AppWindowToken token = new WindowTestUtils.TestAppWindowToken(sDisplayContent);
203        task.addChild(token, 0);
204        return createWindow(null, type, token, name);
205    }
206
207    static WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
208        final WindowToken token = createWindowToken(dc, INVALID_STACK_ID, type);
209        return createWindow(parent, type, token, name);
210    }
211
212    static WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name,
213            boolean ownerCanAddInternalSystemWindow) {
214        final WindowToken token = createWindowToken(dc, INVALID_STACK_ID, type);
215        return createWindow(parent, type, token, name, ownerCanAddInternalSystemWindow);
216    }
217
218    static WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
219        return createWindow(parent, type, token, name, false /* ownerCanAddInternalSystemWindow */);
220    }
221
222    static WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
223            boolean ownerCanAddInternalSystemWindow) {
224        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
225        attrs.setTitle(name);
226
227        final WindowState w = new WindowState(sWm, sMockSession, sIWindow, token, parent, OP_NONE,
228                0, attrs, VISIBLE, 0, ownerCanAddInternalSystemWindow);
229        // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
230        // adding it to the token...
231        token.addWindow(w);
232        return w;
233    }
234
235    /** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */
236    static TaskStack createTaskStackOnDisplay(DisplayContent dc) {
237        return createStackControllerOnDisplay(dc).mContainer;
238    }
239
240    static StackWindowController createStackControllerOnDisplay(DisplayContent dc) {
241        final int stackId = ++sNextStackId;
242        return createStackControllerOnStackOnDisplay(stackId, dc);
243    }
244
245    static StackWindowController createStackControllerOnStackOnDisplay(int stackId,
246            DisplayContent dc) {
247        return new StackWindowController(stackId, null, dc.getDisplayId(),
248                true /* onTop */, new Rect(), sWm);
249    }
250
251    /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
252    static Task createTaskInStack(TaskStack stack, int userId) {
253        return WindowTestUtils.createTaskInStack(sWm, stack, userId);
254    }
255
256    /** Creates a {@link DisplayContent} and adds it to the system. */
257    DisplayContent createNewDisplay() {
258        final int displayId = sNextDisplayId++;
259        final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
260                sDisplayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
261        return new DisplayContent(display, sWm, sLayersController, new WallpaperController(sWm));
262    }
263
264    /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
265    WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs,
266            WindowToken token) {
267        return new WindowTestUtils.TestWindowState(sWm, sMockSession, sIWindow, attrs, token);
268    }
269
270}
271