WindowTestsBase.java revision 8347163dbb64fb61012c0393163283106a0a351e
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 android.app.ActivityManager.TaskDescription; 20import android.content.res.Configuration; 21import android.graphics.Rect; 22import android.hardware.display.DisplayManagerGlobal; 23import android.os.Binder; 24import android.view.Display; 25import android.view.DisplayInfo; 26import android.view.IApplicationToken; 27import org.junit.Assert; 28import org.junit.After; 29import org.junit.Before; 30import org.mockito.MockitoAnnotations; 31 32import android.app.ActivityManager.TaskSnapshot; 33import android.content.Context; 34import android.os.IBinder; 35import android.support.test.InstrumentationRegistry; 36import android.view.IWindow; 37import android.view.WindowManager; 38 39import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID; 40import static android.app.ActivityManager.StackId.INVALID_STACK_ID; 41import static android.app.AppOpsManager.OP_NONE; 42import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; 43import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 44import static android.content.res.Configuration.EMPTY; 45import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; 46import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; 47import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; 48import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; 49import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY; 50import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 51import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; 52import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; 53import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; 54import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; 55import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; 56import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; 57import static com.android.server.wm.WindowContainer.POSITION_TOP; 58import static org.mockito.Mockito.mock; 59 60import com.android.server.AttributeCache; 61 62import java.util.HashSet; 63 64/** 65 * Common base class for window manager unit test classes. 66 */ 67class WindowTestsBase { 68 static WindowManagerService sWm = null; 69 static TestWindowManagerPolicy sPolicy = null; 70 private final static IWindow sIWindow = new TestIWindow(); 71 private final static Session sMockSession = mock(Session.class); 72 private static int sNextDisplayId = Display.DEFAULT_DISPLAY + 1; 73 static int sNextStackId = FIRST_DYNAMIC_STACK_ID; 74 private static int sNextTaskId = 0; 75 76 private static boolean sOneTimeSetupDone = false; 77 static DisplayContent sDisplayContent; 78 static DisplayInfo sDisplayInfo = new DisplayInfo(); 79 static WindowLayersController sLayersController; 80 static WindowState sWallpaperWindow; 81 static WindowState sImeWindow; 82 static WindowState sImeDialogWindow; 83 static WindowState sStatusBarWindow; 84 static WindowState sDockedDividerWindow; 85 static WindowState sNavBarWindow; 86 static WindowState sAppWindow; 87 static WindowState sChildAppWindowAbove; 88 static WindowState sChildAppWindowBelow; 89 static HashSet<WindowState> sCommonWindows; 90 91 @Before 92 public void setUp() throws Exception { 93 if (sOneTimeSetupDone) { 94 return; 95 } 96 sOneTimeSetupDone = true; 97 MockitoAnnotations.initMocks(this); 98 final Context context = InstrumentationRegistry.getTargetContext(); 99 AttributeCache.init(context); 100 sWm = TestWindowManagerPolicy.getWindowManagerService(context); 101 sPolicy = (TestWindowManagerPolicy) sWm.mPolicy; 102 sLayersController = new WindowLayersController(sWm); 103 sDisplayContent = sWm.mRoot.getDisplayContent(context.getDisplay().getDisplayId()); 104 if (sDisplayContent != null) { 105 sDisplayContent.removeImmediately(); 106 } 107 // Make sure that display ids don't overlap, so there won't be several displays with same 108 // ids among RootWindowContainer children. 109 for (DisplayContent dc : sWm.mRoot.mChildren) { 110 if (dc.getDisplayId() >= sNextDisplayId) { 111 sNextDisplayId = dc.getDisplayId() + 1; 112 } 113 } 114 context.getDisplay().getDisplayInfo(sDisplayInfo); 115 sDisplayContent = createNewDisplay(); 116 sWm.mDisplayEnabled = true; 117 sWm.mDisplayReady = true; 118 119 // Set-up some common windows. 120 sCommonWindows = new HashSet(); 121 sWallpaperWindow = createCommonWindow(null, TYPE_WALLPAPER, "wallpaperWindow"); 122 sImeWindow = createCommonWindow(null, TYPE_INPUT_METHOD, "sImeWindow"); 123 sImeDialogWindow = createCommonWindow(null, TYPE_INPUT_METHOD_DIALOG, "sImeDialogWindow"); 124 sStatusBarWindow = createCommonWindow(null, TYPE_STATUS_BAR, "sStatusBarWindow"); 125 sNavBarWindow = createCommonWindow(null, TYPE_NAVIGATION_BAR, "sNavBarWindow"); 126 sDockedDividerWindow = createCommonWindow(null, TYPE_DOCK_DIVIDER, "sDockedDividerWindow"); 127 sAppWindow = createCommonWindow(null, TYPE_BASE_APPLICATION, "sAppWindow"); 128 sChildAppWindowAbove = createCommonWindow(sAppWindow, TYPE_APPLICATION_ATTACHED_DIALOG, 129 "sChildAppWindowAbove"); 130 sChildAppWindowBelow = createCommonWindow(sAppWindow, TYPE_APPLICATION_MEDIA_OVERLAY, 131 "sChildAppWindowBelow"); 132 } 133 134 @After 135 public void tearDown() throws Exception { 136 sWm.mRoot.forAllWindows(w -> { 137 if (!sCommonWindows.contains(w)) { 138 w.removeImmediately(); 139 } 140 }, true /* traverseTopToBottom */); 141 } 142 143 private static WindowState createCommonWindow(WindowState parent, int type, String name) { 144 final WindowState win = createWindow(parent, type, name); 145 sCommonWindows.add(win); 146 return win; 147 } 148 149 /** 150 * Creates a window for a task on a the given {@param stackId}. 151 */ 152 private WindowState createStackWindow(int stackId, String name) { 153 final StackWindowController stackController = createStackControllerOnStackOnDisplay(stackId, 154 sDisplayContent); 155 final TestTaskWindowContainerController taskController = 156 new TestTaskWindowContainerController(stackController); 157 TestAppWindowToken appWinToken = new TestAppWindowToken(sDisplayContent); 158 appWinToken.mTask = taskController.mContainer; 159 final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, name); 160 win.mAppToken = appWinToken; 161 return win; 162 } 163 164 /** Asserts that the first entry is greater than the second entry. */ 165 void assertGreaterThan(int first, int second) throws Exception { 166 Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second); 167 } 168 169 /** 170 * Waits until the main handler for WM has processed all messages. 171 */ 172 void waitUntilHandlerIdle() { 173 sWm.mH.runWithScissors(() -> { }, 0); 174 } 175 176 private static WindowToken createWindowToken(DisplayContent dc, int stackId, int type) { 177 if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) { 178 return new TestWindowToken(type, dc); 179 } 180 181 final TaskStack stack = stackId == INVALID_STACK_ID 182 ? createTaskStackOnDisplay(dc) 183 : createStackControllerOnStackOnDisplay(stackId, dc).mContainer; 184 final Task task = createTaskInStack(stack, 0 /* userId */); 185 final TestAppWindowToken token = new TestAppWindowToken(dc); 186 task.addChild(token, 0); 187 return token; 188 } 189 190 static WindowState createWindow(WindowState parent, int type, String name) { 191 return (parent == null) 192 ? createWindow(parent, type, sDisplayContent, name) 193 : createWindow(parent, type, parent.mToken, name); 194 } 195 196 static WindowState createWindowOnStack(WindowState parent, int stackId, int type, 197 DisplayContent dc, String name) { 198 final WindowToken token = createWindowToken(dc, stackId, type); 199 return createWindow(parent, type, token, name); 200 } 201 202 WindowState createAppWindow(Task task, int type, String name) { 203 final AppWindowToken token = new TestAppWindowToken(sDisplayContent); 204 task.addChild(token, 0); 205 return createWindow(null, type, token, name); 206 } 207 208 static WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) { 209 final WindowToken token = createWindowToken(dc, INVALID_STACK_ID, type); 210 return createWindow(parent, type, token, name); 211 } 212 213 static WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name, 214 boolean ownerCanAddInternalSystemWindow) { 215 final WindowToken token = createWindowToken(dc, INVALID_STACK_ID, type); 216 return createWindow(parent, type, token, name, ownerCanAddInternalSystemWindow); 217 } 218 219 static WindowState createWindow(WindowState parent, int type, WindowToken token, String name) { 220 return createWindow(parent, type, token, name, false /* ownerCanAddInternalSystemWindow */); 221 } 222 223 static WindowState createWindow(WindowState parent, int type, WindowToken token, String name, 224 boolean ownerCanAddInternalSystemWindow) { 225 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type); 226 attrs.setTitle(name); 227 228 final WindowState w = new WindowState(sWm, sMockSession, sIWindow, token, parent, OP_NONE, 229 0, attrs, 0, 0, ownerCanAddInternalSystemWindow); 230 // TODO: Probably better to make this call in the WindowState ctor to avoid errors with 231 // adding it to the token... 232 token.addWindow(w); 233 return w; 234 } 235 236 /** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */ 237 static TaskStack createTaskStackOnDisplay(DisplayContent dc) { 238 return createStackControllerOnDisplay(dc).mContainer; 239 } 240 241 static StackWindowController createStackControllerOnDisplay(DisplayContent dc) { 242 final int stackId = ++sNextStackId; 243 return createStackControllerOnStackOnDisplay(stackId, dc); 244 } 245 246 static StackWindowController createStackControllerOnStackOnDisplay(int stackId, 247 DisplayContent dc) { 248 return new StackWindowController(stackId, null, dc.getDisplayId(), 249 true /* onTop */, new Rect(), sWm); 250 } 251 252 /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */ 253 static Task createTaskInStack(TaskStack stack, int userId) { 254 final Task newTask = new Task(sNextTaskId++, stack, userId, sWm, null, EMPTY, 0, false, 255 false, new TaskDescription(), null); 256 stack.addTask(newTask, POSITION_TOP); 257 return newTask; 258 } 259 260 /** Creates a {@link DisplayContent} and adds it to the system. */ 261 DisplayContent createNewDisplay() { 262 final int displayId = sNextDisplayId++; 263 final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId, 264 sDisplayInfo, DEFAULT_DISPLAY_ADJUSTMENTS); 265 return new DisplayContent(display, sWm, sLayersController, new WallpaperController(sWm)); 266 } 267 268 /* Used so we can gain access to some protected members of the {@link WindowToken} class */ 269 static class TestWindowToken extends WindowToken { 270 271 TestWindowToken(int type, DisplayContent dc) { 272 this(type, dc, false /* persistOnEmpty */); 273 } 274 275 TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) { 276 super(sWm, mock(IBinder.class), type, persistOnEmpty, dc, 277 false /* ownerCanManageAppTokens */); 278 } 279 280 int getWindowsCount() { 281 return mChildren.size(); 282 } 283 284 boolean hasWindow(WindowState w) { 285 return mChildren.contains(w); 286 } 287 } 288 289 /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */ 290 static class TestAppWindowToken extends AppWindowToken { 291 292 TestAppWindowToken(DisplayContent dc) { 293 super(sWm, null, false, dc, true /* fillsParent */); 294 } 295 296 TestAppWindowToken(WindowManagerService service, IApplicationToken token, 297 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, 298 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, 299 int rotationAnimationHint, int configChanges, boolean launchTaskBehind, 300 boolean alwaysFocusable, AppWindowContainerController controller) { 301 super(service, token, voiceInteraction, dc, inputDispatchingTimeoutNanos, fullscreen, 302 showForAllUsers, targetSdk, orientation, rotationAnimationHint, configChanges, 303 launchTaskBehind, alwaysFocusable, controller); 304 } 305 306 int getWindowsCount() { 307 return mChildren.size(); 308 } 309 310 boolean hasWindow(WindowState w) { 311 return mChildren.contains(w); 312 } 313 314 WindowState getFirstChild() { 315 return mChildren.getFirst(); 316 } 317 318 WindowState getLastChild() { 319 return mChildren.getLast(); 320 } 321 322 int positionInParent() { 323 return getParent().mChildren.indexOf(this); 324 } 325 } 326 327 /* Used so we can gain access to some protected members of the {@link Task} class */ 328 class TestTask extends Task { 329 330 boolean mShouldDeferRemoval = false; 331 boolean mOnDisplayChangedCalled = false; 332 private boolean mUseLocalIsAnimating = false; 333 private boolean mIsAnimating = false; 334 335 TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds, 336 Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture, 337 boolean homeTask, TaskWindowContainerController controller) { 338 super(taskId, stack, userId, service, bounds, overrideConfig, resizeMode, 339 supportsPictureInPicture, homeTask, new TaskDescription(), controller); 340 } 341 342 boolean shouldDeferRemoval() { 343 return mShouldDeferRemoval; 344 } 345 346 int positionInParent() { 347 return getParent().mChildren.indexOf(this); 348 } 349 350 @Override 351 void onDisplayChanged(DisplayContent dc) { 352 super.onDisplayChanged(dc); 353 mOnDisplayChangedCalled = true; 354 } 355 356 @Override 357 boolean isAnimating() { 358 return mUseLocalIsAnimating ? mIsAnimating : super.isAnimating(); 359 } 360 361 void setLocalIsAnimating(boolean isAnimating) { 362 mUseLocalIsAnimating = true; 363 mIsAnimating = isAnimating; 364 } 365 } 366 367 /** 368 * Used so we can gain access to some protected members of {@link TaskWindowContainerController} 369 * class. 370 */ 371 class TestTaskWindowContainerController extends TaskWindowContainerController { 372 373 TestTaskWindowContainerController() { 374 this(createStackControllerOnDisplay(sDisplayContent)); 375 } 376 377 TestTaskWindowContainerController(StackWindowController stackController) { 378 super(sNextTaskId++, new TaskWindowContainerListener() { 379 @Override 380 public void onSnapshotChanged(TaskSnapshot snapshot) { 381 382 } 383 384 @Override 385 public void requestResize(Rect bounds, int resizeMode) { 386 387 } 388 }, stackController, 0 /* userId */, null /* bounds */, 389 EMPTY /* overrideConfig*/, RESIZE_MODE_UNRESIZEABLE, 390 false /* supportsPictureInPicture */, false /* homeTask*/, true /* toTop*/, 391 true /* showForAllUsers */, new TaskDescription(), sWm); 392 } 393 394 @Override 395 TestTask createTask(int taskId, TaskStack stack, int userId, Rect bounds, 396 Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture, 397 boolean homeTask, TaskDescription taskDescription) { 398 return new TestTask(taskId, stack, userId, mService, bounds, overrideConfig, resizeMode, 399 supportsPictureInPicture, homeTask, this); 400 } 401 } 402 403 class TestAppWindowContainerController extends AppWindowContainerController { 404 405 final IApplicationToken mToken; 406 407 TestAppWindowContainerController(TestTaskWindowContainerController taskController) { 408 this(taskController, new TestIApplicationToken()); 409 } 410 411 TestAppWindowContainerController(TestTaskWindowContainerController taskController, 412 IApplicationToken token) { 413 super(taskController, token, null /* listener */, 0 /* index */, 414 SCREEN_ORIENTATION_UNSPECIFIED, true /* fullscreen */, 415 true /* showForAllUsers */, 0 /* configChanges */, false /* voiceInteraction */, 416 false /* launchTaskBehind */, false /* alwaysFocusable */, 417 0 /* targetSdkVersion */, 0 /* rotationAnimationHint */, 418 0 /* inputDispatchingTimeoutNanos */, sWm); 419 mToken = token; 420 } 421 422 @Override 423 AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token, 424 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, 425 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, 426 int rotationAnimationHint, int configChanges, boolean launchTaskBehind, 427 boolean alwaysFocusable, AppWindowContainerController controller) { 428 return new TestAppWindowToken(service, token, voiceInteraction, dc, 429 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, 430 orientation, 431 rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable, 432 controller); 433 } 434 435 AppWindowToken getAppWindowToken() { 436 return (AppWindowToken) sDisplayContent.getWindowToken(mToken.asBinder()); 437 } 438 } 439 440 class TestIApplicationToken implements IApplicationToken { 441 442 private final Binder mBinder = new Binder(); 443 @Override 444 public IBinder asBinder() { 445 return mBinder; 446 } 447 } 448 449 /** Used to track resize reports. */ 450 class TestWindowState extends WindowState { 451 boolean resizeReported; 452 453 TestWindowState(WindowManager.LayoutParams attrs, WindowToken token) { 454 super(sWm, sMockSession, sIWindow, token, null, OP_NONE, 0, attrs, 0, 0, 455 false /* ownerCanAddInternalSystemWindow */); 456 } 457 458 @Override 459 void reportResized() { 460 super.reportResized(); 461 resizeReported = true; 462 } 463 464 @Override 465 public boolean isGoneForLayoutLw() { 466 return false; 467 } 468 469 @Override 470 void updateResizingWindowIfNeeded() { 471 // Used in AppWindowTokenTests#testLandscapeSeascapeRotationRelayout to deceive 472 // the system that it can actually update the window. 473 boolean hadSurface = mHasSurface; 474 mHasSurface = true; 475 476 super.updateResizingWindowIfNeeded(); 477 478 mHasSurface = hadSurface; 479 } 480 } 481} 482