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