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