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