From c32262be8bcf5f874d4c73f14f811e126ceca568 Mon Sep 17 00:00:00 2001 From: Diego Vela Date: Thu, 8 Oct 2020 17:00:52 +0000 Subject: [PATCH] Revert^2 "Use same display for activities in same process." The error was a bad git merge that removed an import. The fix was just to redo the commit again so the import is available. Original Commit Message: Use same display for activities in same process. Use WindowProcessController to calculate display to hold activity. Use the display with the top most activity within the same application. If no top activity is available use the default display Add additional parameter to task params modifier to include request. Handle launching on same display if using PendingIntent. Bug: 152958720 Test: atest WmTests:WindowProcessControllerTests atest WmTests:TaskLauncherParamsModifierTests Change-Id: If96cdc7207ec9dba6663eb327350e7148605f157 --- .../com/android/server/wm/ActivityRecord.java | 12 ++ .../android/server/wm/ActivityStarter.java | 10 +- .../server/wm/LaunchParamsController.java | 19 +- .../server/wm/TaskLaunchParamsModifier.java | 74 ++++++-- .../server/wm/WindowProcessController.java | 22 +++ .../server/wm/ActivityStarterTests.java | 2 +- .../wm/LaunchParamsControllerTests.java | 50 ++--- .../wm/TaskLaunchParamsModifierTests.java | 178 ++++++++++++++++++ .../wm/WindowProcessControllerTests.java | 42 +++++ 9 files changed, 362 insertions(+), 47 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index c2016decdbe93..913c3e580adfa 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -7584,6 +7584,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_VR_HEADSET; } + String getProcessName() { + return info.applicationInfo.processName; + } + int getUid() { return info.applicationInfo.uid; } @@ -7596,6 +7600,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return app != null ? app.getPid() : 0; } + int getLaunchedFromPid() { + return launchedFromPid; + } + + int getLaunchedFromUid() { + return launchedFromUid; + } + /** * Determines whether this ActivityRecord can turn the screen on. It checks whether the flag * {@link ActivityRecord#getTurnScreenOnFlag} is set and checks whether the ActivityRecord diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index acee7b26725e7..90cd682d6a8f5 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -57,9 +57,6 @@ import static android.view.WindowManager.TRANSIT_OPEN; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS; -import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME; -import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP; -import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS; @@ -71,6 +68,9 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_USER_ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.ActivityTaskManagerService.ANIMATE; +import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME; +import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP; +import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY; import static com.android.server.wm.Task.ActivityState.RESUMED; @@ -1870,7 +1870,7 @@ class ActivityStarter { } mSupervisor.getLaunchParamsController().calculate(targetTask, r.info.windowLayout, r, - sourceRecord, mOptions, PHASE_BOUNDS, mLaunchParams); + sourceRecord, mOptions, PHASE_BOUNDS, mLaunchParams, mRequest); mPreferredTaskDisplayArea = mLaunchParams.hasPreferredTaskDisplayArea() ? mLaunchParams.mPreferredTaskDisplayArea : mRootWindowContainer.getDefaultTaskDisplayArea(); @@ -2254,7 +2254,7 @@ class ActivityStarter { // Preferred display id is the only state we need for now and it could be updated again // after we located a reusable task (which might be resided in another display). mSupervisor.getLaunchParamsController().calculate(inTask, r.info.windowLayout, r, - sourceRecord, options, PHASE_DISPLAY, mLaunchParams); + sourceRecord, options, PHASE_DISPLAY, mLaunchParams, mRequest); mPreferredTaskDisplayArea = mLaunchParams.hasPreferredTaskDisplayArea() ? mLaunchParams.mPreferredTaskDisplayArea : mRootWindowContainer.getDefaultTaskDisplayArea(); diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java index f1ae921c87f58..b6b172eeae5b1 100644 --- a/services/core/java/com/android/server/wm/LaunchParamsController.java +++ b/services/core/java/com/android/server/wm/LaunchParamsController.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.INVALID_DISPLAY; +import static com.android.server.wm.ActivityStarter.Request; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_DONE; @@ -73,9 +74,10 @@ class LaunchParamsController { * @param source The {@link ActivityRecord} from which activity was started from. * @param options The {@link ActivityOptions} specified for the activity. * @param result The resulting params. + * @param request The optional request from the activity starter. */ - void calculate(Task task, WindowLayout layout, ActivityRecord activity, - ActivityRecord source, ActivityOptions options, int phase, LaunchParams result) { + void calculate(Task task, WindowLayout layout, ActivityRecord activity, ActivityRecord source, + ActivityOptions options, int phase, LaunchParams result, @Nullable Request request) { result.reset(); if (task != null || activity != null) { @@ -91,7 +93,7 @@ class LaunchParamsController { final LaunchParamsModifier modifier = mModifiers.get(i); switch(modifier.onCalculate(task, layout, activity, source, options, phase, mTmpCurrent, - mTmpResult)) { + mTmpResult, request)) { case RESULT_SKIP: // Do not apply any results when we are told to skip continue; @@ -128,7 +130,8 @@ class LaunchParamsController { boolean layoutTask(Task task, WindowLayout layout, ActivityRecord activity, ActivityRecord source, ActivityOptions options) { - calculate(task, layout, activity, source, options, PHASE_BOUNDS, mTmpParams); + calculate(task, layout, activity, source, options, PHASE_BOUNDS, mTmpParams, + null /* request */); // No changes, return. if (mTmpParams.isEmpty()) { @@ -305,15 +308,17 @@ class LaunchParamsController { * launched should have this be non-null. * @param source the Activity that launched a new task. Could be {@code null}. * @param options {@link ActivityOptions} used to start the activity with. - * @param phase the calculation phase, see {@link LaunchParamsModifier.Phase} + * @param phase the calculation phase, see {@link Phase} * @param currentParams launching params after the process of last {@link * LaunchParamsModifier}. * @param outParams the result params to be set. + * @param request Optional data to give more context on the launch * @return see {@link LaunchParamsModifier.Result} */ @Result - int onCalculate(Task task, WindowLayout layout, ActivityRecord activity, + int onCalculate(@Nullable Task task, WindowLayout layout, ActivityRecord activity, ActivityRecord source, ActivityOptions options, @Phase int phase, - LaunchParams currentParams, LaunchParams outParams); + LaunchParams currentParams, LaunchParams outParams, + @Nullable Request request); } } diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index 6dc957c1d1186..8b2fa52afd221 100644 --- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -35,6 +35,7 @@ import static android.util.DisplayMetrics.DENSITY_DEFAULT; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; +import static com.android.server.wm.ActivityStarter.Request; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -99,23 +100,25 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { ActivityRecord source, ActivityOptions options, LaunchParams currentParams, LaunchParams outParams) { return onCalculate(task, layout, activity, source, options, PHASE_BOUNDS, currentParams, - outParams); + outParams, null); } @Override - public int onCalculate(Task task, ActivityInfo.WindowLayout layout, - ActivityRecord activity, ActivityRecord source, ActivityOptions options, - int phase, LaunchParams currentParams, LaunchParams outParams) { + public int onCalculate(@Nullable Task task, @NonNull ActivityInfo.WindowLayout layout, + @NonNull ActivityRecord activity, @Nullable ActivityRecord source, + ActivityOptions options, int phase, LaunchParams currentParams, LaunchParams outParams, + @Nullable Request request) { initLogBuilder(task, activity); final int result = calculate(task, layout, activity, source, options, phase, currentParams, - outParams); + outParams, request); outputLog(); return result; } - private int calculate(Task task, ActivityInfo.WindowLayout layout, - ActivityRecord activity, ActivityRecord source, ActivityOptions options, int phase, - LaunchParams currentParams, LaunchParams outParams) { + private int calculate(@Nullable Task task, @NonNull ActivityInfo.WindowLayout layout, + @NonNull ActivityRecord activity, @Nullable ActivityRecord source, + ActivityOptions options, int phase, LaunchParams currentParams, LaunchParams outParams, + @Nullable Request request) { final ActivityRecord root; if (task != null) { root = task.getRootActivity() == null ? activity : task.getRootActivity(); @@ -138,7 +141,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { // STEP 1: Determine the display area to launch the activity/task. final TaskDisplayArea taskDisplayArea = getPreferredLaunchTaskDisplayArea(task, - options, source, currentParams); + options, source, currentParams, activity, request); outParams.mPreferredTaskDisplayArea = taskDisplayArea; // TODO(b/152116619): Update the usages of display to use taskDisplayArea below. final DisplayContent display = taskDisplayArea.mDisplayContent; @@ -298,7 +301,8 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } private TaskDisplayArea getPreferredLaunchTaskDisplayArea(@Nullable Task task, - @Nullable ActivityOptions options, ActivityRecord source, LaunchParams currentParams) { + @Nullable ActivityOptions options, ActivityRecord source, LaunchParams currentParams, + @NonNull ActivityRecord activityRecord, @Nullable Request request) { TaskDisplayArea taskDisplayArea = null; final WindowContainerToken optionLaunchTaskDisplayAreaToken = options != null @@ -369,7 +373,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { taskDisplayArea = currentParams.mPreferredTaskDisplayArea; } - // Fallback to default display if the device didn't declare support for multi-display + // Re-route to default display if the device didn't declare support for multi-display if (taskDisplayArea != null && !mSupervisor.mService.mSupportsMultiDisplay && taskDisplayArea.getDisplayId() != DEFAULT_DISPLAY) { taskDisplayArea = mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea(); @@ -377,7 +381,53 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { return (taskDisplayArea != null) ? taskDisplayArea - : mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea(); + : getFallbackDisplayAreaForActivity(activityRecord, request); + } + + /** + * Calculates the default {@link TaskDisplayArea} for a task. We attempt to put the activity + * within the same display area if possible. The strategy is to find the display in the + * following order: + * + *
    + *
  1. The display area of the top activity from the launching process will be used
  2. + *
  3. The display area of the top activity from the real launching process will be used + *
  4. + *
  5. Default display area from the associated root window container.
  6. + *
+ * @param activityRecord the activity being started + * @param request optional {@link Request} made to start the activity record + * @return {@link TaskDisplayArea} to house the task + */ + private TaskDisplayArea getFallbackDisplayAreaForActivity( + @NonNull ActivityRecord activityRecord, @Nullable Request request) { + + WindowProcessController controllerFromLaunchingRecord = mSupervisor.mService + .getProcessController(activityRecord.launchedFromPid, + activityRecord.launchedFromUid); + final TaskDisplayArea displayAreaForLaunchingRecord = controllerFromLaunchingRecord == null + ? null : controllerFromLaunchingRecord.getTopActivityDisplayArea(); + if (displayAreaForLaunchingRecord != null) { + return displayAreaForLaunchingRecord; + } + + WindowProcessController controllerFromProcess = mSupervisor.mService.getProcessController( + activityRecord.getProcessName(), activityRecord.getUid()); + final TaskDisplayArea displayAreaForRecord = controllerFromProcess == null ? null + : controllerFromProcess.getTopActivityDisplayArea(); + if (displayAreaForRecord != null) { + return displayAreaForRecord; + } + + WindowProcessController controllerFromRequest = request == null ? null : mSupervisor + .mService.getProcessController(request.realCallingPid, request.realCallingUid); + final TaskDisplayArea displayAreaFromSourceProcess = controllerFromRequest == null ? null + : controllerFromRequest.getTopActivityDisplayArea(); + if (displayAreaFromSourceProcess != null) { + return displayAreaFromSourceProcess; + } + + return mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea(); } private boolean canInheritWindowingModeFromSource(@NonNull DisplayContent display, diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index c55f059cae160..8f8fea34e620f 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -730,6 +730,28 @@ public class WindowProcessController extends ConfigurationContainer= 0; --index) { + ActivityRecord nextRecord = mActivities.get(index); + TaskDisplayArea nextDisplayArea = nextRecord.getDisplayArea(); + if (nextRecord.compareTo(topRecord) > 0 && nextDisplayArea != null) { + topRecord = nextRecord; + displayArea = nextDisplayArea; + } + } + + return displayArea; + } + private boolean hasActivityInVisibleTask() { for (int i = mActivities.size() - 1; i >= 0; --i) { Task task = mActivities.get(i).getTask(); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index bded3f9de9bad..565bf8b615c78 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -422,7 +422,7 @@ public class ActivityStarterTests extends WindowTestsBase { // verify that values are passed to the modifier. Values are passed thrice -- two for // setting initial state, another when task is created. verify(modifier, times(3)).onCalculate(any(), eq(windowLayout), any(), any(), eq(options), - anyInt(), any(), any()); + anyInt(), any(), any(), any()); } /** diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java index e514ac04efbeb..cd428e10a4378 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java @@ -33,6 +33,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.server.wm.ActivityStarter.Request; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_DONE; @@ -92,11 +93,12 @@ public class LaunchParamsControllerTests extends WindowTestsBase { final ActivityRecord source = new ActivityBuilder(mAtm).build(); final WindowLayout layout = new WindowLayout(0, 0, 0, 0, 0, 0, 0); final ActivityOptions options = mock(ActivityOptions.class); + final Request request = new Request(); mController.calculate(record.getTask(), layout, record, source, options, PHASE_BOUNDS, - new LaunchParams()); + new LaunchParams(), request); verify(positioner, times(1)).onCalculate(eq(record.getTask()), eq(layout), eq(record), - eq(source), eq(options), anyInt(), any(), any()); + eq(source), eq(options), anyInt(), any(), any(), eq(request)); } /** @@ -119,9 +121,9 @@ public class LaunchParamsControllerTests extends WindowTestsBase { mPersister.putLaunchParams(userId, name, expected); mController.calculate(activity.getTask(), null /*layout*/, activity, null /*source*/, - null /*options*/, PHASE_BOUNDS, new LaunchParams()); + null /*options*/, PHASE_BOUNDS, new LaunchParams(), null /* request */); verify(positioner, times(1)).onCalculate(any(), any(), any(), any(), any(), anyInt(), - eq(expected), any()); + eq(expected), any(), any()); } /** @@ -132,16 +134,17 @@ public class LaunchParamsControllerTests extends WindowTestsBase { final LaunchParamsModifier ignoredPositioner = mock(LaunchParamsModifier.class); final LaunchParamsModifier earlyExitPositioner = - (task, layout, activity, source, options, phase, currentParams, outParams) + (task, layout, activity, source, options, phase, currentParams, outParams, request) -> RESULT_DONE; mController.registerModifier(ignoredPositioner); mController.registerModifier(earlyExitPositioner); mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, - null /*source*/, null /*options*/, PHASE_BOUNDS, new LaunchParams()); + null /*source*/, null /*options*/, PHASE_BOUNDS, new LaunchParams(), + null /* request */); verify(ignoredPositioner, never()).onCalculate(any(), any(), any(), any(), any(), anyInt(), - any(), any()); + any(), any(), any()); } /** @@ -157,20 +160,22 @@ public class LaunchParamsControllerTests extends WindowTestsBase { mController.registerModifier(firstPositioner); mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, - null /*source*/, null /*options*/, PHASE_BOUNDS, new LaunchParams()); + null /*source*/, null /*options*/, PHASE_BOUNDS, new LaunchParams(), + null /* request */); verify(firstPositioner, times(1)).onCalculate(any(), any(), any(), any(), any(), anyInt(), - any(), any()); + any(), any(), any()); final LaunchParamsModifier secondPositioner = spy(earlyExitPositioner); mController.registerModifier(secondPositioner); mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, - null /*source*/, null /*options*/, PHASE_BOUNDS, new LaunchParams()); + null /*source*/, null /*options*/, PHASE_BOUNDS, new LaunchParams(), + null /* request */); verify(firstPositioner, times(1)).onCalculate(any(), any(), any(), any(), any(), anyInt(), - any(), any()); + any(), any(), any()); verify(secondPositioner, times(1)).onCalculate(any(), any(), any(), any(), any(), anyInt(), - any(), any()); + any(), any(), any()); } /** @@ -192,10 +197,10 @@ public class LaunchParamsControllerTests extends WindowTestsBase { mController.registerModifier(positioner2); mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, null /*source*/, - null /*options*/, PHASE_BOUNDS, new LaunchParams()); + null /*options*/, PHASE_BOUNDS, new LaunchParams(), null /* request */); verify(positioner1, times(1)).onCalculate(any(), any(), any(), any(), any(), anyInt(), - eq(positioner2.getLaunchParams()), any()); + eq(positioner2.getLaunchParams()), any(), any()); } /** @@ -218,7 +223,7 @@ public class LaunchParamsControllerTests extends WindowTestsBase { final LaunchParams result = new LaunchParams(); mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, null /*source*/, - null /*options*/, PHASE_BOUNDS, result); + null /*options*/, PHASE_BOUNDS, result, null /* request */); assertEquals(result, positioner2.getLaunchParams()); } @@ -237,17 +242,17 @@ public class LaunchParamsControllerTests extends WindowTestsBase { // VR activities should always land on default display. mController.calculate(null /*task*/, null /*layout*/, vrActivity /*activity*/, - null /*source*/, null /*options*/, PHASE_BOUNDS, result); + null /*source*/, null /*options*/, PHASE_BOUNDS, result, null /* request */); assertEquals(mRootWindowContainer.getDefaultTaskDisplayArea(), result.mPreferredTaskDisplayArea); // Otherwise, always lands on VR 2D display. final ActivityRecord vr2dActivity = new ActivityBuilder(mAtm).build(); mController.calculate(null /*task*/, null /*layout*/, vr2dActivity /*activity*/, - null /*source*/, null /*options*/, PHASE_BOUNDS, result); + null /*source*/, null /*options*/, PHASE_BOUNDS, result, null /* request */); assertEquals(vrDisplay.getDefaultTaskDisplayArea(), result.mPreferredTaskDisplayArea); mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, null /*source*/, - null /*options*/, PHASE_BOUNDS, result); + null /*options*/, PHASE_BOUNDS, result, null /* request */); assertEquals(vrDisplay.getDefaultTaskDisplayArea(), result.mPreferredTaskDisplayArea); mAtm.mVr2dDisplayId = INVALID_DISPLAY; @@ -269,9 +274,9 @@ public class LaunchParamsControllerTests extends WindowTestsBase { final ActivityOptions options = mock(ActivityOptions.class); mController.calculate(record.getTask(), layout, record, source, options, PHASE_BOUNDS, - new LaunchParams()); + new LaunchParams(), null /* request */); verify(positioner, times(1)).onCalculate(eq(record.getTask()), eq(layout), eq(record), - eq(source), eq(options), eq(PHASE_BOUNDS), any(), any()); + eq(source), eq(options), eq(PHASE_BOUNDS), any(), any(), any()); } /** @@ -403,8 +408,9 @@ public class LaunchParamsControllerTests extends WindowTestsBase { @Override public int onCalculate(Task task, WindowLayout layout, ActivityRecord activity, - ActivityRecord source, ActivityOptions options, int phase, - LaunchParams currentParams, LaunchParams outParams) { + ActivityRecord source, ActivityOptions options, int phase, + LaunchParams currentParams, LaunchParams outParams, + Request request) { outParams.set(mParams); return mReturnVal; } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java index 98520bb7a20bf..4f55322e2085a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java @@ -35,6 +35,7 @@ import static android.view.InsetsState.ITYPE_STATUS_BAR; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.server.wm.ActivityStarter.Request; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP; @@ -42,6 +43,9 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import android.app.ActivityOptions; import android.content.pm.ActivityInfo; @@ -265,6 +269,180 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { mResult.mPreferredTaskDisplayArea); } + @Test + public void testUsesDisplayAreaFromTopMostActivityInApplicationIfAvailable() { + final String processName = "processName"; + final int uid = 124214; + final TestDisplayContent firstScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN); + final TestDisplayContent secondScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN); + final TaskDisplayArea expectedDisplayArea = secondScreen.getDefaultTaskDisplayArea(); + final WindowProcessController controller = mock(WindowProcessController.class); + + when(controller.getTopActivityDisplayArea()).thenReturn(expectedDisplayArea); + + when(mActivity.getProcessName()).thenReturn(processName); + when(mActivity.getUid()).thenReturn(uid); + doReturn(controller) + .when(mSupervisor.mService) + .getProcessController(processName, uid); + + assertEquals(RESULT_CONTINUE, mTarget.onCalculate( + null /* task */, + null /* layout */, + mActivity /* activity */, + null /* source */, + null /* options */, + -1 /* phase */, + mCurrent, + mResult, + null /* request */ + )); + + assertEquals(expectedDisplayArea, mResult.mPreferredTaskDisplayArea); + } + + @Test + public void testUsesDisplayAreaFromLaunchingActivityIfApplicationLaunching() { + final String processName = "processName"; + final int uid = 124214; + final TestDisplayContent firstScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN); + final TestDisplayContent secondScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN); + final TaskDisplayArea expectedTaskDisplayArea = secondScreen.getDefaultTaskDisplayArea(); + final WindowProcessController controller = mock(WindowProcessController.class); + + when(controller.getTopActivityDisplayArea()).thenReturn(expectedTaskDisplayArea); + + when(mActivity.getProcessName()).thenReturn(processName); + when(mActivity.getUid()).thenReturn(uid); + doReturn(null) + .when(mSupervisor.mService) + .getProcessController(processName, uid); + + doReturn(controller) + .when(mSupervisor.mService) + .getProcessController(mActivity.launchedFromPid, mActivity.launchedFromUid); + + assertEquals(RESULT_CONTINUE, mTarget.onCalculate( + null /* task */, + null /* layout */, + mActivity /* activity */, + null /* source */, + null /* options */, + -1 /* phase */, + mCurrent, + mResult, + null /* request */ + )); + + assertEquals(expectedTaskDisplayArea, mResult.mPreferredTaskDisplayArea); + } + + @Test + public void testDisplayAreaFromLaunchingActivityTakesPrecedence() { + final String processName = "processName"; + final int uid = 124214; + final TestDisplayContent firstScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN); + final TestDisplayContent secondScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN); + final TaskDisplayArea firstTaskDisplayArea = firstScreen.getDefaultTaskDisplayArea(); + final TaskDisplayArea expectedTaskDisplayArea = secondScreen.getDefaultTaskDisplayArea(); + final WindowProcessController controllerForLaunching = mock(WindowProcessController.class); + final WindowProcessController controllerForApplication = + mock(WindowProcessController.class); + + when(mActivity.getProcessName()).thenReturn(processName); + when(mActivity.getUid()).thenReturn(uid); + + when(controllerForApplication.getTopActivityDisplayArea()).thenReturn(firstTaskDisplayArea); + when(controllerForLaunching.getTopActivityDisplayArea()) + .thenReturn(expectedTaskDisplayArea); + + doReturn(controllerForApplication) + .when(mSupervisor.mService) + .getProcessController(processName, uid); + doReturn(controllerForLaunching) + .when(mSupervisor.mService) + .getProcessController(mActivity.launchedFromPid, mActivity.launchedFromUid); + + assertEquals(RESULT_CONTINUE, mTarget.onCalculate( + null /* task */, + null /* layout */, + mActivity /* activity */, + null /* source */, + null /* options */, + -1 /* phase */, + mCurrent, + mResult, + null /* request */ + )); + + assertEquals(expectedTaskDisplayArea, mResult.mPreferredTaskDisplayArea); + } + + @Test + public void testUsesDisplayAreaOriginalProcessAsLastResort() { + final TestDisplayContent firstScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN); + final TestDisplayContent secondScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN); + final TaskDisplayArea expectedTaskDisplayArea = secondScreen.getDefaultTaskDisplayArea(); + final Request request = new Request(); + request.realCallingPid = 12412413; + request.realCallingUid = 235424; + + final WindowProcessController controller = mock(WindowProcessController.class); + + when(controller.getTopActivityDisplayArea()).thenReturn(expectedTaskDisplayArea); + + doReturn(null) + .when(mSupervisor.mService) + .getProcessController(mActivity.processName, mActivity.info.applicationInfo.uid); + + doReturn(null) + .when(mSupervisor.mService) + .getProcessController(mActivity.launchedFromPid, mActivity.launchedFromUid); + + doReturn(controller) + .when(mSupervisor.mService) + .getProcessController(request.realCallingPid, request.realCallingUid); + + assertEquals(RESULT_CONTINUE, mTarget.onCalculate( + null /* task */, + null /* layout */, + mActivity /* activity */, + null /* source */, + null /* options */, + -1 /* phase */, + mCurrent, + mResult, + request + )); + + assertEquals(expectedTaskDisplayArea, mResult.mPreferredTaskDisplayArea); + } + + @Test + public void testUsesDefaultDisplayAreaIfWindowProcessControllerIsNotPresent() { + doReturn(null) + .when(mSupervisor.mService) + .getProcessController(mActivity.processName, mActivity.info.applicationInfo.uid); + + doReturn(null) + .when(mSupervisor.mService) + .getProcessController(mActivity.launchedFromPid, mActivity.launchedFromUid); + + assertEquals(RESULT_CONTINUE, mTarget.onCalculate( + null /* task */, + null /* layout */, + mActivity /* activity */, + null /* source */, + null /* options */, + -1 /* phase */, + mCurrent, + mResult, + null /* request */ + )); + + assertEquals(DEFAULT_DISPLAY, mResult.mPreferredTaskDisplayArea.getDisplayId()); + } + // ===================================== // Launch Windowing Mode Related Tests // ===================================== diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java index 5afcedb10dd65..3057558a6e984 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java @@ -27,10 +27,13 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; +import static org.mockito.Mockito.when; import android.Manifest; import android.app.IApplicationThread; @@ -327,6 +330,45 @@ public class WindowProcessControllerTests extends WindowTestsBase { return new ActivityBuilder(mAtm).setCreateTask(true).setUseProcess(wpc).build(); } + @Test + public void testTopActivityDisplayAreaMatchesTopMostActivity_noActivities() { + assertNull(mWpc.getTopActivityDisplayArea()); + } + + @Test + public void testTopActivityDisplayAreaMatchesTopMostActivity_singleActivity() { + final ActivityRecord activityRecord = new ActivityBuilder(mSupervisor.mService).build(); + final TaskDisplayArea expectedDisplayArea = mock(TaskDisplayArea.class); + + when(activityRecord.getDisplayArea()) + .thenReturn(expectedDisplayArea); + + mWpc.addActivityIfNeeded(activityRecord); + + assertEquals(expectedDisplayArea, mWpc.getTopActivityDisplayArea()); + } + + /** + * Test that top most activity respects z-order. + */ + @Test + public void testTopActivityDisplayAreaMatchesTopMostActivity_multipleActivities() { + final ActivityRecord bottomRecord = new ActivityBuilder(mSupervisor.mService).build(); + final TaskDisplayArea bottomDisplayArea = mock(TaskDisplayArea.class); + final ActivityRecord topRecord = new ActivityBuilder(mSupervisor.mService).build(); + final TaskDisplayArea topDisplayArea = mock(TaskDisplayArea.class); + + when(bottomRecord.getDisplayArea()).thenReturn(bottomDisplayArea); + when(topRecord.getDisplayArea()).thenReturn(topDisplayArea); + doReturn(-1).when(bottomRecord).compareTo(topRecord); + doReturn(1).when(topRecord).compareTo(bottomRecord); + + mWpc.addActivityIfNeeded(topRecord); + mWpc.addActivityIfNeeded(bottomRecord); + + assertEquals(topDisplayArea, mWpc.getTopActivityDisplayArea()); + } + private TestDisplayContent createTestDisplayContentInContainer() { return new TestDisplayContent.Builder(mAtm, 1000, 1500).build(); }