1 /* 2 * Copyright (C) 2017 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 17 package com.android.server.wm; 18 19 import android.app.ActivityManager; 20 import android.content.Context; 21 import android.content.res.Configuration; 22 import android.graphics.Rect; 23 import android.os.Binder; 24 import android.os.IBinder; 25 import android.view.IApplicationToken; 26 import android.view.IWindow; 27 import android.view.WindowManager; 28 29 import static android.app.AppOpsManager.OP_NONE; 30 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; 31 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 32 33 import static com.android.server.wm.WindowContainer.POSITION_TOP; 34 import static org.mockito.Mockito.any; 35 import static org.mockito.Mockito.anyBoolean; 36 import static org.mockito.Mockito.anyFloat; 37 import static org.mockito.Mockito.anyInt; 38 import static org.mockito.Mockito.doAnswer; 39 import static org.mockito.Mockito.mock; 40 import static org.mockito.Mockito.when; 41 42 import org.mockito.invocation.InvocationOnMock; 43 44 /** 45 * A collection of static functions that can be referenced by other test packages to provide access 46 * to WindowManager related test functionality. 47 */ 48 public class WindowTestUtils { 49 public static int sNextTaskId = 0; 50 51 /** 52 * Retrieves an instance of a mock {@link WindowManagerService}. 53 */ getMockWindowManagerService()54 public static WindowManagerService getMockWindowManagerService() { 55 final WindowManagerService service = mock(WindowManagerService.class); 56 final WindowHashMap windowMap = new WindowHashMap(); 57 when(service.getWindowManagerLock()).thenReturn(windowMap); 58 return service; 59 } 60 61 /** 62 * Creates a mock instance of {@link StackWindowController}. 63 */ createMockStackWindowContainerController()64 public static StackWindowController createMockStackWindowContainerController() { 65 StackWindowController controller = mock(StackWindowController.class); 66 controller.mContainer = mock(TestTaskStack.class); 67 68 // many components rely on the {@link StackWindowController#adjustConfigurationForBounds} 69 // to properly set bounds values in the configuration. We must mimick those actions here. 70 doAnswer((InvocationOnMock invocationOnMock) -> { 71 final Configuration config = invocationOnMock.<Configuration>getArgument(7); 72 final Rect bounds = invocationOnMock.<Rect>getArgument(0); 73 config.windowConfiguration.setBounds(bounds); 74 return null; 75 }).when(controller).adjustConfigurationForBounds(any(), any(), any(), any(), 76 anyBoolean(), anyBoolean(), anyFloat(), any(), any(), anyInt()); 77 78 return controller; 79 } 80 81 /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */ createTaskInStack(WindowManagerService service, TaskStack stack, int userId)82 public static Task createTaskInStack(WindowManagerService service, TaskStack stack, 83 int userId) { 84 synchronized (service.mWindowMap) { 85 final Task newTask = new Task(sNextTaskId++, stack, userId, service, 0, false, 86 new ActivityManager.TaskDescription(), null); 87 stack.addTask(newTask, POSITION_TOP); 88 return newTask; 89 } 90 } 91 92 /** 93 * An extension of {@link TestTaskStack}, which overrides package scoped methods that would not 94 * normally be mocked out. 95 */ 96 public static class TestTaskStack extends TaskStack { TestTaskStack(WindowManagerService service, int stackId)97 TestTaskStack(WindowManagerService service, int stackId) { 98 super(service, stackId, null); 99 } 100 101 @Override addTask(Task task, int position, boolean showForAllUsers, boolean moveParents)102 void addTask(Task task, int position, boolean showForAllUsers, boolean moveParents) { 103 // Do nothing. 104 } 105 } 106 createTestAppWindowToken(DisplayContent dc)107 static TestAppWindowToken createTestAppWindowToken(DisplayContent dc) { 108 synchronized (dc.mService.mWindowMap) { 109 return new TestAppWindowToken(dc); 110 } 111 } 112 113 /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */ 114 public static class TestAppWindowToken extends AppWindowToken { 115 boolean mOnTop = false; 116 TestAppWindowToken(DisplayContent dc)117 private TestAppWindowToken(DisplayContent dc) { 118 super(dc.mService, new IApplicationToken.Stub() { 119 public String getName() {return null;} 120 }, false, dc, true /* fillsParent */); 121 } 122 TestAppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint, int configChanges, boolean launchTaskBehind, boolean alwaysFocusable, AppWindowContainerController controller)123 TestAppWindowToken(WindowManagerService service, IApplicationToken token, 124 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, 125 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, 126 int rotationAnimationHint, int configChanges, boolean launchTaskBehind, 127 boolean alwaysFocusable, AppWindowContainerController controller) { 128 super(service, token, voiceInteraction, dc, inputDispatchingTimeoutNanos, fullscreen, 129 showForAllUsers, targetSdk, orientation, rotationAnimationHint, configChanges, 130 launchTaskBehind, alwaysFocusable, controller); 131 } 132 getWindowsCount()133 int getWindowsCount() { 134 return mChildren.size(); 135 } 136 hasWindow(WindowState w)137 boolean hasWindow(WindowState w) { 138 return mChildren.contains(w); 139 } 140 getFirstChild()141 WindowState getFirstChild() { 142 return mChildren.peekFirst(); 143 } 144 getLastChild()145 WindowState getLastChild() { 146 return mChildren.peekLast(); 147 } 148 positionInParent()149 int positionInParent() { 150 return getParent().mChildren.indexOf(this); 151 } 152 setIsOnTop(boolean onTop)153 void setIsOnTop(boolean onTop) { 154 mOnTop = onTop; 155 } 156 157 @Override isOnTop()158 boolean isOnTop() { 159 return mOnTop; 160 } 161 } 162 createTestWindowToken(int type, DisplayContent dc)163 static TestWindowToken createTestWindowToken(int type, DisplayContent dc) { 164 return createTestWindowToken(type, dc, false /* persistOnEmpty */); 165 } 166 createTestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty)167 static TestWindowToken createTestWindowToken(int type, DisplayContent dc, 168 boolean persistOnEmpty) { 169 synchronized (dc.mService.mWindowMap) { 170 return new TestWindowToken(type, dc, persistOnEmpty); 171 } 172 } 173 174 /* Used so we can gain access to some protected members of the {@link WindowToken} class */ 175 public static class TestWindowToken extends WindowToken { 176 TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty)177 private TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) { 178 super(dc.mService, mock(IBinder.class), type, persistOnEmpty, dc, 179 false /* ownerCanManageAppTokens */); 180 } 181 getWindowsCount()182 int getWindowsCount() { 183 return mChildren.size(); 184 } 185 hasWindow(WindowState w)186 boolean hasWindow(WindowState w) { 187 return mChildren.contains(w); 188 } 189 } 190 191 /* Used so we can gain access to some protected members of the {@link Task} class */ 192 public static class TestTask extends Task { 193 boolean mShouldDeferRemoval = false; 194 boolean mOnDisplayChangedCalled = false; 195 private boolean mIsAnimating = false; 196 TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, int resizeMode, boolean supportsPictureInPicture, TaskWindowContainerController controller)197 TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, 198 int resizeMode, boolean supportsPictureInPicture, 199 TaskWindowContainerController controller) { 200 super(taskId, stack, userId, service, resizeMode, supportsPictureInPicture, 201 new ActivityManager.TaskDescription(), controller); 202 } 203 shouldDeferRemoval()204 boolean shouldDeferRemoval() { 205 return mShouldDeferRemoval; 206 } 207 positionInParent()208 int positionInParent() { 209 return getParent().mChildren.indexOf(this); 210 } 211 212 @Override onDisplayChanged(DisplayContent dc)213 void onDisplayChanged(DisplayContent dc) { 214 super.onDisplayChanged(dc); 215 mOnDisplayChangedCalled = true; 216 } 217 218 @Override isSelfAnimating()219 boolean isSelfAnimating() { 220 return mIsAnimating; 221 } 222 setLocalIsAnimating(boolean isAnimating)223 void setLocalIsAnimating(boolean isAnimating) { 224 mIsAnimating = isAnimating; 225 } 226 } 227 228 /** 229 * Used so we can gain access to some protected members of {@link TaskWindowContainerController} 230 * class. 231 */ 232 public static class TestTaskWindowContainerController extends TaskWindowContainerController { 233 TestTaskWindowContainerController(WindowTestsBase testsBase)234 TestTaskWindowContainerController(WindowTestsBase testsBase) { 235 this(testsBase.createStackControllerOnDisplay(testsBase.mDisplayContent)); 236 } 237 TestTaskWindowContainerController(StackWindowController stackController)238 TestTaskWindowContainerController(StackWindowController stackController) { 239 super(sNextTaskId++, new TaskWindowContainerListener() { 240 @Override 241 public void registerConfigurationChangeListener( 242 ConfigurationContainerListener listener) { 243 244 } 245 246 @Override 247 public void unregisterConfigurationChangeListener( 248 ConfigurationContainerListener listener) { 249 250 } 251 252 @Override 253 public void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) { 254 255 } 256 257 @Override 258 public void requestResize(Rect bounds, int resizeMode) { 259 260 } 261 }, stackController, 0 /* userId */, null /* bounds */, RESIZE_MODE_UNRESIZEABLE, 262 false /* supportsPictureInPicture */, true /* toTop*/, 263 true /* showForAllUsers */, new ActivityManager.TaskDescription(), 264 stackController.mService); 265 } 266 267 @Override createTask(int taskId, TaskStack stack, int userId, int resizeMode, boolean supportsPictureInPicture, ActivityManager.TaskDescription taskDescription)268 TestTask createTask(int taskId, TaskStack stack, int userId, int resizeMode, 269 boolean supportsPictureInPicture, ActivityManager.TaskDescription taskDescription) { 270 return new TestTask(taskId, stack, userId, mService, resizeMode, 271 supportsPictureInPicture, this); 272 } 273 } 274 275 public static class TestAppWindowContainerController extends AppWindowContainerController { 276 277 final IApplicationToken mToken; 278 TestAppWindowContainerController(TestTaskWindowContainerController taskController)279 TestAppWindowContainerController(TestTaskWindowContainerController taskController) { 280 this(taskController, new TestIApplicationToken()); 281 } 282 TestAppWindowContainerController(TestTaskWindowContainerController taskController, IApplicationToken token)283 TestAppWindowContainerController(TestTaskWindowContainerController taskController, 284 IApplicationToken token) { 285 super(taskController, token, null /* listener */, 0 /* index */, 286 SCREEN_ORIENTATION_UNSPECIFIED, true /* fullscreen */, 287 true /* showForAllUsers */, 0 /* configChanges */, false /* voiceInteraction */, 288 false /* launchTaskBehind */, false /* alwaysFocusable */, 289 0 /* targetSdkVersion */, 0 /* rotationAnimationHint */, 290 0 /* inputDispatchingTimeoutNanos */, taskController.mService); 291 mToken = token; 292 } 293 294 @Override createAppWindow(WindowManagerService service, IApplicationToken token, boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint, int configChanges, boolean launchTaskBehind, boolean alwaysFocusable, AppWindowContainerController controller)295 AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token, 296 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, 297 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, 298 int rotationAnimationHint, int configChanges, boolean launchTaskBehind, 299 boolean alwaysFocusable, AppWindowContainerController controller) { 300 return new TestAppWindowToken(service, token, voiceInteraction, dc, 301 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, 302 orientation, 303 rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable, 304 controller); 305 } 306 getAppWindowToken(DisplayContent dc)307 AppWindowToken getAppWindowToken(DisplayContent dc) { 308 return (AppWindowToken) dc.getWindowToken(mToken.asBinder()); 309 } 310 } 311 312 public static class TestIApplicationToken implements IApplicationToken { 313 314 private final Binder mBinder = new Binder(); 315 @Override asBinder()316 public IBinder asBinder() { 317 return mBinder; 318 } 319 @Override getName()320 public String getName() { 321 return null; 322 } 323 } 324 325 /** Used to track resize reports. */ 326 public static class TestWindowState extends WindowState { 327 boolean resizeReported; 328 TestWindowState(WindowManagerService service, Session session, IWindow window, WindowManager.LayoutParams attrs, WindowToken token)329 TestWindowState(WindowManagerService service, Session session, IWindow window, 330 WindowManager.LayoutParams attrs, WindowToken token) { 331 super(service, session, window, token, null, OP_NONE, 0, attrs, 0, 0, 332 false /* ownerCanAddInternalSystemWindow */); 333 } 334 335 @Override reportResized()336 void reportResized() { 337 super.reportResized(); 338 resizeReported = true; 339 } 340 341 @Override isGoneForLayoutLw()342 public boolean isGoneForLayoutLw() { 343 return false; 344 } 345 346 @Override updateResizingWindowIfNeeded()347 void updateResizingWindowIfNeeded() { 348 // Used in AppWindowTokenTests#testLandscapeSeascapeRotationRelayout to deceive 349 // the system that it can actually update the window. 350 boolean hadSurface = mHasSurface; 351 mHasSurface = true; 352 353 super.updateResizingWindowIfNeeded(); 354 355 mHasSurface = hadSurface; 356 } 357 } 358 } 359