Update car launch params modifier.

Add missing parameter to CarLaunchParamsModifier
Update test for CarLaunchParamsModifier
Use source display for CarLaunchParamsModifier when allowed.

Test: atest CarServicesTest:CarLaunchParamsModifierTest
Bug: 152958720
Change-Id: I697d63ed26bc9a288afde2c57fba957eb4363b6d
diff --git a/src/com/android/internal/car/CarServiceHelperService.java b/src/com/android/internal/car/CarServiceHelperService.java
index 328a638..1a9097f 100644
--- a/src/com/android/internal/car/CarServiceHelperService.java
+++ b/src/com/android/internal/car/CarServiceHelperService.java
@@ -574,7 +574,7 @@
 
         @Override
         public void setDisplayAllowlistForUser(@UserIdInt int userId, int[] displayIds) {
-            mCarLaunchParamsModifier.setDisplayAllowlistForUser(userId, displayIds);
+            mCarLaunchParamsModifier.setDisplayAllowListForUser(userId, displayIds);
         }
 
         @Override
diff --git a/src/com/android/server/wm/CarLaunchParamsModifier.java b/src/com/android/server/wm/CarLaunchParamsModifier.java
index c5cbe78..d706ec1 100644
--- a/src/com/android/server/wm/CarLaunchParamsModifier.java
+++ b/src/com/android/server/wm/CarLaunchParamsModifier.java
@@ -16,6 +16,9 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.ActivityStarter.Request;
+
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
@@ -194,7 +197,7 @@
      * <p>The allowlist is kept only for profile user. Assigning the current user unassigns users
      * for the given displays.
      */
