ActivityTestsBase.java revision 3345c4ea9687bb35a8c419ec21ec90b49616b2c9
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 mStack = mStackId == ActivityManager.StackId.PINNED_STACK_ID 234 ? new PinnedActivityStack(this, recents, mOnTop) 235 : new TestActivityStack(this, recents, mOnTop); 236 } 237 238 return mStack; 239 } 240 } 241 } 242 243 private static WindowManagerService prepareMockWindowManager() { 244 final WindowManagerService service = mock(WindowManagerService.class); 245 246 doAnswer((InvocationOnMock invocationOnMock) -> { 247 final Runnable runnable = invocationOnMock.<Runnable>getArgument(0); 248 if (runnable != null) { 249 runnable.run(); 250 } 251 return null; 252 }).when(service).inSurfaceTransaction(any()); 253 254 return service; 255 } 256 257 protected interface ActivityStackReporter { 258 int onActivityRemovedFromStackInvocationCount(); 259 } 260 261 /** 262 * Override of {@link ActivityStack} that tracks test metrics, such as the number of times a 263 * method is called. Note that its functionality depends on the implementations of the 264 * construction arguments. 265 */ 266 protected static class TestActivityStack<T extends StackWindowController> 267 extends ActivityStack<T> implements ActivityStackReporter { 268 private int mOnActivityRemovedFromStackCount = 0; 269 private T mContainerController; 270 TestActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer, 271 RecentTasks recentTasks, boolean onTop) { 272 super(activityContainer, recentTasks, onTop); 273 } 274 275 @Override 276 void onActivityRemovedFromStack(ActivityRecord r) { 277 mOnActivityRemovedFromStackCount++; 278 super.onActivityRemovedFromStack(r); 279 } 280 281 // Returns the number of times {@link #onActivityRemovedFromStack} has been called 282 @Override 283 public int onActivityRemovedFromStackInvocationCount() { 284 return mOnActivityRemovedFromStackCount; 285 } 286 287 @Override 288 protected T createStackWindowController(int displayId, boolean onTop, 289 Rect outBounds) { 290 mContainerController = (T) WindowTestUtils.createMockStackWindowContainerController(); 291 return mContainerController; 292 } 293 294 @Override 295 T getWindowContainerController() { 296 return mContainerController; 297 } 298 } 299 300 301 protected static class ActivityStackBuilder { 302 private boolean mOnTop = true; 303 private int mStackId = 0; 304 private int mDisplayId = 1; 305 306 private final ActivityManagerService mService; 307 308 public ActivityStackBuilder(ActivityManagerService ams) { 309 mService = ams; 310 } 311 312 public ActivityStackBuilder setOnTop(boolean onTop) { 313 mOnTop = onTop; 314 return this; 315 } 316 317 public ActivityStackBuilder setStackId(int id) { 318 mStackId = id; 319 return this; 320 } 321 322 public ActivityStackBuilder setDisplayId(int id) { 323 mDisplayId = id; 324 return this; 325 } 326 327 public ActivityStack build() { 328 return createActivityStack(mService, mStackId, mDisplayId, mOnTop); 329 } 330 } 331} 332