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