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