-    public void setDisplayAllowlistForUser(int userId, int[] displayIds) {
+    public void setDisplayAllowListForUser(int userId, int[] displayIds) {
         if (DBG) {
             Slog.d(TAG, "setDisplayAllowlistForUser userId:" + userId
                     + " displays:" + displayIds);
@@ -265,10 +268,11 @@
      * allowed, change to the 1st allowed display.</p>
      */
     @Override
-    public int onCalculate(Task task, ActivityInfo.WindowLayout layout, ActivityRecord activity,
-            ActivityRecord source, ActivityOptions options, int phase,
-            LaunchParamsController.LaunchParams currentParams,
-            LaunchParamsController.LaunchParams outParams) {
+    @Result
+    public int onCalculate(@Nullable Task task, @Nullable ActivityInfo.WindowLayout layout,
+            @Nullable ActivityRecord activity, @Nullable ActivityRecord source,
+            ActivityOptions options, int phase, LaunchParamsController.LaunchParams currentParams,
+            LaunchParamsController.LaunchParams outParams, @Nullable Request request) {
         int userId;
         if (task != null) {
             userId = task.mUserId;
@@ -349,7 +353,7 @@
                 break decision;
             }
             targetDisplayArea = getAlternativeDisplayAreaForPassengerLocked(
-                    userId, targetDisplayArea);
+                    userId, activity, request);
         }
         if (targetDisplayArea != null && originalDisplayArea != targetDisplayArea) {
             Slog.i(TAG, "Changed launching display, user:" + userId
@@ -364,21 +368,10 @@
 
     @Nullable
     private TaskDisplayArea getAlternativeDisplayAreaForPassengerLocked(int userId,
-            TaskDisplayArea originalDisplayArea) {
-        int displayId = mDefaultDisplayForProfileUser.get(userId, Display.INVALID_DISPLAY);
-        if (displayId != Display.INVALID_DISPLAY) {
-            return getDefaultTaskDisplayAreaOnDisplay(displayId);
-        }
-        // return the 1st passenger display area if it exists
-        if (!mPassengerDisplays.isEmpty()) {
-            Slog.w(TAG, "No default display area for user:" + userId
-                    + " reassign to 1st passenger display area");
-            return getDefaultTaskDisplayAreaOnDisplay(mPassengerDisplays.get(0));
-        }
-        Slog.w(TAG, "No default display for user:" + userId
-                + " and no passenger display, keep the requested display area:"
-                + originalDisplayArea);
-        return originalDisplayArea;
+            @NonNull ActivityRecord activityRecord, @Nullable Request request) {
+        TaskDisplayArea sourceDisplayArea = sourceDisplayArea(userId, activityRecord, request);
+
+        return sourceDisplayArea != null ? sourceDisplayArea : fallbackDisplayArea(userId);
     }
 
     @VisibleForTesting
@@ -390,4 +383,99 @@
         }
         return dc.getDefaultTaskDisplayArea();
     }
+
+    /**
+     * Calculates the {@link TaskDisplayArea} for the source of the request. The source is
+     * calculated implicitly from the request or the activity record.
+     *
+     * @param userId ID of the current active user
+     * @param activityRecord {@link ActivityRecord} that is to be shown
+     * @param request {@link Request} data for showing the {@link ActivityRecord}
+     * @return {@link TaskDisplayArea} First non {@code null} candidate display area that is allowed
+     * for the user.  It is allowed if the display has been added to the profile mapping.
+     */
+    @Nullable
+    private TaskDisplayArea sourceDisplayArea(int userId, @NonNull ActivityRecord activityRecord,
+            @Nullable Request request) {
+        List<WindowProcessController> candidateControllers = candidateControllers(activityRecord,
+                request);
+
+        for (int i = 0; i < candidateControllers.size(); i++) {
+            WindowProcessController controller = candidateControllers.get(i);
+            TaskDisplayArea candidate = controller.getTopActivityDisplayArea();
+            int displayId = candidate != null ? candidate.getDisplayId() : Display.INVALID_DISPLAY;
+            int userForDisplay = mDisplayToProfileUserMapping.get(displayId, UserHandle.USER_NULL);
+            if (userForDisplay == userId) {
+                return candidate;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Calculates a list of {@link WindowProcessController} that can calculate the
+     * {@link TaskDisplayArea} to house the {@link ActivityRecord}. Controllers are calculated since
+     * calculating the display can be expensive. The list is ordered in the
+     * following way
+     * <ol>
+     *     <li>Controller for the activity record from the process name and app uid</li>
+     *     <li>Controller for the activity that is launching the given record</li>
+     *     <li>Controller for the actual process that is launching the record</li>
+     * </ol>
+     *
+     * @param activityRecord {@link ActivityRecord} that is to be shown
+     * @param request {@link Request} data for showing the {@link ActivityRecord}
+     * @return {@link List} of {@link WindowProcessController} ordered by preference to be shown
+     */
+    private List<WindowProcessController> candidateControllers(
+            @NonNull ActivityRecord activityRecord, @Nullable Request request) {
+        WindowProcessController firstController = mAtm.getProcessController(
+                activityRecord.getProcessName(), activityRecord.getUid());
+
+        WindowProcessController secondController = mAtm.getProcessController(
+                activityRecord.getLaunchedFromPid(), activityRecord.getLaunchedFromUid());
+
+        WindowProcessController thirdController = request == null ? null :
+                mAtm.getProcessController(request.realCallingPid, request.realCallingUid);
+
+        List<WindowProcessController> candidates = new ArrayList<>(3);
+
+        if (firstController != null) {
+            candidates.add(firstController);
+        }
+        if (secondController != null) {
+            candidates.add(secondController);
+        }
+        if (thirdController != null) {
+            candidates.add(thirdController);
+        }
+
+        return candidates;
+    }
+
+    /**
+     * Return a {@link TaskDisplayArea} that can be used if a source display area is not found.
+     * First check the default display for the user. If it is absent select the first passenger
+     * display if present.  If both are absent return {@code null}
+     *
+     * @param userId ID of the active user
+     * @return {@link TaskDisplayArea} that is recommended when a display area is not specified
+     */
+    @Nullable
+    private TaskDisplayArea fallbackDisplayArea(int userId) {
+        int displayIdForUserProfile = mDefaultDisplayForProfileUser.get(userId,
+                Display.INVALID_DISPLAY);
+        if (displayIdForUserProfile != Display.INVALID_DISPLAY) {
+            int displayId = mDefaultDisplayForProfileUser.get(userId);
+            return getDefaultTaskDisplayAreaOnDisplay(displayId);
+        }
+
+        if (!mPassengerDisplays.isEmpty()) {
+            int displayId = mPassengerDisplays.get(0);
+            return getDefaultTaskDisplayAreaOnDisplay(displayId);
+        }
+
+        return null;
+    }
+
 }
diff --git a/tests/src/com/android/server/wm/CarLaunchParamsModifierTest.java b/tests/src/com/android/server/wm/CarLaunchParamsModifierTest.java
index fe4138a..29fb540 100644
--- a/tests/src/com/android/server/wm/CarLaunchParamsModifierTest.java
+++ b/tests/src/com/android/server/wm/CarLaunchParamsModifierTest.java
@@ -24,6 +24,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
 
 import android.annotation.UserIdInt;
@@ -57,6 +59,11 @@
 
 import java.util.Arrays;
 
+/**
+ * Tests for {@link CarLaunchParamsModifier}
+ * Build/Install/Run:
+ *  atest CarServicesTest:CarLaunchParamsModifierTest
+ */
 @RunWith(AndroidJUnit4.class)
 public class CarLaunchParamsModifierTest {
     private static final int PASSENGER_DISPLAY_ID_10 = 10;
@@ -176,7 +183,8 @@
         mCurrentParams.mPreferredTaskDisplayArea = mModifier
                 .getDefaultTaskDisplayAreaOnDisplay(display.getDisplayId());
         assertThat(mModifier.onCalculate(mTask, mWindowLayout, mActivityRecordActivity,
-                mActivityRecordSource, mActivityOptions, 0, mCurrentParams, mOutParams))
+                mActivityRecordSource, mActivityOptions, 0, mCurrentParams, mOutParams,
+                null /* request */))
                 .isEqualTo(LaunchParamsController.LaunchParamsModifier.RESULT_SKIP);
     }
 
@@ -190,7 +198,8 @@
                 .getDefaultTaskDisplayAreaOnDisplay(displayAssigned.getDisplayId());
         mCurrentParams.mPreferredTaskDisplayArea = requestedTaskDisplayArea;
         assertThat(mModifier.onCalculate(mTask, mWindowLayout, mActivityRecordActivity,
-                mActivityRecordSource, mActivityOptions, 0, mCurrentParams, mOutParams))
+                mActivityRecordSource, mActivityOptions, 0, mCurrentParams, mOutParams,
+                null /* request */))
                 .isEqualTo(LaunchParamsController.LaunchParamsModifier.RESULT_DONE);
         assertThat(mOutParams.mPreferredTaskDisplayArea).isEqualTo(assignedTaskDisplayArea);
     }
