ActivityTestsBase.java revision 9c844410572cd432f589d3e1c5a8ea5b67647775
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 public TestActivityStackSupervisor(ActivityManagerService service, Looper looper) { 155 super(service, looper); 156 mWindowManager = prepareMockWindowManager(); 157 } 158 159 // No home stack is set. 160 @Override 161 void moveHomeStackToFront(String reason) { 162 } 163 164 @Override 165 boolean moveHomeStackTaskToTop(String reason) { 166 return true; 167 } 168 169 // Invoked during {@link ActivityStack} creation. 170 @Override 171 void updateUIDsPresentOnDisplay() { 172 } 173 174 // Just return the current front task. 175 @Override 176 ActivityStack getNextFocusableStackLocked(ActivityStack currentFocus) { 177 return mFocusedStack; 178 } 179 180 // Called when moving activity to pinned stack. 181 @Override 182 void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges, 183 boolean preserveWindows) { 184 } 185 186 public <T extends ActivityStack> T createTestStack(ActivityManagerService service, 187 int stackId, boolean onTop) { 188 final ActivityDisplay display = new ActivityDisplay(); 189 final TestActivityContainer container = 190 new TestActivityContainer(service, stackId, display, onTop); 191 mActivityContainers.put(stackId, container); 192 return (T) container.getStack(); 193 } 194 195 @Override 196 protected <T extends ActivityStack> T getStack(int stackId, 197 boolean createStaticStackIfNeeded, boolean createOnTop) { 198 final T stack = super.getStack(stackId, createStaticStackIfNeeded, createOnTop); 199 200 if (stack != null || !createStaticStackIfNeeded) { 201 return stack; 202 } 203 204 return createTestStack(mService, stackId, createOnTop); 205 } 206 207 private class TestActivityContainer extends ActivityContainer { 208 private final ActivityManagerService mService; 209 210 private boolean mOnTop; 211 private int mStackId; 212 private ActivityStack mStack; 213 214 TestActivityContainer(ActivityManagerService service, int stackId, 215 ActivityDisplay activityDisplay, boolean onTop) { 216 super(stackId, activityDisplay, onTop); 217 mService = service; 218 } 219 220 @Override 221 protected void createStack(int stackId, boolean onTop) { 222 // normally stack creation is done here. However we need to do it on demand since 223 // we cannot set {@link mService} by the time the super constructor calling this 224 // method is invoked. 225 mOnTop = onTop; 226 mStackId = stackId; 227 } 228 229 public ActivityStack getStack() { 230 if (mStack == null) { 231 final RecentTasks recents = 232 new RecentTasks(mService, mService.mStackSupervisor); 233 if (mStackId == ActivityManager.StackId.PINNED_STACK_ID) { 234 mStack = new PinnedActivityStack(this, recents, mOnTop) { 235 @Override 236 Rect getPictureInPictureBounds(float aspectRatio, 237 boolean useExistingStackBounds) { 238 return new Rect(50, 50, 100, 100); 239 } 240 }; 241 } else { 242 mStack = new TestActivityStack(this, recents, mOnTop); 243 } 244 } 245 246 return mStack; 247 } 248 } 249 } 250 251 private static WindowManagerService prepareMockWindowManager() { 252 final WindowManagerService service = mock(WindowManagerService.class); 253 254 doAnswer((InvocationOnMock invocationOnMock) -> { 255 final Runnable runnable = invocationOnMock.<Runnable>getArgument(0); 256 if (runnable != null) { 257 runnable.run(); 258 } 259 return null; 260 }).when(service).inSurfaceTransaction(any()); 261 262 return service; 263 } 264 265 protected interface ActivityStackReporter { 266 int onActivityRemovedFromStackInvocationCount(); 267 } 268 269 /** 270 * Override of {@link ActivityStack} that tracks test metrics, such as the number of times a 271 * method is called. Note that its functionality depends on the implementations of the 272 * construction arguments. 273 */ 274 protected static class TestActivityStack<T extends StackWindowController> 275 extends ActivityStack<T> implements ActivityStackReporter { 276 private int mOnActivityRemovedFromStackCount = 0; 277 private T mContainerController; 278 TestActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer, 279 RecentTasks recentTasks, boolean onTop) { 280 super(activityContainer, recentTasks, onTop); 281 } 282 283 @Override 284 void onActivityRemovedFromStack(ActivityRecord r) { 285 mOnActivityRemovedFromStackCount++; 286 super.onActivityRemovedFromStack(r); 287 } 288 289 // Returns the number of times {@link #onActivityRemovedFromStack} has been called 290 @Override 291 public int onActivityRemovedFromStackInvocationCount() { 292 return mOnActivityRemovedFromStackCount; 293 } 294 295 @Override 296 protected T createStackWindowController(int displayId, boolean onTop, 297 Rect outBounds) { 298 mContainerController = (T) WindowTestUtils.createMockStackWindowContainerController(); 299 return mContainerController; 300 } 301 302 @Override 303 T getWindowContainerController() { 304 return mContainerController; 305 } 306 } 307 308 309 protected static class ActivityStackBuilder { 310 private boolean mOnTop = true; 311 private int mStackId = 0; 312 private int mDisplayId = 1; 313 314 private final ActivityManagerService mService; 315 316 public ActivityStackBuilder(ActivityManagerService ams) { 317 mService = ams; 318 } 319 320 public ActivityStackBuilder setOnTop(boolean onTop) { 321 mOnTop = onTop; 322 return this; 323 } 324 325 public ActivityStackBuilder setStackId(int id) { 326 mStackId = id; 327 return this; 328 } 329 330 public ActivityStackBuilder setDisplayId(int id) { 331 mDisplayId = id; 332 return this; 333 } 334 335 public ActivityStack build() { 336 return createActivityStack(mService, mStackId, mDisplayId, mOnTop); 337 } 338 } 339} 340