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.am; 18 19 import static org.mockito.Mockito.mock; 20 import static org.mockito.Mockito.doReturn; 21 import static org.mockito.Mockito.any; 22 import static org.mockito.Mockito.doAnswer; 23 24 import org.mockito.invocation.InvocationOnMock; 25 26 import android.app.ActivityManager; 27 import android.content.ComponentName; 28 import android.content.Context; 29 import android.content.Intent; 30 import android.content.pm.ActivityInfo; 31 import android.content.pm.ApplicationInfo; 32 import android.content.res.Configuration; 33 import android.graphics.Rect; 34 import android.os.HandlerThread; 35 import android.os.Looper; 36 import android.support.test.InstrumentationRegistry; 37 import com.android.server.AttributeCache; 38 import com.android.server.wm.AppWindowContainerController; 39 import com.android.server.wm.StackWindowController; 40 41 import com.android.server.wm.TaskWindowContainerController; 42 import com.android.server.wm.WindowManagerService; 43 import com.android.server.wm.WindowTestUtils; 44 import org.junit.After; 45 import org.junit.Before; 46 import org.mockito.MockitoAnnotations; 47 48 /** 49 * A base class to handle common operations in activity related unit tests. 50 */ 51 public class ActivityTestsBase { 52 private final Context mContext = InstrumentationRegistry.getContext(); 53 private HandlerThread mHandlerThread; 54 55 // Grabbing an instance of {@link WindowManagerService} creates it if not present so this must 56 // be called at before any tests. 57 private final WindowManagerService mWms = WindowTestUtils.getWindowManagerService(mContext); 58 59 @Before 60 public void setUp() throws Exception { 61 MockitoAnnotations.initMocks(this); 62 mHandlerThread = new HandlerThread("ActivityTestsBaseThread"); 63 mHandlerThread.start(); 64 } 65 66 @After 67 public void tearDown() { 68 mHandlerThread.quitSafely(); 69 } 70 71 protected ActivityManagerService createActivityManagerService() { 72 final ActivityManagerService service = new TestActivityManagerService(mContext); 73 service.mWindowManager = WindowTestUtils.getMockWindowManagerService(); 74 return service; 75 } 76 77 protected static ActivityStack createActivityStack(ActivityManagerService service, 78 int stackId, int displayId, boolean onTop) { 79 if (service.mStackSupervisor instanceof TestActivityStackSupervisor) { 80 return ((TestActivityStackSupervisor) service.mStackSupervisor) 81 .createTestStack(service, stackId, onTop); 82 } 83 84 return null; 85 } 86 87 protected static ActivityRecord createActivity(ActivityManagerService service, 88 ComponentName component, TaskRecord task) { 89 Intent intent = new Intent(); 90 intent.setComponent(component); 91 final ActivityInfo aInfo = new ActivityInfo(); 92 aInfo.applicationInfo = new ApplicationInfo(); 93 aInfo.applicationInfo.packageName = component.getPackageName(); 94 AttributeCache.init(service.mContext); 95 final ActivityRecord activity = new ActivityRecord(service, null /* caller */, 96 0 /* launchedFromPid */, 0, null, intent, null, 97 aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */, 98 0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */, 99 service.mStackSupervisor, null /* container */, null /* options */, 100 null /* sourceRecord */); 101 activity.mWindowContainerController = mock(AppWindowContainerController.class); 102 103 if (task != null) { 104 task.addActivityToTop(activity); 105 } 106 107 return activity; 108 } 109 110 protected static TaskRecord createTask(ActivityManagerService service, 111 ComponentName component, int stackId) { 112 final ActivityInfo aInfo = new ActivityInfo(); 113 aInfo.applicationInfo = new ApplicationInfo(); 114 aInfo.applicationInfo.packageName = component.getPackageName(); 115 116 Intent intent = new Intent(); 117 intent.setComponent(component); 118 119 final TaskRecord task = new TaskRecord(service, 0, aInfo, intent /*intent*/, 120 null /*_taskDescription*/, new ActivityManager.TaskThumbnailInfo()); 121 final ActivityStack stack = service.mStackSupervisor.getStack(stackId, 122 true /*createStaticStackIfNeeded*/, true /*onTop*/); 123 stack.addTask(task, true, "creating test task"); 124 task.setStack(stack); 125 task.setWindowContainerController(mock(TaskWindowContainerController.class)); 126 127 return task; 128 } 129 130 131 /** 132 * An {@link ActivityManagerService} subclass which provides a test 133 * {@link ActivityStackSupervisor}. 134 */ 135 protected static class TestActivityManagerService extends ActivityManagerService { 136 public TestActivityManagerService(Context context) { 137 super(context); 138 mSupportsMultiWindow = true; 139 mSupportsMultiDisplay = true; 140 mWindowManager = WindowTestUtils.getWindowManagerService(context); 141 } 142 143 @Override 144 protected ActivityStackSupervisor createStackSupervisor() { 145 return new TestActivityStackSupervisor(this, mHandlerThread.getLooper()); 146 } 147 } 148 149 /** 150 * An {@link ActivityStackSupervisor} which stubs out certain methods that depend on 151 * setup not available in the test environment. Also specifies an injector for 152 */ 153 protected static class TestActivityStackSupervisor extends ActivityStackSupervisor { 154 private final ActivityDisplay mDisplay; 155 156 public TestActivityStackSupervisor(ActivityManagerService service, Looper looper) { 157 super(service, looper); 158 mWindowManager = prepareMockWindowManager(); 159 mDisplay = new ActivityDisplay(); 160 } 161 162 // No home stack is set. 163 @Override 164 void moveHomeStackToFront(String reason) { 165 } 166 167 @Override 168 boolean moveHomeStackTaskToTop(String reason) { 169 return true; 170 } 171 172 // Invoked during {@link ActivityStack} creation. 173 @Override 174 void updateUIDsPresentOnDisplay() { 175 } 176 177 // Just return the current front task. 178 @Override 179 ActivityStack getNextFocusableStackLocked(ActivityStack currentFocus) { 180 return mFocusedStack; 181 } 182 183 // Called when moving activity to pinned stack. 184 @Override 185 void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges, 186 boolean preserveWindows) { 187 } 188 189 public <T extends ActivityStack> T createTestStack(ActivityManagerService service, 190 int stackId, boolean onTop) { 191 final TestActivityContainer container = 192 new TestActivityContainer(service, stackId, mDisplay, onTop); 193 mActivityContainers.put(stackId, container); 194 return (T) container.getStack(); 195 } 196 197 @Override 198 protected <T extends ActivityStack> T getStack(int stackId, 199 boolean createStaticStackIfNeeded, boolean createOnTop) { 200 final T stack = super.getStack(stackId, createStaticStackIfNeeded, createOnTop); 201 202 if (stack != null || !createStaticStackIfNeeded) { 203 return stack; 204 } 205 206 return createTestStack(mService, stackId, createOnTop); 207 } 208 209 private class TestActivityContainer extends ActivityContainer { 210 private final ActivityManagerService mService; 211 212 private boolean mOnTop; 213 private int mStackId; 214 private ActivityStack mStack; 215 216 TestActivityContainer(ActivityManagerService service, int stackId, 217 ActivityDisplay activityDisplay, boolean onTop) { 218 super(stackId, activityDisplay, onTop); 219 mService = service; 220 } 221 222 @Override 223 protected void createStack(int stackId, boolean onTop) { 224 // normally stack creation is done here. However we need to do it on demand since 225 // we cannot set {@link mService} by the time the super constructor calling this 226 // method is invoked. 227 mOnTop = onTop; 228 mStackId = stackId; 229 } 230 231 public ActivityStack getStack() { 232 if (mStack == null) { 233 final RecentTasks recents = 234 new RecentTasks(mService, mService.mStackSupervisor); 235 if (mStackId == ActivityManager.StackId.PINNED_STACK_ID) { 236 mStack = new PinnedActivityStack(this, recents, mOnTop) { 237 @Override 238 Rect getDefaultPictureInPictureBounds(float aspectRatio) { 239 return new Rect(50, 50, 100, 100); 240 } 241 }; 242 } else { 243 mStack = new TestActivityStack(this, recents, mOnTop); 244 } 245 } 246 247 return mStack; 248 } 249 } 250 } 251 252 private static WindowManagerService prepareMockWindowManager() { 253 final WindowManagerService service = mock(WindowManagerService.class); 254 255 doAnswer((InvocationOnMock invocationOnMock) -> { 256 final Runnable runnable = invocationOnMock.<Runnable>getArgument(0); 257 if (runnable != null) { 258 runnable.run(); 259 } 260 return null; 261 }).when(service).inSurfaceTransaction(any()); 262 263 return service; 264 } 265 266 protected interface ActivityStackReporter { 267 int onActivityRemovedFromStackInvocationCount(); 268 } 269 270 /** 271 * Override of {@link ActivityStack} that tracks test metrics, such as the number of times a 272 * method is called. Note that its functionality depends on the implementations of the 273 * construction arguments. 274 */ 275 protected static class TestActivityStack<T extends StackWindowController> 276 extends ActivityStack<T> implements ActivityStackReporter { 277 private int mOnActivityRemovedFromStackCount = 0; 278 private T mContainerController; 279 TestActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer, 280 RecentTasks recentTasks, boolean onTop) { 281 super(activityContainer, recentTasks, onTop); 282 } 283 284 @Override 285 void onActivityRemovedFromStack(ActivityRecord r) { 286 mOnActivityRemovedFromStackCount++; 287 super.onActivityRemovedFromStack(r); 288 } 289 290 // Returns the number of times {@link #onActivityRemovedFromStack} has been called 291 @Override 292 public int onActivityRemovedFromStackInvocationCount() { 293 return mOnActivityRemovedFromStackCount; 294 } 295 296 @Override 297 protected T createStackWindowController(int displayId, boolean onTop, 298 Rect outBounds) { 299 mContainerController = (T) WindowTestUtils.createMockStackWindowContainerController(); 300 return mContainerController; 301 } 302 303 @Override 304 T getWindowContainerController() { 305 return mContainerController; 306 } 307 } 308 309 310 protected static class ActivityStackBuilder { 311 private boolean mOnTop = true; 312 private int mStackId = 0; 313 private int mDisplayId = 1; 314 315 private final ActivityManagerService mService; 316 317 public ActivityStackBuilder(ActivityManagerService ams) { 318 mService = ams; 319 } 320 321 public ActivityStackBuilder setOnTop(boolean onTop) { 322 mOnTop = onTop; 323 return this; 324 } 325 326 public ActivityStackBuilder setStackId(int id) { 327 mStackId = id; 328 return this; 329 } 330 331 public ActivityStackBuilder setDisplayId(int id) { 332 mDisplayId = id; 333 return this; 334 } 335 336 public ActivityStack build() { 337 return createActivityStack(mService, mStackId, mDisplayId, mOnTop); 338 } 339 } 340 } 341