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 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