@@ -200,7 +209,8 @@
         mTask.mUserId = userId;
         mCurrentParams.mPreferredTaskDisplayArea = null;
         assertThat(mModifier.onCalculate(mTask, mWindowLayout, mActivityRecordActivity,
-                mActivityRecordSource, mActivityOptions, 0, mCurrentParams, mOutParams))
+                mActivityRecordSource, mActivityOptions, 0, mCurrentParams, mOutParams,
+                null /* request */))
                 .isEqualTo(LaunchParamsController.LaunchParamsModifier.RESULT_DONE);
         assertThat(mOutParams.mPreferredTaskDisplayArea).isEqualTo(expectedDisplayArea);
     }
@@ -209,7 +219,8 @@
         mTask.mUserId = userId;
         mCurrentParams.mPreferredTaskDisplayArea = null;
         assertThat(mModifier.onCalculate(mTask, mWindowLayout, mActivityRecordActivity,
-                mActivityRecordSource, mActivityOptions, 0, mCurrentParams, mOutParams))
+                mActivityRecordSource, mActivityOptions, 0, mCurrentParams, mOutParams,
+                null /* request */))
                 .isEqualTo(LaunchParamsController.LaunchParamsModifier.RESULT_SKIP);
         assertThat(mOutParams.mPreferredTaskDisplayArea).isNull();
     }
