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 android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 20 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; 23 import static android.view.Display.DEFAULT_DISPLAY; 24 import static org.mockito.Mockito.mock; 25 import static org.mockito.Mockito.doNothing; 26 import static org.mockito.Mockito.doReturn; 27 import static org.mockito.Mockito.any; 28 import static org.mockito.Mockito.anyBoolean; 29 import static org.mockito.Mockito.anyInt; 30 import static org.mockito.Mockito.doAnswer; 31 import static org.mockito.Mockito.spy; 32 33 import android.app.ActivityOptions; 34 import com.android.server.wm.DisplayWindowController; 35 36 import org.junit.Rule; 37 import org.mockito.invocation.InvocationOnMock; 38 39 import android.app.IApplicationThread; 40 import android.content.ComponentName; 41 import android.content.Context; 42 import android.content.Intent; 43 import android.content.pm.ActivityInfo; 44 import android.content.pm.ApplicationInfo; 45 import android.content.pm.IPackageManager; 46 import android.content.res.Configuration; 47 import android.graphics.Rect; 48 import android.hardware.display.DisplayManager; 49 import android.os.HandlerThread; 50 import android.os.Looper; 51 import android.service.voice.IVoiceInteractionSession; 52 import android.support.test.InstrumentationRegistry; 53 import android.testing.DexmakerShareClassLoaderRule; 54 55 56 import com.android.internal.app.IVoiceInteractor; 57 58 import com.android.server.AttributeCache; 59 import com.android.server.wm.AppWindowContainerController; 60 import com.android.server.wm.PinnedStackWindowController; 61 import com.android.server.wm.StackWindowController; 62 import com.android.server.wm.TaskWindowContainerController; 63 import com.android.server.wm.WindowManagerService; 64 import com.android.server.wm.WindowTestUtils; 65 import org.junit.After; 66 import org.junit.Before; 67 import org.mockito.MockitoAnnotations; 68 69 70 /** 71 * A base class to handle common operations in activity related unit tests. 72 */ 73 public class ActivityTestsBase { 74 private static boolean sOneTimeSetupDone = false; 75 76 @Rule 77 public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = 78 new DexmakerShareClassLoaderRule(); 79 80 private final Context mContext = InstrumentationRegistry.getContext(); 81 private HandlerThread mHandlerThread; 82 83 // Default package name 84 static final String DEFAULT_COMPONENT_PACKAGE_NAME = "com.foo"; 85 86 // Default base activity name 87 private static final String DEFAULT_COMPONENT_CLASS_NAME = ".BarActivity"; 88 89 @Before setUp()90 public void setUp() throws Exception { 91 if (!sOneTimeSetupDone) { 92 sOneTimeSetupDone = true; 93 MockitoAnnotations.initMocks(this); 94 } 95 mHandlerThread = new HandlerThread("ActivityTestsBaseThread"); 96 mHandlerThread.start(); 97 } 98 99 @After tearDown()100 public void tearDown() { 101 mHandlerThread.quitSafely(); 102 } 103 createActivityManagerService()104 protected ActivityManagerService createActivityManagerService() { 105 final ActivityManagerService service = 106 setupActivityManagerService(new TestActivityManagerService(mContext)); 107 AttributeCache.init(mContext); 108 return service; 109 } 110 setupActivityManagerService(ActivityManagerService service)111 protected ActivityManagerService setupActivityManagerService(ActivityManagerService service) { 112 service = spy(service); 113 doReturn(mock(IPackageManager.class)).when(service).getPackageManager(); 114 doNothing().when(service).grantEphemeralAccessLocked(anyInt(), any(), anyInt(), anyInt()); 115 service.mWindowManager = prepareMockWindowManager(); 116 return service; 117 } 118 119 /** 120 * Builder for creating new activities. 121 */ 122 protected static class ActivityBuilder { 123 // An id appended to the end of the component name to make it unique 124 private static int sCurrentActivityId = 0; 125 126 127 128 private final ActivityManagerService mService; 129 130 private ComponentName mComponent; 131 private TaskRecord mTaskRecord; 132 private int mUid; 133 private boolean mCreateTask; 134 private ActivityStack mStack; 135 private int mActivityFlags; 136 ActivityBuilder(ActivityManagerService service)137 ActivityBuilder(ActivityManagerService service) { 138 mService = service; 139 } 140 setComponent(ComponentName component)141 ActivityBuilder setComponent(ComponentName component) { 142 mComponent = component; 143 return this; 144 } 145 getDefaultComponent()146 static ComponentName getDefaultComponent() { 147 return ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, 148 DEFAULT_COMPONENT_PACKAGE_NAME); 149 } 150 setTask(TaskRecord task)151 ActivityBuilder setTask(TaskRecord task) { 152 mTaskRecord = task; 153 return this; 154 } 155 setActivityFlags(int flags)156 ActivityBuilder setActivityFlags(int flags) { 157 mActivityFlags = flags; 158 return this; 159 } 160 setStack(ActivityStack stack)161 ActivityBuilder setStack(ActivityStack stack) { 162 mStack = stack; 163 return this; 164 } 165 setCreateTask(boolean createTask)166 ActivityBuilder setCreateTask(boolean createTask) { 167 mCreateTask = createTask; 168 return this; 169 } 170 setUid(int uid)171 ActivityBuilder setUid(int uid) { 172 mUid = uid; 173 return this; 174 } 175 build()176 ActivityRecord build() { 177 if (mComponent == null) { 178 final int id = sCurrentActivityId++; 179 mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, 180 DEFAULT_COMPONENT_CLASS_NAME + id); 181 } 182 183 if (mCreateTask) { 184 mTaskRecord = new TaskBuilder(mService.mStackSupervisor) 185 .setComponent(mComponent) 186 .setStack(mStack).build(); 187 } 188 189 Intent intent = new Intent(); 190 intent.setComponent(mComponent); 191 final ActivityInfo aInfo = new ActivityInfo(); 192 aInfo.applicationInfo = new ApplicationInfo(); 193 aInfo.applicationInfo.packageName = mComponent.getPackageName(); 194 aInfo.applicationInfo.uid = mUid; 195 aInfo.flags |= mActivityFlags; 196 197 final ActivityRecord activity = new ActivityRecord(mService, null /* caller */, 198 0 /* launchedFromPid */, 0, null, intent, null, 199 aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */, 200 0 /* reqCode */, false /*componentSpecified*/, false /* rootVoiceInteraction */, 201 mService.mStackSupervisor, null /* options */, null /* sourceRecord */); 202 activity.mWindowContainerController = mock(AppWindowContainerController.class); 203 204 if (mTaskRecord != null) { 205 mTaskRecord.addActivityToTop(activity); 206 } 207 208 activity.setProcess(new ProcessRecord(null, null, 209 mService.mContext.getApplicationInfo(), "name", 12345)); 210 activity.app.thread = mock(IApplicationThread.class); 211 212 return activity; 213 } 214 } 215 216 /** 217 * Builder for creating new tasks. 218 */ 219 protected static class TaskBuilder { 220 // Default package name 221 static final String DEFAULT_PACKAGE = "com.bar"; 222 223 private final ActivityStackSupervisor mSupervisor; 224 225 private ComponentName mComponent; 226 private String mPackage; 227 private int mFlags = 0; 228 private int mTaskId = 0; 229 private int mUserId = 0; 230 private IVoiceInteractionSession mVoiceSession; 231 private boolean mCreateStack = true; 232 233 private ActivityStack mStack; 234 TaskBuilder(ActivityStackSupervisor supervisor)235 TaskBuilder(ActivityStackSupervisor supervisor) { 236 mSupervisor = supervisor; 237 } 238 setComponent(ComponentName component)239 TaskBuilder setComponent(ComponentName component) { 240 mComponent = component; 241 return this; 242 } 243 setPackage(String packageName)244 TaskBuilder setPackage(String packageName) { 245 mPackage = packageName; 246 return this; 247 } 248 249 /** 250 * Set to {@code true} by default, set to {@code false} to prevent the task from 251 * automatically creating a parent stack. 252 */ setCreateStack(boolean createStack)253 TaskBuilder setCreateStack(boolean createStack) { 254 mCreateStack = createStack; 255 return this; 256 } 257 setVoiceSession(IVoiceInteractionSession session)258 TaskBuilder setVoiceSession(IVoiceInteractionSession session) { 259 mVoiceSession = session; 260 return this; 261 } 262 setFlags(int flags)263 TaskBuilder setFlags(int flags) { 264 mFlags = flags; 265 return this; 266 } 267 setTaskId(int taskId)268 TaskBuilder setTaskId(int taskId) { 269 mTaskId = taskId; 270 return this; 271 } 272 setUserId(int userId)273 TaskBuilder setUserId(int userId) { 274 mUserId = userId; 275 return this; 276 } 277 setStack(ActivityStack stack)278 TaskBuilder setStack(ActivityStack stack) { 279 mStack = stack; 280 return this; 281 } 282 build()283 TaskRecord build() { 284 if (mStack == null && mCreateStack) { 285 mStack = mSupervisor.getDefaultDisplay().createStack( 286 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); 287 } 288 289 final ActivityInfo aInfo = new ActivityInfo(); 290 aInfo.applicationInfo = new ApplicationInfo(); 291 aInfo.applicationInfo.packageName = mPackage; 292 293 Intent intent = new Intent(); 294 if (mComponent == null) { 295 mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, 296 DEFAULT_COMPONENT_CLASS_NAME); 297 } 298 299 intent.setComponent(mComponent); 300 intent.setFlags(mFlags); 301 302 final TestTaskRecord task = new TestTaskRecord(mSupervisor.mService, mTaskId, aInfo, 303 intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/); 304 task.userId = mUserId; 305 306 if (mStack != null) { 307 mSupervisor.setFocusStackUnchecked("test", mStack); 308 mStack.addTask(task, true, "creating test task"); 309 task.setStack(mStack); 310 task.setWindowContainerController(); 311 } 312 313 task.touchActiveTime(); 314 315 return task; 316 } 317 318 private static class TestTaskRecord extends TaskRecord { TestTaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent, IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor)319 TestTaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, 320 Intent _intent, IVoiceInteractionSession _voiceSession, 321 IVoiceInteractor _voiceInteractor) { 322 super(service, _taskId, info, _intent, _voiceSession, _voiceInteractor); 323 } 324 325 @Override createWindowContainer(boolean onTop, boolean showForAllUsers)326 void createWindowContainer(boolean onTop, boolean showForAllUsers) { 327 setWindowContainerController(); 328 } 329 setWindowContainerController()330 private void setWindowContainerController() { 331 setWindowContainerController(mock(TaskWindowContainerController.class)); 332 } 333 } 334 } 335 336 /** 337 * An {@link ActivityManagerService} subclass which provides a test 338 * {@link ActivityStackSupervisor}. 339 */ 340 protected static class TestActivityManagerService extends ActivityManagerService { 341 private ClientLifecycleManager mLifecycleManager; 342 private LockTaskController mLockTaskController; 343 TestActivityManagerService(Context context)344 TestActivityManagerService(Context context) { 345 super(context); 346 mSupportsMultiWindow = true; 347 mSupportsMultiDisplay = true; 348 mSupportsSplitScreenMultiWindow = true; 349 mSupportsFreeformWindowManagement = true; 350 mSupportsPictureInPicture = true; 351 mWindowManager = WindowTestUtils.getMockWindowManagerService(); 352 } 353 354 @Override getLifecycleManager()355 public ClientLifecycleManager getLifecycleManager() { 356 if (mLifecycleManager == null) { 357 return super.getLifecycleManager(); 358 } 359 return mLifecycleManager; 360 } 361 getLockTaskController()362 public LockTaskController getLockTaskController() { 363 if (mLockTaskController == null) { 364 mLockTaskController = spy(super.getLockTaskController()); 365 } 366 367 return mLockTaskController; 368 } 369 setLifecycleManager(ClientLifecycleManager manager)370 void setLifecycleManager(ClientLifecycleManager manager) { 371 mLifecycleManager = manager; 372 } 373 374 @Override createStackSupervisor()375 final protected ActivityStackSupervisor createStackSupervisor() { 376 final ActivityStackSupervisor supervisor = spy(createTestSupervisor()); 377 final KeyguardController keyguardController = mock(KeyguardController.class); 378 379 // No home stack is set. 380 doNothing().when(supervisor).moveHomeStackToFront(any()); 381 doReturn(true).when(supervisor).moveHomeStackTaskToTop(any()); 382 // Invoked during {@link ActivityStack} creation. 383 doNothing().when(supervisor).updateUIDsPresentOnDisplay(); 384 // Always keep things awake. 385 doReturn(true).when(supervisor).hasAwakeDisplay(); 386 // Called when moving activity to pinned stack. 387 doNothing().when(supervisor).ensureActivitiesVisibleLocked(any(), anyInt(), anyBoolean()); 388 // Do not schedule idle timeouts 389 doNothing().when(supervisor).scheduleIdleTimeoutLocked(any()); 390 // unit test version does not handle launch wake lock 391 doNothing().when(supervisor).acquireLaunchWakelock(); 392 doReturn(keyguardController).when(supervisor).getKeyguardController(); 393 394 supervisor.initialize(); 395 396 return supervisor; 397 } 398 createTestSupervisor()399 protected ActivityStackSupervisor createTestSupervisor() { 400 return new TestActivityStackSupervisor(this, mHandlerThread.getLooper()); 401 } 402 403 @Override updateUsageStats(ActivityRecord component, boolean resumed)404 void updateUsageStats(ActivityRecord component, boolean resumed) { 405 } 406 } 407 408 /** 409 * An {@link ActivityStackSupervisor} which stubs out certain methods that depend on 410 * setup not available in the test environment. Also specifies an injector for 411 */ 412 protected static class TestActivityStackSupervisor extends ActivityStackSupervisor { 413 private ActivityDisplay mDisplay; 414 private KeyguardController mKeyguardController; 415 TestActivityStackSupervisor(ActivityManagerService service, Looper looper)416 public TestActivityStackSupervisor(ActivityManagerService service, Looper looper) { 417 super(service, looper); 418 mDisplayManager = 419 (DisplayManager) mService.mContext.getSystemService(Context.DISPLAY_SERVICE); 420 mWindowManager = prepareMockWindowManager(); 421 mKeyguardController = mock(KeyguardController.class); 422 } 423 424 @Override initialize()425 public void initialize() { 426 super.initialize(); 427 mDisplay = spy(new TestActivityDisplay(this, DEFAULT_DISPLAY)); 428 attachDisplay(mDisplay); 429 } 430 431 @Override getKeyguardController()432 public KeyguardController getKeyguardController() { 433 return mKeyguardController; 434 } 435 436 @Override getDefaultDisplay()437 ActivityDisplay getDefaultDisplay() { 438 return mDisplay; 439 } 440 441 // Just return the current front task. This is called internally so we cannot use spy to mock this out. 442 @Override getNextFocusableStackLocked(ActivityStack currentFocus, boolean ignoreCurrent)443 ActivityStack getNextFocusableStackLocked(ActivityStack currentFocus, 444 boolean ignoreCurrent) { 445 return mFocusedStack; 446 } 447 } 448 449 protected static class TestActivityDisplay extends ActivityDisplay { 450 451 private final ActivityStackSupervisor mSupervisor; TestActivityDisplay(ActivityStackSupervisor supervisor, int displayId)452 TestActivityDisplay(ActivityStackSupervisor supervisor, int displayId) { 453 super(supervisor, displayId); 454 mSupervisor = supervisor; 455 } 456 457 @Override createStackUnchecked(int windowingMode, int activityType, int stackId, boolean onTop)458 <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType, 459 int stackId, boolean onTop) { 460 if (windowingMode == WINDOWING_MODE_PINNED) { 461 return (T) new PinnedActivityStack(this, stackId, mSupervisor, onTop) { 462 @Override 463 Rect getDefaultPictureInPictureBounds(float aspectRatio) { 464 return new Rect(50, 50, 100, 100); 465 } 466 467 @Override 468 PinnedStackWindowController createStackWindowController(int displayId, 469 boolean onTop, Rect outBounds) { 470 return mock(PinnedStackWindowController.class); 471 } 472 }; 473 } else { 474 return (T) new TestActivityStack( 475 this, stackId, mSupervisor, windowingMode, activityType, onTop); 476 } 477 } 478 479 @Override createWindowContainerController()480 protected DisplayWindowController createWindowContainerController() { 481 return mock(DisplayWindowController.class); 482 } 483 } 484 485 private static WindowManagerService prepareMockWindowManager() { 486 final WindowManagerService service = WindowTestUtils.getMockWindowManagerService(); 487 488 doAnswer((InvocationOnMock invocationOnMock) -> { 489 final Runnable runnable = invocationOnMock.<Runnable>getArgument(0); 490 if (runnable != null) { 491 runnable.run(); 492 } 493 return null; 494 }).when(service).inSurfaceTransaction(any()); 495 496 return service; 497 } 498 499 /** 500 * Overridden {@link ActivityStack} that tracks test metrics, such as the number of times a 501 * method is called. Note that its functionality depends on the implementations of the 502 * construction arguments. 503 */ 504 protected static class TestActivityStack<T extends StackWindowController> 505 extends ActivityStack<T> { 506 private int mOnActivityRemovedFromStackCount = 0; 507 private T mContainerController; 508 509 static final int IS_TRANSLUCENT_UNSET = 0; 510 static final int IS_TRANSLUCENT_FALSE = 1; 511 static final int IS_TRANSLUCENT_TRUE = 2; 512 private int mIsTranslucent = IS_TRANSLUCENT_UNSET; 513 514 static final int SUPPORTS_SPLIT_SCREEN_UNSET = 0; 515 static final int SUPPORTS_SPLIT_SCREEN_FALSE = 1; 516 static final int SUPPORTS_SPLIT_SCREEN_TRUE = 2; 517 private int mSupportsSplitScreen = SUPPORTS_SPLIT_SCREEN_UNSET; 518 519 TestActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor, 520 int windowingMode, int activityType, boolean onTop) { 521 super(display, stackId, supervisor, windowingMode, activityType, onTop); 522 } 523 524 @Override 525 void onActivityRemovedFromStack(ActivityRecord r) { 526 mOnActivityRemovedFromStackCount++; 527 super.onActivityRemovedFromStack(r); 528 } 529 530 // Returns the number of times {@link #onActivityRemovedFromStack} has been called 531 int onActivityRemovedFromStackInvocationCount() { 532 return mOnActivityRemovedFromStackCount; 533 } 534 535 @Override 536 protected T createStackWindowController(int displayId, boolean onTop, Rect outBounds) { 537 mContainerController = (T) WindowTestUtils.createMockStackWindowContainerController(); 538 539 // Primary pinned stacks require a non-empty out bounds to be set or else all tasks 540 // will be moved to the full screen stack. 541 if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { 542 outBounds.set(0, 0, 100, 100); 543 } 544 return mContainerController; 545 } 546 547 @Override 548 T getWindowContainerController() { 549 return mContainerController; 550 } 551 552 void setIsTranslucent(boolean isTranslucent) { 553 mIsTranslucent = isTranslucent ? IS_TRANSLUCENT_TRUE : IS_TRANSLUCENT_FALSE; 554 } 555 556 @Override 557 boolean isStackTranslucent(ActivityRecord starting) { 558 switch (mIsTranslucent) { 559 case IS_TRANSLUCENT_TRUE: 560 return true; 561 case IS_TRANSLUCENT_FALSE: 562 return false; 563 case IS_TRANSLUCENT_UNSET: 564 default: 565 return super.isStackTranslucent(starting); 566 } 567 } 568 569 void setSupportsSplitScreen(boolean supportsSplitScreen) { 570 mSupportsSplitScreen = supportsSplitScreen 571 ? SUPPORTS_SPLIT_SCREEN_TRUE : SUPPORTS_SPLIT_SCREEN_FALSE; 572 } 573 574 @Override 575 public boolean supportsSplitScreenWindowingMode() { 576 switch (mSupportsSplitScreen) { 577 case SUPPORTS_SPLIT_SCREEN_TRUE: 578 return true; 579 case SUPPORTS_SPLIT_SCREEN_FALSE: 580 return false; 581 case SUPPORTS_SPLIT_SCREEN_UNSET: 582 default: 583 return super.supportsSplitScreenWindowingMode(); 584 } 585 } 586 587 @Override 588 void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity, 589 boolean newTask, boolean keepCurTransition, 590 ActivityOptions options) { 591 } 592 } 593 } 594