Use DeviceProfile to determine whether to exclude tasks from Recent
For Android Auto, tasks should exclude from Recents by default.
For App streaming device profile, tasks should be showed from Recents.
This change also keep the most recent task of "Default display" in
Recents even if it's excluded from Recents.
Bug: 232385935
Test: atest WmTests:RecentTasksTest
Change-Id: Ic01ed6bbae1f2b77f8664196cbc59b248f5ec3b4
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 c60dfa1..ebe0efb 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -224,6 +224,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;
@@ -1959,6 +1960,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));