Merge "Decide on navigation to task by policy in Virtual Device" into tm-dev
diff --git a/core/java/android/window/DisplayWindowPolicyController.java b/core/java/android/window/DisplayWindowPolicyController.java
index 1270d87..d3cc918 100644
--- a/core/java/android/window/DisplayWindowPolicyController.java
+++ b/core/java/android/window/DisplayWindowPolicyController.java
@@ -110,6 +110,13 @@
@WindowConfiguration.WindowingMode int windowingMode);
/**
+ * Returns {@code true} if the given new task can be launched on this virtual display.
+ */
+ public abstract boolean canActivityBeLaunched(@NonNull ActivityInfo activityInfo,
+ @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId,
+ boolean isNewTask);
+
+ /**
* Called when an Activity window is layouted with the new changes where contains the
* window flags that we’re interested in.
* Returns {@code false} if the Activity cannot remain on the display and the activity task will
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 f4c24a8..27de8cd 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -76,6 +76,10 @@
@NonNull
private final ArraySet<UserHandle> mAllowedUsers;
@Nullable
+ private final ArraySet<ComponentName> mAllowedCrossTaskNavigations;
+ @Nullable
+ private final ArraySet<ComponentName> mBlockedCrossTaskNavigations;
+ @Nullable
private final ArraySet<ComponentName> mAllowedActivities;
@Nullable
private final ArraySet<ComponentName> mBlockedActivities;
@@ -100,6 +104,10 @@
* @param windowFlags The window flags that this controller is interested in.
* @param systemWindowFlags The system window flags that this controller is interested in.
* @param allowedUsers The set of users that are allowed to stream in this display.
+ * @param allowedCrossTaskNavigations The set of components explicitly allowed to navigate
+ * across tasks on this device.
+ * @param blockedCrossTaskNavigations The set of components explicitly blocked from
+ * navigating across tasks on this device.
* @param allowedActivities The set of activities explicitly allowed to stream on this device.
* Used only if the {@code activityPolicy} is
* {@link VirtualDeviceParams#ACTIVITY_POLICY_DEFAULT_BLOCKED}.
@@ -115,6 +123,8 @@
*/
public GenericWindowPolicyController(int windowFlags, int systemWindowFlags,
@NonNull ArraySet<UserHandle> allowedUsers,
+ @NonNull Set<ComponentName> allowedCrossTaskNavigations,
+ @NonNull Set<ComponentName> blockedCrossTaskNavigations,
@NonNull Set<ComponentName> allowedActivities,
@NonNull Set<ComponentName> blockedActivities,
@ActivityPolicy int defaultActivityPolicy,
@@ -122,6 +132,8 @@
@NonNull Consumer<ActivityInfo> activityBlockedCallback) {
super();
mAllowedUsers = allowedUsers;
+ mAllowedCrossTaskNavigations = new ArraySet<>(allowedCrossTaskNavigations);
+ mBlockedCrossTaskNavigations = new ArraySet<>(blockedCrossTaskNavigations);
mAllowedActivities = new ArraySet<>(allowedActivities);
mBlockedActivities = new ArraySet<>(blockedActivities);
mDefaultActivityPolicy = defaultActivityPolicy;
@@ -154,6 +166,46 @@
}
@Override
+ public boolean canActivityBeLaunched(ActivityInfo activityInfo,
+ @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId,
+ boolean isNewTask) {
+ if (!isWindowingModeSupported(windowingMode)) {
+ return false;
+ }
+
+ final ComponentName activityComponent = activityInfo.getComponentName();
+ if (BLOCKED_APP_STREAMING_COMPONENT.equals(activityComponent)) {
+ // The error dialog alerting users that streaming is blocked is always allowed.
+ return true;
+ }
+
+ if (!canContainActivity(activityInfo, /* windowFlags= */ 0, /* systemWindowFlags= */ 0)) {
+ mActivityBlockedCallback.accept(activityInfo);
+ return false;
+ }
+
+ if (launchingFromDisplayId == Display.DEFAULT_DISPLAY) {
+ return true;
+ }
+ if (isNewTask && !mBlockedCrossTaskNavigations.isEmpty()
+ && mBlockedCrossTaskNavigations.contains(activityComponent)) {
+ Slog.d(TAG, "Virtual device blocking cross task navigation of " + activityComponent);
+ mActivityBlockedCallback.accept(activityInfo);
+ return false;
+ }
+ if (isNewTask && !mAllowedCrossTaskNavigations.isEmpty()
+ && !mAllowedCrossTaskNavigations.contains(activityComponent)) {
+ Slog.d(TAG, "Virtual device not allowing cross task navigation of "
+ + activityComponent);
+ mActivityBlockedCallback.accept(activityInfo);
+ return false;
+ }
+
+ return true;
+ }
+
+
+ @Override
public boolean keepActivityOnWindowFlagsChanged(ActivityInfo activityInfo, int windowFlags,
int systemWindowFlags) {
if (!canContainActivity(activityInfo, windowFlags, systemWindowFlags)) {
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 235d286..90c879a 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -533,6 +533,8 @@
new GenericWindowPolicyController(FLAG_SECURE,
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
getAllowedUserHandles(),
+ mParams.getAllowedCrossTaskNavigations(),
+ mParams.getBlockedCrossTaskNavigations(),
mParams.getAllowedActivities(),
mParams.getBlockedActivities(),
mParams.getDefaultActivityPolicy(),
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index d72e0ba..dfc6fa9 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -135,7 +135,6 @@
import java.io.PrintWriter;
import java.text.DateFormat;
-import java.util.ArrayList;
import java.util.Date;
/**
@@ -2046,12 +2045,13 @@
final DisplayContent displayContent = mRootWindowContainer.getDisplayContentOrCreate(
mPreferredTaskDisplayArea.getDisplayId());
if (displayContent != null && displayContent.mDwpcHelper.hasController()) {
- final ArrayList<ActivityInfo> activities = new ArrayList<>();
- activities.add(r.info);
final int targetWindowingMode = (targetTask != null)
? targetTask.getWindowingMode() : displayContent.getWindowingMode();
+ final int launchingFromDisplayId =
+ mSourceRecord != null ? mSourceRecord.getDisplayId() : DEFAULT_DISPLAY;
if (!displayContent.mDwpcHelper
- .canContainActivities(activities, targetWindowingMode)) {
+ .canActivityBeLaunched(r.info, targetWindowingMode, launchingFromDisplayId,
+ newTask)) {
Slog.w(TAG, "Abort to launch " + r.info.getComponentName()
+ " on display area " + mPreferredTaskDisplayArea);
return START_ABORTED;
diff --git a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
index 27d46ec..2deb828 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
@@ -75,6 +75,19 @@
}
/**
+ * @see DisplayWindowPolicyController#canActivityBeLaunched(ActivityInfo, int, int, boolean)
+ */
+ public boolean canActivityBeLaunched(ActivityInfo activityInfo,
+ @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId,
+ boolean isNewTask) {
+ if (mDisplayWindowPolicyController == null) {
+ return true;
+ }
+ return mDisplayWindowPolicyController.canActivityBeLaunched(activityInfo, windowingMode,
+ launchingFromDisplayId, isNewTask);
+ }
+
+ /**
* @see DisplayWindowPolicyController#keepActivityOnWindowFlagsChanged(ActivityInfo, int, int)
*/
boolean keepActivityOnWindowFlagsChanged(ActivityInfo aInfo, int flagChanges,
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 75faf45..cd836c7 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
@@ -75,6 +75,8 @@
FLAG_SECURE,
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
/* allowedUsers= */ new ArraySet<>(),
+ /* allowedCrossTaskNavigations= */ new ArraySet<>(),
+ /* blockedCrossTaskNavigations= */ new ArraySet<>(),
/* allowedActivities= */ new ArraySet<>(),
/* blockedActivities= */ new ArraySet<>(),
VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED,
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 a8282600..02009b7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
@@ -170,7 +170,7 @@
}
@Test
- public void testCanContainActivities() {
+ public void testCanActivityBeLaunched() {
ActivityStarter starter = new ActivityStarter(mock(ActivityStartController.class), mAtm,
mSupervisor, mock(ActivityStartInterceptor.class));
final Task task = new TaskBuilder(mSupervisor).setDisplay(mSecondaryDisplay).build();
@@ -204,6 +204,13 @@
ArraySet<Integer> mRunningUids = new ArraySet<>();
@Override
+ public boolean canActivityBeLaunched(@NonNull ActivityInfo activity,
+ @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId,
+ boolean isNewTask) {
+ return false;
+ }
+
+ @Override
public boolean canContainActivities(@NonNull List<ActivityInfo> activities,
@WindowConfiguration.WindowingMode int windowingMode) {
final int activityCount = activities.size();