@@ -281,7 +292,7 @@
                 mDisplay11ForPassenger.getDisplayId()});
 
         final int passengerUserId = 100;
-        mModifier.setDisplayAllowlistForUser(passengerUserId,
+        mModifier.setDisplayAllowListForUser(passengerUserId,
                 new int[]{mDisplay10ForPassenger.getDisplayId()});
 
         assertDisplayIsAllowed(passengerUserId, mDisplay10ForPassenger);
@@ -293,13 +304,13 @@
                 mDisplay11ForPassenger.getDisplayId()});
 
         int passengerUserId1 = 100;
-        mModifier.setDisplayAllowlistForUser(passengerUserId1,
+        mModifier.setDisplayAllowListForUser(passengerUserId1,
                 new int[]{mDisplay11ForPassenger.getDisplayId()});
 
         assertDisplayIsAllowed(passengerUserId1, mDisplay11ForPassenger);
 
         int passengerUserId2 = 101;
-        mModifier.setDisplayAllowlistForUser(passengerUserId2,
+        mModifier.setDisplayAllowListForUser(passengerUserId2,
                 new int[]{mDisplay11ForPassenger.getDisplayId()});
 
         assertDisplayIsAllowed(passengerUserId2, mDisplay11ForPassenger);
@@ -313,7 +324,7 @@
                 mDisplay11ForPassenger.getDisplayId()});
 
         final int passengerUserId = 100;
-        mModifier.setDisplayAllowlistForUser(
+        mModifier.setDisplayAllowListForUser(
                 passengerUserId, new int[]{mDisplay10ForPassenger.getDisplayId()});
 
         assertDisplayIsReassigned(passengerUserId, mDisplay0ForDriver, mDisplay10ForPassenger);
@@ -326,7 +337,7 @@
                 mDisplay11ForPassenger.getDisplayId()});
 
         int passengerUserId = 100;
-        mModifier.setDisplayAllowlistForUser(
+        mModifier.setDisplayAllowListForUser(
                 passengerUserId, new int[]{mDisplay11ForPassenger.getDisplayId()});
         assertDisplayIsAllowed(passengerUserId, mDisplay11ForPassenger);
 
@@ -342,11 +353,11 @@
                 mDisplay11ForPassenger.getDisplayId()});
 
         int passengerUserId = 100;
-        mModifier.setDisplayAllowlistForUser(
+        mModifier.setDisplayAllowListForUser(
                 passengerUserId, new int[]{mDisplay11ForPassenger.getDisplayId()});
         assertDisplayIsAllowed(passengerUserId, mDisplay11ForPassenger);
 
-        mModifier.setDisplayAllowlistForUser(
+        mModifier.setDisplayAllowListForUser(
                 UserHandle.USER_SYSTEM, new int[]{mDisplay11ForPassenger.getDisplayId()});
 
         assertDisplayIsReassigned(passengerUserId, mDisplay0ForDriver, mDisplay10ForPassenger);
@@ -359,7 +370,7 @@
                 mDisplay11ForPassenger.getDisplayId()});
 
         final int passengerUserId = 100;
-        mModifier.setDisplayAllowlistForUser(passengerUserId,
+        mModifier.setDisplayAllowListForUser(passengerUserId,
                 new int[]{mDisplay10ForPassenger.getDisplayId(),
                         mDisplay11ForPassenger.getDisplayId()});
 
@@ -378,7 +389,7 @@
                 mDisplay11ForPassenger.getDisplayId()});
 
         final int passengerUserId = 100;
-        mModifier.setDisplayAllowlistForUser(passengerUserId,
+        mModifier.setDisplayAllowListForUser(passengerUserId,
                 new int[]{mDisplay10ForPassenger.getDisplayId(),
                         mDisplay11ForPassenger.getDisplayId()});
 
@@ -397,7 +408,7 @@
                 mDisplay11ForPassenger.getDisplayId()});
 
         final int passengerUserId = 100;
