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