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