1 /* 2 * Copyright (C) 2018 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.wm; 18 19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; 23 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 24 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 25 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; 26 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 27 28 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 29 30 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; 31 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; 32 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; 33 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 34 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; 35 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 36 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; 37 38 import android.app.ActivityManager; 39 import android.app.ActivityOptions; 40 import android.app.IApplicationThread; 41 import android.app.WindowConfiguration; 42 import android.content.ComponentName; 43 import android.content.Context; 44 import android.content.Intent; 45 import android.content.pm.ActivityInfo; 46 import android.content.pm.ApplicationInfo; 47 import android.content.res.Configuration; 48 import android.os.Build; 49 import android.os.Bundle; 50 import android.os.UserHandle; 51 import android.service.voice.IVoiceInteractionSession; 52 import android.view.SurfaceControl; 53 import android.window.ITaskOrganizer; 54 import android.window.WindowContainerToken; 55 56 import com.android.server.AttributeCache; 57 58 import org.junit.Before; 59 import org.junit.BeforeClass; 60 61 /** 62 * A base class to handle common operations in activity related unit tests. 63 */ 64 class ActivityTestsBase extends SystemServiceTestsBase { 65 final Context mContext = getInstrumentation().getTargetContext(); 66 67 ActivityTaskManagerService mService; 68 RootWindowContainer mRootWindowContainer; 69 ActivityStackSupervisor mSupervisor; 70 71 // Default package name 72 static final String DEFAULT_COMPONENT_PACKAGE_NAME = "com.foo"; 73 74 // Default base activity name 75 private static final String DEFAULT_COMPONENT_CLASS_NAME = ".BarActivity"; 76 77 @BeforeClass setUpOnceBase()78 public static void setUpOnceBase() { 79 AttributeCache.init(getInstrumentation().getTargetContext()); 80 } 81 82 @Before setUpBase()83 public void setUpBase() { 84 mService = mSystemServicesTestRule.getActivityTaskManagerService(); 85 mSupervisor = mService.mStackSupervisor; 86 mRootWindowContainer = mService.mRootWindowContainer; 87 } 88 89 /** Creates and adds a {@link TestDisplayContent} to supervisor at the given position. */ addNewDisplayContentAt(int position)90 TestDisplayContent addNewDisplayContentAt(int position) { 91 return new TestDisplayContent.Builder(mService, 1000, 1500).setPosition(position).build(); 92 } 93 94 /** Sets the default minimum task size to 1 so that tests can use small task sizes */ removeGlobalMinSizeRestriction()95 public void removeGlobalMinSizeRestriction() { 96 mService.mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp = 1; 97 } 98 99 /** 100 * Builder for creating new activities. 101 */ 102 protected static class ActivityBuilder { 103 // An id appended to the end of the component name to make it unique 104 private static int sCurrentActivityId = 0; 105 106 private final ActivityTaskManagerService mService; 107 108 private ComponentName mComponent; 109 private String mTargetActivity; 110 private Task mTask; 111 private String mProcessName = "name"; 112 private String mAffinity; 113 private int mUid = 12345; 114 private boolean mCreateTask; 115 private ActivityStack mStack; 116 private int mActivityFlags; 117 private int mLaunchMode; 118 private int mResizeMode = RESIZE_MODE_RESIZEABLE; 119 private float mMaxAspectRatio; 120 private int mScreenOrientation = SCREEN_ORIENTATION_UNSPECIFIED; 121 private boolean mLaunchTaskBehind; 122 private int mConfigChanges; 123 private int mLaunchedFromPid; 124 private int mLaunchedFromUid; 125 private WindowProcessController mWpc; 126 private Bundle mIntentExtras; 127 ActivityBuilder(ActivityTaskManagerService service)128 ActivityBuilder(ActivityTaskManagerService service) { 129 mService = service; 130 } 131 setComponent(ComponentName component)132 ActivityBuilder setComponent(ComponentName component) { 133 mComponent = component; 134 return this; 135 } 136 setTargetActivity(String targetActivity)137 ActivityBuilder setTargetActivity(String targetActivity) { 138 mTargetActivity = targetActivity; 139 return this; 140 } 141 setIntentExtras(Bundle extras)142 ActivityBuilder setIntentExtras(Bundle extras) { 143 mIntentExtras = extras; 144 return this; 145 } 146 getDefaultComponent()147 static ComponentName getDefaultComponent() { 148 return ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, 149 DEFAULT_COMPONENT_PACKAGE_NAME); 150 } 151 setTask(Task task)152 ActivityBuilder setTask(Task task) { 153 mTask = task; 154 return this; 155 } 156 setActivityFlags(int flags)157 ActivityBuilder setActivityFlags(int flags) { 158 mActivityFlags = flags; 159 return this; 160 } 161 setLaunchMode(int launchMode)162 ActivityBuilder setLaunchMode(int launchMode) { 163 mLaunchMode = launchMode; 164 return this; 165 } 166 setStack(ActivityStack stack)167 ActivityBuilder setStack(ActivityStack stack) { 168 mStack = stack; 169 return this; 170 } 171 setCreateTask(boolean createTask)172 ActivityBuilder setCreateTask(boolean createTask) { 173 mCreateTask = createTask; 174 return this; 175 } 176 setProcessName(String name)177 ActivityBuilder setProcessName(String name) { 178 mProcessName = name; 179 return this; 180 } 181 setUid(int uid)182 ActivityBuilder setUid(int uid) { 183 mUid = uid; 184 return this; 185 } 186 setResizeMode(int resizeMode)187 ActivityBuilder setResizeMode(int resizeMode) { 188 mResizeMode = resizeMode; 189 return this; 190 } 191 setMaxAspectRatio(float maxAspectRatio)192 ActivityBuilder setMaxAspectRatio(float maxAspectRatio) { 193 mMaxAspectRatio = maxAspectRatio; 194 return this; 195 } 196 setScreenOrientation(int screenOrientation)197 ActivityBuilder setScreenOrientation(int screenOrientation) { 198 mScreenOrientation = screenOrientation; 199 return this; 200 } 201 setLaunchTaskBehind(boolean launchTaskBehind)202 ActivityBuilder setLaunchTaskBehind(boolean launchTaskBehind) { 203 mLaunchTaskBehind = launchTaskBehind; 204 return this; 205 } 206 setConfigChanges(int configChanges)207 ActivityBuilder setConfigChanges(int configChanges) { 208 mConfigChanges = configChanges; 209 return this; 210 } 211 setLaunchedFromPid(int pid)212 ActivityBuilder setLaunchedFromPid(int pid) { 213 mLaunchedFromPid = pid; 214 return this; 215 } 216 setLaunchedFromUid(int uid)217 ActivityBuilder setLaunchedFromUid(int uid) { 218 mLaunchedFromUid = uid; 219 return this; 220 } 221 setUseProcess(WindowProcessController wpc)222 ActivityBuilder setUseProcess(WindowProcessController wpc) { 223 mWpc = wpc; 224 return this; 225 } 226 setAffinity(String affinity)227 ActivityBuilder setAffinity(String affinity) { 228 mAffinity = affinity; 229 return this; 230 } 231 build()232 ActivityRecord build() { 233 SystemServicesTestRule.checkHoldsLock(mService.mGlobalLock); 234 try { 235 mService.deferWindowLayout(); 236 return buildInner(); 237 } finally { 238 mService.continueWindowLayout(); 239 } 240 } 241 buildInner()242 ActivityRecord buildInner() { 243 if (mComponent == null) { 244 final int id = sCurrentActivityId++; 245 mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, 246 DEFAULT_COMPONENT_CLASS_NAME + id); 247 } 248 249 if (mCreateTask) { 250 mTask = new TaskBuilder(mService.mStackSupervisor) 251 .setComponent(mComponent) 252 .setStack(mStack).build(); 253 } else if (mTask == null && mStack != null && DisplayContent.alwaysCreateStack( 254 mStack.getWindowingMode(), mStack.getActivityType())) { 255 // The stack can be the task root. 256 mTask = mStack; 257 } 258 259 Intent intent = new Intent(); 260 intent.setComponent(mComponent); 261 if (mIntentExtras != null) { 262 intent.putExtras(mIntentExtras); 263 } 264 final ActivityInfo aInfo = new ActivityInfo(); 265 aInfo.applicationInfo = new ApplicationInfo(); 266 aInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; 267 aInfo.applicationInfo.packageName = mComponent.getPackageName(); 268 aInfo.applicationInfo.uid = mUid; 269 aInfo.processName = mProcessName; 270 aInfo.packageName = mComponent.getPackageName(); 271 aInfo.name = mComponent.getClassName(); 272 if (mTargetActivity != null) { 273 aInfo.targetActivity = mTargetActivity; 274 } 275 aInfo.flags |= mActivityFlags; 276 aInfo.launchMode = mLaunchMode; 277 aInfo.resizeMode = mResizeMode; 278 aInfo.maxAspectRatio = mMaxAspectRatio; 279 aInfo.screenOrientation = mScreenOrientation; 280 aInfo.configChanges |= mConfigChanges; 281 aInfo.taskAffinity = mAffinity; 282 283 ActivityOptions options = null; 284 if (mLaunchTaskBehind) { 285 options = ActivityOptions.makeTaskLaunchBehind(); 286 } 287 288 final ActivityRecord activity = new ActivityRecord(mService, null /* caller */, 289 mLaunchedFromPid /* launchedFromPid */, mLaunchedFromUid /* launchedFromUid */, 290 null, null, intent, null, aInfo /*aInfo*/, new Configuration(), 291 null /* resultTo */, null /* resultWho */, 0 /* reqCode */, 292 false /*componentSpecified*/, false /* rootVoiceInteraction */, 293 mService.mStackSupervisor, options, null /* sourceRecord */); 294 spyOn(activity); 295 if (mTask != null) { 296 // fullscreen value is normally read from resources in ctor, so for testing we need 297 // to set it somewhere else since we can't mock resources. 298 doReturn(true).when(activity).occludesParent(); 299 doReturn(true).when(activity).fillsParent(); 300 mTask.addChild(activity); 301 // Make visible by default... 302 activity.setVisible(true); 303 } 304 305 final WindowProcessController wpc; 306 if (mWpc != null) { 307 wpc = mWpc; 308 } else { 309 wpc = new WindowProcessController(mService, 310 mService.mContext.getApplicationInfo(), mProcessName, mUid, 311 UserHandle.getUserId(12345), mock(Object.class), 312 mock(WindowProcessListener.class)); 313 wpc.setThread(mock(IApplicationThread.class)); 314 } 315 wpc.setThread(mock(IApplicationThread.class)); 316 activity.setProcess(wpc); 317 doReturn(wpc).when(mService).getProcessController( 318 activity.processName, activity.info.applicationInfo.uid); 319 320 // Resume top activities to make sure all other signals in the system are connected. 321 mService.mRootWindowContainer.resumeFocusedStacksTopActivities(); 322 return activity; 323 } 324 } 325 326 /** 327 * Builder for creating new tasks. 328 */ 329 protected static class TaskBuilder { 330 private final ActivityStackSupervisor mSupervisor; 331 332 private ComponentName mComponent; 333 private String mPackage; 334 private int mFlags = 0; 335 // Task id 0 is reserved in ARC for the home app. 336 private int mTaskId = SystemServicesTestRule.sNextTaskId++; 337 private int mUserId = 0; 338 private IVoiceInteractionSession mVoiceSession; 339 private boolean mCreateStack = true; 340 341 private ActivityStack mStack; 342 private TaskDisplayArea mTaskDisplayArea; 343 TaskBuilder(ActivityStackSupervisor supervisor)344 TaskBuilder(ActivityStackSupervisor supervisor) { 345 mSupervisor = supervisor; 346 } 347 setComponent(ComponentName component)348 TaskBuilder setComponent(ComponentName component) { 349 mComponent = component; 350 return this; 351 } 352 setPackage(String packageName)353 TaskBuilder setPackage(String packageName) { 354 mPackage = packageName; 355 return this; 356 } 357 358 /** 359 * Set to {@code true} by default, set to {@code false} to prevent the task from 360 * automatically creating a parent stack. 361 */ setCreateStack(boolean createStack)362 TaskBuilder setCreateStack(boolean createStack) { 363 mCreateStack = createStack; 364 return this; 365 } 366 setVoiceSession(IVoiceInteractionSession session)367 TaskBuilder setVoiceSession(IVoiceInteractionSession session) { 368 mVoiceSession = session; 369 return this; 370 } 371 setFlags(int flags)372 TaskBuilder setFlags(int flags) { 373 mFlags = flags; 374 return this; 375 } 376 setTaskId(int taskId)377 TaskBuilder setTaskId(int taskId) { 378 mTaskId = taskId; 379 return this; 380 } 381 setUserId(int userId)382 TaskBuilder setUserId(int userId) { 383 mUserId = userId; 384 return this; 385 } 386 setStack(ActivityStack stack)387 TaskBuilder setStack(ActivityStack stack) { 388 mStack = stack; 389 return this; 390 } 391 setDisplay(DisplayContent display)392 TaskBuilder setDisplay(DisplayContent display) { 393 mTaskDisplayArea = display.getDefaultTaskDisplayArea(); 394 return this; 395 } 396 build()397 Task build() { 398 SystemServicesTestRule.checkHoldsLock(mSupervisor.mService.mGlobalLock); 399 400 if (mStack == null && mCreateStack) { 401 TaskDisplayArea displayArea = mTaskDisplayArea != null ? mTaskDisplayArea 402 : mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea(); 403 mStack = displayArea.createStack( 404 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); 405 spyOn(mStack); 406 } 407 408 final ActivityInfo aInfo = new ActivityInfo(); 409 aInfo.applicationInfo = new ApplicationInfo(); 410 aInfo.applicationInfo.packageName = mPackage; 411 412 Intent intent = new Intent(); 413 if (mComponent == null) { 414 mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, 415 DEFAULT_COMPONENT_CLASS_NAME); 416 } 417 418 intent.setComponent(mComponent); 419 intent.setFlags(mFlags); 420 421 final Task task = new ActivityStack(mSupervisor.mService, mTaskId, aInfo, 422 intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/, 423 null /*taskDescription*/, mStack); 424 spyOn(task); 425 task.mUserId = mUserId; 426 427 if (mStack != null) { 428 mStack.moveToFront("test"); 429 mStack.addChild(task, true, true); 430 } 431 432 return task; 433 } 434 } 435 436 static class StackBuilder { 437 private final RootWindowContainer mRootWindowContainer; 438 private DisplayContent mDisplay; 439 private TaskDisplayArea mTaskDisplayArea; 440 private int mStackId = -1; 441 private int mWindowingMode = WINDOWING_MODE_UNDEFINED; 442 private int mActivityType = ACTIVITY_TYPE_STANDARD; 443 private boolean mOnTop = true; 444 private boolean mCreateActivity = true; 445 private ActivityInfo mInfo; 446 private Intent mIntent; 447 StackBuilder(RootWindowContainer root)448 StackBuilder(RootWindowContainer root) { 449 mRootWindowContainer = root; 450 mDisplay = mRootWindowContainer.getDefaultDisplay(); 451 mTaskDisplayArea = mDisplay.getDefaultTaskDisplayArea(); 452 } 453 setWindowingMode(int windowingMode)454 StackBuilder setWindowingMode(int windowingMode) { 455 mWindowingMode = windowingMode; 456 return this; 457 } 458 setActivityType(int activityType)459 StackBuilder setActivityType(int activityType) { 460 mActivityType = activityType; 461 return this; 462 } 463 setStackId(int stackId)464 StackBuilder setStackId(int stackId) { 465 mStackId = stackId; 466 return this; 467 } 468 469 /** 470 * Set the parent {@link DisplayContent} and use the default task display area. Overrides 471 * the task display area, if was set before. 472 */ setDisplay(DisplayContent display)473 StackBuilder setDisplay(DisplayContent display) { 474 mDisplay = display; 475 mTaskDisplayArea = mDisplay.getDefaultTaskDisplayArea(); 476 return this; 477 } 478 479 /** Set the parent {@link TaskDisplayArea}. Overrides the display, if was set before. */ setTaskDisplayArea(TaskDisplayArea taskDisplayArea)480 StackBuilder setTaskDisplayArea(TaskDisplayArea taskDisplayArea) { 481 mTaskDisplayArea = taskDisplayArea; 482 mDisplay = mTaskDisplayArea.mDisplayContent; 483 return this; 484 } 485 setOnTop(boolean onTop)486 StackBuilder setOnTop(boolean onTop) { 487 mOnTop = onTop; 488 return this; 489 } 490 setCreateActivity(boolean createActivity)491 StackBuilder setCreateActivity(boolean createActivity) { 492 mCreateActivity = createActivity; 493 return this; 494 } 495 setActivityInfo(ActivityInfo info)496 StackBuilder setActivityInfo(ActivityInfo info) { 497 mInfo = info; 498 return this; 499 } 500 setIntent(Intent intent)501 StackBuilder setIntent(Intent intent) { 502 mIntent = intent; 503 return this; 504 } 505 build()506 ActivityStack build() { 507 SystemServicesTestRule.checkHoldsLock(mRootWindowContainer.mWmService.mGlobalLock); 508 509 final int stackId = mStackId >= 0 ? mStackId : mTaskDisplayArea.getNextStackId(); 510 final ActivityStack stack = mTaskDisplayArea.createStackUnchecked( 511 mWindowingMode, mActivityType, stackId, mOnTop, mInfo, mIntent, 512 false /* createdByOrganizer */); 513 final ActivityStackSupervisor supervisor = mRootWindowContainer.mStackSupervisor; 514 515 if (mCreateActivity) { 516 new ActivityBuilder(supervisor.mService) 517 .setCreateTask(true) 518 .setStack(stack) 519 .build(); 520 if (mOnTop) { 521 // We move the task to front again in order to regain focus after activity 522 // added to the stack. Or {@link DisplayContent#mPreferredTopFocusableStack} 523 // could be other stacks (e.g. home stack). 524 stack.moveToFront("createActivityStack"); 525 } else { 526 stack.moveToBack("createActivityStack", null); 527 } 528 } 529 spyOn(stack); 530 531 doNothing().when(stack).startActivityLocked( 532 any(), any(), anyBoolean(), anyBoolean(), any()); 533 534 return stack; 535 } 536 537 } 538 539 static class TestSplitOrganizer extends ITaskOrganizer.Stub { 540 final ActivityTaskManagerService mService; 541 Task mPrimary; 542 Task mSecondary; 543 boolean mInSplit = false; 544 // moves everything to secondary. Most tests expect this since sysui usually does it. 545 boolean mMoveToSecondaryOnEnter = true; 546 int mDisplayId; TestSplitOrganizer(ActivityTaskManagerService service, int displayId)547 TestSplitOrganizer(ActivityTaskManagerService service, int displayId) { 548 mService = service; 549 mDisplayId = displayId; 550 mService.mTaskOrganizerController.registerTaskOrganizer(this, 551 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); 552 mService.mTaskOrganizerController.registerTaskOrganizer(this, 553 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); 554 WindowContainerToken primary = mService.mTaskOrganizerController.createRootTask( 555 displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token; 556 mPrimary = WindowContainer.fromBinder(primary.asBinder()).asTask(); 557 WindowContainerToken secondary = mService.mTaskOrganizerController.createRootTask( 558 displayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token; 559 mSecondary = WindowContainer.fromBinder(secondary.asBinder()).asTask(); 560 } TestSplitOrganizer(ActivityTaskManagerService service)561 TestSplitOrganizer(ActivityTaskManagerService service) { 562 this(service, 563 service.mStackSupervisor.mRootWindowContainer.getDefaultDisplay().mDisplayId); 564 } setMoveToSecondaryOnEnter(boolean move)565 public void setMoveToSecondaryOnEnter(boolean move) { 566 mMoveToSecondaryOnEnter = move; 567 } 568 @Override onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash)569 public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) { 570 } 571 @Override onTaskVanished(ActivityManager.RunningTaskInfo info)572 public void onTaskVanished(ActivityManager.RunningTaskInfo info) { 573 } 574 @Override onTaskInfoChanged(ActivityManager.RunningTaskInfo info)575 public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) { 576 if (mInSplit) { 577 return; 578 } 579 if (info.topActivityType == ACTIVITY_TYPE_UNDEFINED) { 580 // Not populated 581 return; 582 } 583 if (info.configuration.windowConfiguration.getWindowingMode() 584 != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { 585 return; 586 } 587 mInSplit = true; 588 if (!mMoveToSecondaryOnEnter) { 589 return; 590 } 591 mService.mTaskOrganizerController.setLaunchRoot(mDisplayId, 592 mSecondary.mRemoteToken.toWindowContainerToken()); 593 DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId); 594 for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { 595 final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx); 596 for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { 597 final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); 598 if (!WindowConfiguration.isSplitScreenWindowingMode(stack.getWindowingMode())) { 599 stack.reparent(mSecondary, POSITION_BOTTOM); 600 } 601 } 602 } 603 } 604 @Override onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo)605 public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) { 606 } 607 }; 608 } 609