-        mModifier.setDisplayAllowlistForUser(passengerUserId,
+        mModifier.setDisplayAllowListForUser(passengerUserId,
                 new int[]{mDisplay10ForPassenger.getDisplayId(),
                         mDisplay10ForPassenger.getDisplayId()});
 
@@ -412,7 +423,7 @@
         final int wasDriver = 10;
         final int wasPassenger = 11;
         mModifier.handleCurrentUserSwitching(wasDriver);
-        mModifier.setDisplayAllowlistForUser(wasPassenger,
+        mModifier.setDisplayAllowListForUser(wasPassenger,
                 new int[]{mDisplay10ForPassenger.getDisplayId(),
                         mDisplay11ForPassenger.getDisplayId()});
 
@@ -426,7 +437,7 @@
         final int driver = wasPassenger;
         final int passenger = wasDriver;
         mModifier.handleCurrentUserSwitching(driver);
-        mModifier.setDisplayAllowlistForUser(passenger,
+        mModifier.setDisplayAllowListForUser(passenger,
                 new int[]{mDisplay10ForPassenger.getDisplayId(),
                         mDisplay11ForPassenger.getDisplayId()});
 
@@ -453,7 +464,7 @@
     public void testPreferSourceForPassenger() {
         mModifier.setPassengerDisplays(new int[]{PASSENGER_DISPLAY_ID_10, PASSENGER_DISPLAY_ID_11});
         int passengerUserId = 100;
-        mModifier.setDisplayAllowlistForUser(passengerUserId,
+        mModifier.setDisplayAllowListForUser(passengerUserId,
                 new int[]{PASSENGER_DISPLAY_ID_10, PASSENGER_DISPLAY_ID_11});
         when(mActivityRecordSource.getDisplayArea()).thenReturn(mDisplayArea11ForPassenger);
 
@@ -492,4 +503,117 @@
 
         assertNoDisplayIsAssigned(UserHandle.USER_SYSTEM);
     }
+
+    @Test
+    public void testSourceDisplayFromProcessDisplayIfAvailable() {
+        int userId = 10;
+        String processName = "processName";
+        int processUid = 11;
+        when(mActivityRecordActivity.getProcessName())
+                .thenReturn(processName);
+        when(mActivityRecordActivity.getUid())
+                .thenReturn(processUid);
+        mModifier.setPassengerDisplays(new int[]{mDisplay11ForPassenger.getDisplayId(),
+                mDisplay10ForPassenger.getDisplayId()});
+        mModifier.setDisplayAllowListForUser(userId,
+                new int[]{mDisplay10ForPassenger.getDisplayId()});
+        WindowProcessController controller = mock(WindowProcessController.class);
+        when(mActivityTaskManagerService.getProcessController(processName, processUid))
+                .thenReturn(controller);
+        when(controller.getTopActivityDisplayArea())
+                .thenReturn(mDisplayArea10ForPassenger);
+        mCurrentParams.mPreferredTaskDisplayArea = null;
+        mTask.mUserId = userId;
+
+        assertThat(mModifier.onCalculate(mTask, mWindowLayout, mActivityRecordActivity,
+                mActivityRecordSource, null, 0, mCurrentParams, mOutParams,
+                null /* request */))
+                .isEqualTo(TaskLaunchParamsModifier.RESULT_DONE);
+        assertThat(mOutParams.mPreferredTaskDisplayArea)
+                .isEqualTo(mDisplayArea10ForPassenger);
+    }
+
+    @Test
+    public void testSourceDisplayFromLaunchingDisplayIfAvailable() {
+        int userId = 10;
+        int launchedFromPid = 1324;
+        int launchedFromUid = 325;
+        when(mActivityRecordActivity.getLaunchedFromPid())
+                .thenReturn(launchedFromPid);
+        when(mActivityRecordActivity.getLaunchedFromUid())
+                .thenReturn(launchedFromUid);
+        mModifier.setPassengerDisplays(new int[]{mDisplay11ForPassenger.getDisplayId(),
+                mDisplay10ForPassenger.getDisplayId()});
+        mModifier.setDisplayAllowListForUser(userId,
+                new int[]{mDisplay10ForPassenger.getDisplayId()});
+        WindowProcessController controller = mock(WindowProcessController.class);
+        when(mActivityTaskManagerService.getProcessController(launchedFromPid, launchedFromUid))
+                .thenReturn(controller);
+        when(controller.getTopActivityDisplayArea())
+                .thenReturn(mDisplayArea10ForPassenger);
+        mCurrentParams.mPreferredTaskDisplayArea = null;
+        mTask.mUserId = 10;
+
+        assertThat(mModifier.onCalculate(mTask, mWindowLayout, mActivityRecordActivity,
+                mActivityRecordSource, null, 0, mCurrentParams, mOutParams,
+                null /* request */))
+                .isEqualTo(TaskLaunchParamsModifier.RESULT_DONE);
+        assertThat(mOutParams.mPreferredTaskDisplayArea)
+                .isEqualTo(mDisplayArea10ForPassenger);
+    }
+
+    @Test
+    public void testSourceDisplayFromCallingDisplayIfAvailable() {
+        int userId = 10;
+        ActivityStarter.Request request = fakeRequest();
+        mModifier.setPassengerDisplays(new int[]{mDisplay11ForPassenger.getDisplayId(),
+                mDisplay10ForPassenger.getDisplayId()});
+        mModifier.setDisplayAllowListForUser(userId,
+                new int[]{mDisplay10ForPassenger.getDisplayId()});
+        WindowProcessController controller = mock(WindowProcessController.class);
+        when(mActivityTaskManagerService.getProcessController(request.realCallingPid,
+                request.realCallingUid))
+                .thenReturn(controller);
+        when(controller.getTopActivityDisplayArea())
+                .thenReturn(mDisplayArea10ForPassenger);
+        mCurrentParams.mPreferredTaskDisplayArea = null;
+        mTask.mUserId = userId;
+
+        assertThat(mModifier.onCalculate(mTask, mWindowLayout, mActivityRecordActivity,
+                mActivityRecordSource, null, 0, mCurrentParams, mOutParams,
+                request))
+                .isEqualTo(TaskLaunchParamsModifier.RESULT_DONE);
+        assertThat(mOutParams.mPreferredTaskDisplayArea)
+                .isEqualTo(mDisplayArea10ForPassenger);
+    }
+
+    @Test
+    public void testSourceDisplayIgnoredIfNotInAllowList() {
+        ActivityStarter.Request request = fakeRequest();
+        mModifier.setPassengerDisplays(new int[]{mDisplay11ForPassenger.getDisplayId(),
+                mDisplay10ForPassenger.getDisplayId()});
+        WindowProcessController controller = mock(WindowProcessController.class);
+        when(mActivityTaskManagerService.getProcessController(anyString(), anyInt()))
+                .thenReturn(controller);
+        when(mActivityTaskManagerService.getProcessController(anyInt(), anyInt()))
+                .thenReturn(controller);
+        when(controller.getTopActivityDisplayArea())
+                .thenReturn(mDisplayArea10ForPassenger);
+        mCurrentParams.mPreferredTaskDisplayArea = null;
+        mTask.mUserId = 10;
+
+        assertThat(mModifier.onCalculate(mTask, mWindowLayout, mActivityRecordActivity,
+                mActivityRecordSource, null, 0, mCurrentParams, mOutParams,
+                request))
+                .isEqualTo(TaskLaunchParamsModifier.RESULT_DONE);
+        assertThat(mOutParams.mPreferredTaskDisplayArea)
+                .isEqualTo(mDisplayArea11ForPassenger);
+    }
+
+    private ActivityStarter.Request fakeRequest() {
+        ActivityStarter.Request request = new ActivityStarter.Request();
+        request.realCallingPid = 1324;
+        request.realCallingUid = 235;
+        return request;
+    }
 }