WindowTestsBase.java revision 7fbeb8a5d754c7e5c330458cf241c5e2a718099c
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 /** Asserts that the first entry is greater than the second entry. */ 162 void assertGreaterThan(int first, int second) throws Exception { 163 Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second); 164 } 165 166 /** 167 * Waits until the main handler for WM has processed all messages. 168 */ 169 void waitUntilHandlerIdle() { 170 sWm.mH.runWithScissors(() -> { }, 0); 171 } 172 173 private static WindowToken createWindowToken(DisplayContent dc, int stackId, int type) { 174 if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) { 175 return new TestWindowToken(type, dc); 176 } 177 178 final TaskStack stack = stackId == INVALID_STACK_ID 179 ? createTaskStackOnDisplay(dc) 180 : createStackControllerOnStackOnDisplay(stackId, dc).mContainer; 181 final Task task = createTaskInStack(stack, 0 /* userId */); 182 final TestAppWindowToken token = new TestAppWindowToken(dc); 183 task.addChild(token, 0); 184 return token; 185 } 186 187 static WindowState createWindow(WindowState parent, int type, String name) { 188 return (parent == null) 189 ? createWindow(parent, type, sDisplayContent, name) 190 : createWindow(parent, type, parent.mToken, name); 191 } 192 193 static WindowState createWindowOnStack(WindowState parent, int stackId, int type, 194 DisplayContent dc, String name) { 195 final WindowToken token = createWindowToken(dc, stackId, type); 196 return createWindow(parent, type, token, name); 197 } 198 199 WindowState createAppWindow(Task task, int type, String name) { 200 final AppWindowToken token = new TestAppWindowToken(sDisplayContent); 201 task.addChild(token, 0); 202 return createWindow(null, type, token, name); 203 } 204 205 static WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) { 206 final WindowToken token = createWindowToken(dc, INVALID_STACK_ID, type); 207 return createWindow(parent, type, token, name); 208 } 209 210 static WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name, 211 boolean ownerCanAddInternalSystemWindow) { 212 final WindowToken token = createWindowToken(dc, INVALID_STACK_ID, type); 213 return createWindow(parent, type, token, name, ownerCanAddInternalSystemWindow); 214 } 215 216 static WindowState createWindow(WindowState parent, int type, WindowToken token, String name) { 217 return createWindow(parent, type, token, name, false /* ownerCanAddInternalSystemWindow */); 218 } 219 220 static WindowState createWindow(WindowState parent, int type, WindowToken token, String name, 221 boolean ownerCanAddInternalSystemWindow) { 222 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type); 223 attrs.setTitle(name); 224 225 final WindowState w = new WindowState(sWm, sMockSession, new TestIWindow(), token, parent, 226 OP_NONE, 0, attrs, 0, 0, ownerCanAddInternalSystemWindow); 227 // TODO: Probably better to make this call in the WindowState ctor to avoid errors with 228 // adding it to the token... 229 token.addWindow(w); 230 sWm.mWindowMap.put(w.mClient.asBinder(), w); 231 return w; 232 } 233 234 /** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */ 235 static TaskStack createTaskStackOnDisplay(DisplayContent dc) { 236 return createStackControllerOnDisplay(dc).mContainer; 237 } 238 239 static StackWindowController createStackControllerOnDisplay(DisplayContent dc) { 240 final int stackId = ++sNextStackId; 241 return createStackControllerOnStackOnDisplay(stackId, dc); 242 } 243 244 static StackWindowController createStackControllerOnStackOnDisplay(int stackId, 245 DisplayContent dc) { 246 return new StackWindowController(stackId, null, dc.getDisplayId(), 247 true /* onTop */, new Rect(), sWm); 248 } 249 250 /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */ 251 static Task createTaskInStack(TaskStack stack, int userId) { 252 final Task newTask = new Task(sNextTaskId++, stack, userId, sWm, null, EMPTY, 0, false, 253 false, new TaskDescription(), null); 254 stack.addTask(newTask, POSITION_TOP); 255 return newTask; 256 } 257 258 /** Creates a {@link DisplayContent} and adds it to the system. */ 259 DisplayContent createNewDisplay() { 260 final int displayId = sNextDisplayId++; 261 final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId, 262 sDisplayInfo, DEFAULT_DISPLAY_ADJUSTMENTS); 263 return new DisplayContent(display, sWm, sLayersController, new WallpaperController(sWm)); 264 } 265 266 /* Used so we can gain access to some protected members of the {@link WindowToken} class */ 267 static class TestWindowToken extends WindowToken { 268 int adj = 0; 269 270 TestWindowToken(int type, DisplayContent dc) { 271 this(type, dc, false /* persistOnEmpty */); 272 } 273 274 TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) { 275 super(sWm, mock(IBinder.class), type, persistOnEmpty, dc, 276 false /* ownerCanManageAppTokens */); 277 } 278 279 int getWindowsCount() { 280 return mChildren.size(); 281 } 282 283 boolean hasWindow(WindowState w) { 284 return mChildren.contains(w); 285 } 286 287 @Override 288 int getAnimLayerAdjustment() { 289 return adj; 290 } 291 } 292 293 /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */ 294 static class TestAppWindowToken extends AppWindowToken { 295 296 TestAppWindowToken(DisplayContent dc) { 297 super(sWm, null, false, dc, true /* fillsParent */); 298 } 299 300 TestAppWindowToken(WindowManagerService service, IApplicationToken token, 301 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, 302 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, 303 int rotationAnimationHint, int configChanges, boolean launchTaskBehind, 304 boolean alwaysFocusable, AppWindowContainerController controller) { 305 super(service, token, voiceInteraction, dc, inputDispatchingTimeoutNanos, fullscreen, 306 showForAllUsers, targetSdk, orientation, rotationAnimationHint, configChanges, 307 launchTaskBehind, alwaysFocusable, controller); 308 } 309 310 int getWindowsCount() { 311 return mChildren.size(); 312 } 313 314 boolean hasWindow(WindowState w) { 315 return mChildren.contains(w); 316 } 317 318 WindowState getFirstChild() { 319 return mChildren.getFirst(); 320 } 321 322 WindowState getLastChild() { 323 return mChildren.getLast(); 324 } 325 326 int positionInParent() { 327 return getParent().mChildren.indexOf(this); 328 } 329 } 330 331 /* Used so we can gain access to some protected members of the {@link Task} class */ 332 class TestTask extends Task { 333 334 boolean mShouldDeferRemoval = false; 335 boolean mOnDisplayChangedCalled = false; 336 private boolean mUseLocalIsAnimating = false; 337 private boolean mIsAnimating = false; 338 339 TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds, 340 Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture, 341 boolean homeTask, TaskWindowContainerController controller) { 342 super(taskId, stack, userId, service, bounds, overrideConfig, resizeMode, 343 supportsPictureInPicture, homeTask, new TaskDescription(), controller); 344 } 345 346 boolean shouldDeferRemoval() { 347 return mShouldDeferRemoval; 348 } 349 350 int positionInParent() { 351 return getParent().mChildren.indexOf(this); 352 } 353 354 @Override 355 void onDisplayChanged(DisplayContent dc) { 356 super.onDisplayChanged(dc); 357 mOnDisplayChangedCalled = true; 358 } 359 360 @Override 361 boolean isAnimating() { 362 return mUseLocalIsAnimating ? mIsAnimating : super.isAnimating(); 363 } 364 365 void setLocalIsAnimating(boolean isAnimating) { 366 mUseLocalIsAnimating = true; 367 mIsAnimating = isAnimating; 368 } 369 } 370 371 /** 372 * Used so we can gain access to some protected members of {@link TaskWindowContainerController} 373 * class. 374 */ 375 class TestTaskWindowContainerController extends TaskWindowContainerController { 376 377 TestTaskWindowContainerController() { 378 this(createStackControllerOnDisplay(sDisplayContent)); 379 } 380 381 TestTaskWindowContainerController(StackWindowController stackController) { 382 super(sNextTaskId++, new TaskWindowContainerListener() { 383 @Override 384 public void onSnapshotChanged(TaskSnapshot snapshot) { 385 386 } 387 388 @Override 389 public void requestResize(Rect bounds, int resizeMode) { 390 391 } 392 }, stackController, 0 /* userId */, null /* bounds */, 393 EMPTY /* overrideConfig*/, RESIZE_MODE_UNRESIZEABLE, 394 false /* supportsPictureInPicture */, false /* homeTask*/, true /* toTop*/, 395 true /* showForAllUsers */, new TaskDescription(), sWm); 396 } 397 398 @Override 399 TestTask createTask(int taskId, TaskStack stack, int userId, Rect bounds, 400 Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture, 401 boolean homeTask, TaskDescription taskDescription) { 402 return new TestTask(taskId, stack, userId, mService, bounds, overrideConfig, resizeMode, 403 supportsPictureInPicture, homeTask, this); 404 } 405 } 406 407 class TestAppWindowContainerController extends AppWindowContainerController { 408 409 final IApplicationToken mToken; 410 411 TestAppWindowContainerController(TestTaskWindowContainerController taskController) { 412 this(taskController, new TestIApplicationToken()); 413 } 414 415 TestAppWindowContainerController(TestTaskWindowContainerController taskController, 416 IApplicationToken token) { 417 super(taskController, token, null /* listener */, 0 /* index */, 418 SCREEN_ORIENTATION_UNSPECIFIED, true /* fullscreen */, 419 true /* showForAllUsers */, 0 /* configChanges */, false /* voiceInteraction */, 420 false /* launchTaskBehind */, false /* alwaysFocusable */, 421 0 /* targetSdkVersion */, 0 /* rotationAnimationHint */, 422 0 /* inputDispatchingTimeoutNanos */, sWm); 423 mToken = token; 424 } 425 426 @Override 427 AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token, 428 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, 429 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, 430 int rotationAnimationHint, int configChanges, boolean launchTaskBehind, 431 boolean alwaysFocusable, AppWindowContainerController controller) { 432 return new TestAppWindowToken(service, token, voiceInteraction, dc, 433 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, 434 orientation, 435 rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable, 436 controller); 437 } 438 439 AppWindowToken getAppWindowToken() { 440 return (AppWindowToken) sDisplayContent.getWindowToken(mToken.asBinder()); 441 } 442 } 443 444 class TestIApplicationToken implements IApplicationToken { 445 446 private final Binder mBinder = new Binder(); 447 @Override 448 public IBinder asBinder() { 449 return mBinder; 450 } 451 } 452 453 /** Used to track resize reports. */ 454 class TestWindowState extends WindowState { 455 boolean resizeReported; 456 457 TestWindowState(WindowManager.LayoutParams attrs, WindowToken token) { 458 super(sWm, sMockSession, new TestIWindow(), token, null, OP_NONE, 0, attrs, 0, 0, 459 false /* ownerCanAddInternalSystemWindow */); 460 sWm.mWindowMap.put(mClient.asBinder(), this); 461 } 462 463 @Override 464 void reportResized() { 465 super.reportResized(); 466 resizeReported = true; 467 } 468 469 @Override 470 public boolean isGoneForLayoutLw() { 471 return false; 472 } 473 474 @Override 475 void updateResizingWindowIfNeeded() { 476 // Used in AppWindowTokenTests#testLandscapeSeascapeRotationRelayout to deceive 477 // the system that it can actually update the window. 478 boolean hadSurface = mHasSurface; 479 mHasSurface = true; 480 481 super.updateResizingWindowIfNeeded(); 482 483 mHasSurface = hadSurface; 484 } 485 } 486} 487