WindowTestsBase.java revision 367ff7fd5251790ad8dc086bd386be8cba1dda5c
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); 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 } 228 229 int getWindowsCount() { 230 return mChildren.size(); 231 } 232 233 boolean hasWindow(WindowState w) { 234 return mChildren.contains(w); 235 } 236 } 237 238 /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */ 239 static class TestAppWindowToken extends AppWindowToken { 240 241 TestAppWindowToken(DisplayContent dc) { 242 super(sWm, null, false, dc); 243 } 244 245 int getWindowsCount() { 246 return mChildren.size(); 247 } 248 249 boolean hasWindow(WindowState w) { 250 return mChildren.contains(w); 251 } 252 253 WindowState getFirstChild() { 254 return mChildren.getFirst(); 255 } 256 257 WindowState getLastChild() { 258 return mChildren.getLast(); 259 } 260 } 261 262 /* Used so we can gain access to some protected members of the {@link Task} class */ 263 class TestTask extends Task { 264 265 boolean mShouldDeferRemoval = false; 266 boolean mOnDisplayChangedCalled = false; 267 private boolean mUseLocalIsAnimating = false; 268 private boolean mIsAnimating = false; 269 270 TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds, 271 Configuration overrideConfig, boolean isOnTopLauncher, int resizeMode, 272 boolean supportsPictureInPicture, boolean homeTask, 273 TaskWindowContainerController controller) { 274 super(taskId, stack, userId, service, bounds, overrideConfig, isOnTopLauncher, 275 resizeMode, supportsPictureInPicture, homeTask, new TaskDescription(), 276 controller); 277 } 278 279 boolean shouldDeferRemoval() { 280 return mShouldDeferRemoval; 281 } 282 283 int positionInParent() { 284 return getParent().mChildren.indexOf(this); 285 } 286 287 @Override 288 void onDisplayChanged(DisplayContent dc) { 289 super.onDisplayChanged(dc); 290 mOnDisplayChangedCalled = true; 291 } 292 293 @Override 294 boolean isAnimating() { 295 return mUseLocalIsAnimating ? mIsAnimating : super.isAnimating(); 296 } 297 298 void setLocalIsAnimating(boolean isAnimating) { 299 mUseLocalIsAnimating = true; 300 mIsAnimating = isAnimating; 301 } 302 } 303 304 /** 305 * Used so we can gain access to some protected members of {@link TaskWindowContainerController} 306 * class. 307 */ 308 class TestTaskWindowContainerController extends TaskWindowContainerController { 309 310 TestTaskWindowContainerController() { 311 this(createStackControllerOnDisplay(sDisplayContent)); 312 } 313 314 TestTaskWindowContainerController(StackWindowController stackController) { 315 super(sNextTaskId++, new TaskWindowContainerListener() { 316 @Override 317 public void onSnapshotChanged(TaskSnapshot snapshot) { 318 319 } 320 321 @Override 322 public void requestResize(Rect bounds, int resizeMode) { 323 324 } 325 }, stackController, 0 /* userId */, null /* bounds */, 326 EMPTY /* overrideConfig*/, RESIZE_MODE_UNRESIZEABLE, 327 false /* supportsPictureInPicture */, false /* homeTask*/, 328 false /* isOnTopLauncher */, true /* toTop*/, true /* showForAllUsers */, 329 new TaskDescription(), sWm); 330 } 331 332 @Override 333 TestTask createTask(int taskId, TaskStack stack, int userId, Rect bounds, 334 Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture, 335 boolean homeTask, boolean isOnTopLauncher, TaskDescription taskDescription) { 336 return new TestTask(taskId, stack, userId, mService, bounds, overrideConfig, 337 isOnTopLauncher, resizeMode, supportsPictureInPicture, homeTask, this); 338 } 339 } 340 341 class TestAppWindowContainerController extends AppWindowContainerController { 342 343 final IApplicationToken mToken; 344 345 TestAppWindowContainerController(TestTaskWindowContainerController taskController) { 346 this(taskController, new TestIApplicationToken()); 347 } 348 349 TestAppWindowContainerController(TestTaskWindowContainerController taskController, 350 IApplicationToken token) { 351 super(taskController, token, null /* listener */, 0 /* index */, 352 SCREEN_ORIENTATION_UNSPECIFIED, true /* fullscreen */, 353 true /* showForAllUsers */, 0 /* configChanges */, false /* voiceInteraction */, 354 false /* launchTaskBehind */, false /* alwaysFocusable */, 355 0 /* targetSdkVersion */, 0 /* rotationAnimationHint */, 356 0 /* inputDispatchingTimeoutNanos */, sWm); 357 mToken = token; 358 } 359 360 AppWindowToken getAppWindowToken() { 361 return (AppWindowToken) sDisplayContent.getWindowToken(mToken.asBinder()); 362 } 363 } 364 365 class TestIApplicationToken implements IApplicationToken { 366 367 private final Binder mBinder = new Binder(); 368 @Override 369 public IBinder asBinder() { 370 return mBinder; 371 } 372 } 373 374 /** Used to track resize reports. */ 375 class TestWindowState extends WindowState { 376 boolean resizeReported; 377 378 TestWindowState(WindowManager.LayoutParams attrs, WindowToken token) { 379 super(sWm, sMockSession, sIWindow, token, null, OP_NONE, 0, attrs, 0, 0); 380 } 381 382 @Override 383 void reportResized() { 384 super.reportResized(); 385 resizeReported = true; 386 } 387 388 @Override 389 public boolean isGoneForLayoutLw() { 390 return false; 391 } 392 393 @Override 394 void updateResizingWindowIfNeeded() { 395 // Used in AppWindowTokenTests#testLandscapeSeascapeRotationRelayout to deceive 396 // the system that it can actually update the window. 397 boolean hadSurface = mHasSurface; 398 mHasSurface = true; 399 400 super.updateResizingWindowIfNeeded(); 401 402 mHasSurface = hadSurface; 403 } 404 } 405} 406