Merge "Use DeviceProfile to determine whether to exclude tasks from Recent" into tm-dev
diff --git a/core/java/android/window/DisplayWindowPolicyController.java b/core/java/android/window/DisplayWindowPolicyController.java
index d3cc918..a5aefd5 100644
--- a/core/java/android/window/DisplayWindowPolicyController.java
+++ b/core/java/android/window/DisplayWindowPolicyController.java
@@ -126,6 +126,11 @@
             ActivityInfo activityInfo, int windowFlags, int systemWindowFlags);
 
     /**
+     * Returns {@code true} if the tasks which is on this virtual display can be showed on Recents.
+     */
+    public abstract boolean canShowTasksInRecents();
+
+    /**
      * This is called when the top activity of the display is changed.
      */
     public void onTopActivityChanged(ComponentName topActivity, int uid) {}
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index 0b43744..4473a09 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -16,6 +16,8 @@
 
 package com.android.server.companion.virtual;
 
+import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING;
+import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
 import static android.content.pm.ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
@@ -24,6 +26,7 @@
 import android.annotation.Nullable;
 import android.app.WindowConfiguration;
 import android.app.compat.CompatChanges;
+import android.companion.AssociationRequest;
 import android.companion.virtual.VirtualDeviceManager.ActivityListener;
 import android.companion.virtual.VirtualDeviceParams;
 import android.companion.virtual.VirtualDeviceParams.ActivityPolicy;
@@ -95,6 +98,7 @@
     private final Handler mHandler = new Handler(Looper.getMainLooper());
     private final ArraySet<RunningAppsChangedListener> mRunningAppsChangedListener =
             new ArraySet<>();
+    private final @AssociationRequest.DeviceProfile String mDeviceProfile;
 
     /**
      * Creates a window policy controller that is generic to the different use cases of virtual
@@ -119,6 +123,7 @@
      *   is not populated in this callback and is always {@link Display#INVALID_DISPLAY}.
      * @param activityBlockedCallback Callback that is called when an activity is blocked from
      *   launching.
+     * @param deviceProfile The {@link AssociationRequest.DeviceProfile} of this virtual device.
      */
     public GenericWindowPolicyController(int windowFlags, int systemWindowFlags,
             @NonNull ArraySet<UserHandle> allowedUsers,
@@ -128,7 +133,8 @@
             @NonNull Set<ComponentName> blockedActivities,
             @ActivityPolicy int defaultActivityPolicy,
             @NonNull ActivityListener activityListener,
-            @NonNull Consumer<ActivityInfo> activityBlockedCallback) {
+            @NonNull Consumer<ActivityInfo> activityBlockedCallback,
+            @AssociationRequest.DeviceProfile String deviceProfile) {
         super();
         mAllowedUsers = allowedUsers;
         mAllowedCrossTaskNavigations = new ArraySet<>(allowedCrossTaskNavigations);
@@ -139,6 +145,7 @@
         mActivityBlockedCallback = activityBlockedCallback;
         setInterestedWindowFlags(windowFlags, systemWindowFlags);
         mActivityListener = activityListener;
+        mDeviceProfile = deviceProfile;
     }
 
     /** Register a listener for running applications changes. */
@@ -248,6 +255,18 @@
         });
     }
 
+    @Override
+    public boolean canShowTasksInRecents() {
+        // TODO(b/234075973) : Remove this once proper API is ready.
+        switch (mDeviceProfile) {
+            case DEVICE_PROFILE_AUTOMOTIVE_PROJECTION:
+                return false;
+            case DEVICE_PROFILE_APP_STREAMING:
+            default:
+                return true;
+        }
+    }
+
     /**
      * Returns true if an app with the given UID has an activity running on the virtual display for
      * this controller.
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 638b3ae..33fd83b 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -557,7 +557,8 @@
                             mParams.getBlockedActivities(),
                             mParams.getDefaultActivityPolicy(),
                             createListenerAdapter(displayId),
-                            activityInfo -> onActivityBlocked(displayId, activityInfo));
+                            activityInfo -> onActivityBlocked(displayId, activityInfo),
+                            mAssociationInfo.getDeviceProfile());
             gwpc.registerRunningAppsChangedListener(/* listener= */ this);
             mWindowPolicyControllers.put(displayId, gwpc);
             return gwpc;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 94f4382..a059ac6 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -225,6 +225,7 @@
 import android.view.WindowManager;
 import android.view.WindowManager.DisplayImePolicy;
 import android.view.WindowManagerPolicyConstants.PointerEventListener;
+import android.window.DisplayWindowPolicyController;
 import android.window.IDisplayAreaOrganizer;
 import android.window.TransitionRequestInfo;
 
