ActivityTestsBase.java revision 943ebe705cece8f643d9d7ace005322ddf114d86
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 17package com.android.server.am; 18 19import static org.mockito.Mockito.mock; 20import static org.mockito.Mockito.doReturn; 21import static org.mockito.Mockito.any; 22import static org.mockito.Mockito.doAnswer; 23 24import org.mockito.invocation.InvocationOnMock; 25 26import android.app.ActivityManager; 27import android.content.ComponentName; 28import android.content.Context; 29import android.content.Intent; 30import android.content.pm.ActivityInfo; 31import android.content.pm.ApplicationInfo; 32import android.content.res.Configuration; 33import android.graphics.Rect; 34import android.os.HandlerThread; 35import android.os.Looper; 36import android.support.test.InstrumentationRegistry; 37import com.android.server.AttributeCache; 38import com.android.server.wm.AppWindowContainerController; 39import com.android.server.wm.StackWindowController; 40 41import com.android.server.wm.TaskWindowContainerController; 42import com.android.server.wm.WindowManagerService; 43import com.android.server.wm.WindowTestUtils; 44import org.junit.After; 45import org.junit.Before; 46import org.mockito.MockitoAnnotations; 47 48/** 49 * A base class to handle common operations in activity related unit tests. 50 */ 51public 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 getPictureInPictureBounds(float aspectRatio, 239 boolean useExistingStackBounds) { 240 return new Rect(50, 50, 100, 100); 241 } 242 }; 243 } else { 244 mStack = new TestActivityStack(this, recents, mOnTop); 245 } 246 } 247 248 return mStack; 249 } 250 } 251 } 252 253 private static WindowManagerService prepareMockWindowManager() { 254 final WindowManagerService service = mock(WindowManagerService.class); 255 256 doAnswer((InvocationOnMock invocationOnMock) -> { 257 final Runnable runnable = invocationOnMock.<Runnable>getArgument(0); 258 if (runnable != null) { 259 runnable.run(); 260 } 261 return null; 262 }).when(service).inSurfaceTransaction(any()); 263 264 return service; 265 } 266 267 protected interface ActivityStackReporter { 268 int onActivityRemovedFromStackInvocationCount(); 269 } 270 271 /** 272 * Override of {@link ActivityStack} that tracks test metrics, such as the number of times a 273 * method is called. Note that its functionality depends on the implementations of the 274 * construction arguments. 275 */ 276 protected static class TestActivityStack<T extends StackWindowController> 277 extends ActivityStack<T> implements ActivityStackReporter { 278 private int mOnActivityRemovedFromStackCount = 0; 279 private T mContainerController; 280 TestActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer, 281 RecentTasks recentTasks, boolean onTop) { 282 super(activityContainer, recentTasks, onTop); 283 } 284 285 @Override 286 void onActivityRemovedFromStack(ActivityRecord r) { 287 mOnActivityRemovedFromStackCount++; 288 super.onActivityRemovedFromStack(r); 289 } 290 291 // Returns the number of times {@link #onActivityRemovedFromStack} has been called 292 @Override 293 public int onActivityRemovedFromStackInvocationCount() { 294 return mOnActivityRemovedFromStackCount; 295 } 296 297 @Override 298 protected T createStackWindowController(int displayId, boolean onTop, 299 Rect outBounds) { 300 mContainerController = (T) WindowTestUtils.createMockStackWindowContainerController(); 301 return mContainerController; 302 } 303 304 @Override 305 T getWindowContainerController() { 306 return mContainerController; 307 } 308 } 309 310 311 protected static class ActivityStackBuilder { 312 private boolean mOnTop = true; 313 private int mStackId = 0; 314 private int mDisplayId = 1; 315 316 private final ActivityManagerService mService; 317 318 public ActivityStackBuilder(ActivityManagerService ams) { 319 mService = ams; 320 } 321 322 public ActivityStackBuilder setOnTop(boolean onTop) { 323 mOnTop = onTop; 324 return this; 325 } 326 327 public ActivityStackBuilder setStackId(int id) { 328 mStackId = id; 329 return this; 330 } 331 332 public ActivityStackBuilder setDisplayId(int id) { 333 mDisplayId = id; 334 return this; 335 } 336 337 public ActivityStack build() { 338 return createActivityStack(mService, mStackId, mDisplayId, mOnTop); 339 } 340 } 341} 342