@@ -1960,6 +1961,16 @@
     }
 
     /**
+     * @see DisplayWindowPolicyController#canShowTasksInRecents()
+     */
+    boolean canShowTasksInRecents() {
+        if (mDwpcHelper == null) {
+            return true;
+        }
+        return mDwpcHelper.canShowTasksInRecents();
+    }
+
+    /**
      * Applies the rotation transaction. This must be called after {@link #updateRotationUnchecked}
      * (if it returned {@code true}) to actually finish the rotation.
      *
diff --git a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
index 2deb828..5d49042 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
@@ -152,6 +152,16 @@
         return mDisplayWindowPolicyController.isWindowingModeSupported(windowingMode);
     }
 
+    /**
+     * @see DisplayWindowPolicyController#canShowTasksInRecents()
+     */
+    public final boolean canShowTasksInRecents() {
+        if (mDisplayWindowPolicyController == null) {
+            return true;
+        }
+        return mDisplayWindowPolicyController.canShowTasksInRecents();
+    }
+
     void dump(String prefix, PrintWriter pw) {
         if (mDisplayWindowPolicyController != null) {
             pw.println();
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index e259238..4860762 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1390,6 +1390,13 @@
             return false;
         }
 
+        // Ignore the task if it is started on a display which is not allow to show its tasks on
+        // Recents.
+        if (task.getDisplayContent() != null
+                && !task.getDisplayContent().canShowTasksInRecents()) {
+            return false;
+        }
+
         return true;
     }
 
@@ -1399,13 +1406,19 @@
     private boolean isInVisibleRange(Task task, int taskIndex, int numVisibleTasks,
             boolean skipExcludedCheck) {
         if (!skipExcludedCheck) {
-            // Keep the most recent task even if it is excluded from recents
+            // Keep the most recent task of home display even if it is excluded from recents.
             final boolean isExcludeFromRecents =
                     (task.getBaseIntent().getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
                             == FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
             if (isExcludeFromRecents) {
-                if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\texcludeFromRecents=true");
-                return taskIndex == 0;
+                if (DEBUG_RECENTS_TRIM_TASKS) {
+                    Slog.d(TAG,
+                            "\texcludeFromRecents=true, taskIndex = " + taskIndex
+                                    + ", isOnHomeDisplay: " + task.isOnHomeDisplay());
+                }
+                // The Recents is only supported on default display now, we should only keep the
+                // most recent task of home display.
+                return (task.isOnHomeDisplay() && taskIndex == 0);
             }
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
index cd836c7..e2c3a94 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.companion.virtual.audio;
 
+import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING;
 import static android.media.AudioAttributes.FLAG_SECURE;
 import static android.media.AudioPlaybackConfiguration.PLAYER_STATE_STARTED;
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
@@ -81,7 +82,8 @@
                 /* blockedActivities= */ new ArraySet<>(),
                 VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED,
                 /* activityListener= */ null,
-                /* activityBlockedCallback= */ null);
+                /* activityBlockedCallback= */ null,
+                /* deviceProfile= */ DEVICE_PROFILE_APP_STREAMING);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
index 02009b7..47c2176 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
@@ -242,5 +242,10 @@
             mRunningUids.clear();
             mRunningUids.addAll(runningUids);
         }
+
+        @Override
+        public boolean canShowTasksInRecents() {
+            return true;
+        }
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 2847283..feb1c6f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -691,6 +691,20 @@
     }
 
     @Test
+    public void testVisibleTasks_excludedFromRecents_nonDefaultDisplayTaskNotVisible() {
+        Task excludedTaskOnVirtualDisplay = createTaskBuilder(".excludedTaskOnVirtualDisplay")
+                .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+                .build();
+        excludedTaskOnVirtualDisplay.mUserSetupComplete = true;
+        doReturn(false).when(excludedTaskOnVirtualDisplay).isOnHomeDisplay();
+        mRecentTasks.add(mTasks.get(0));
+        mRecentTasks.add(excludedTaskOnVirtualDisplay);
+
+        // Expect that the first visible excluded-from-recents task is visible
+        assertGetRecentTasksOrder(0 /* flags */, mTasks.get(0));
+    }
+
+    @Test
     public void testVisibleTasks_excludedFromRecents_withExcluded() {
         // Create some set of tasks, some of which are visible and some are not
         Task t1 = createTaskBuilder("com.android.pkg1", ".Task1").build();
@@ -802,6 +816,17 @@
     }
 
     @Test
+    public void testVisibleTask_displayCanNotShowTaskFromRecents_expectNotVisible() {
+        final DisplayContent displayContent = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
+        doReturn(false).when(displayContent).canShowTasksInRecents();
+        final Task task = displayContent.getDefaultTaskDisplayArea().createRootTask(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
+        mRecentTasks.add(task);
+
+        assertFalse(mRecentTasks.isVisibleRecentTask(task));
+    }
+
+    @Test
     public void testFreezeTaskListOrder_reorderExistingTask() {
         // Add some tasks
         mRecentTasks.add(mTasks.get(0));