Merge "Pass IntentSender to VDM's onActivityLaunchBlocked" into main
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index bed1b43..15e5706 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3448,7 +3448,7 @@
   }
 
   public static interface VirtualDeviceManager.ActivityListener {
-    method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public default void onActivityLaunchBlocked(int, @NonNull android.content.ComponentName, int);
+    method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public default void onActivityLaunchBlocked(int, @NonNull android.content.ComponentName, int, @Nullable android.content.IntentSender);
     method public void onDisplayEmpty(int);
     method @Deprecated public void onTopActivityChanged(int, @NonNull android.content.ComponentName);
     method public default void onTopActivityChanged(int, @NonNull android.content.ComponentName, int);
diff --git a/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl b/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl
index 39371a3..564fb02 100644
--- a/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl
+++ b/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl
@@ -17,6 +17,7 @@
 package android.companion.virtual;
 
 import android.content.ComponentName;
+import android.content.IntentSender;
 
 /**
  * Interface to listen for activity changes in a virtual device.
@@ -48,6 +49,8 @@
      * @param displayId The display ID on which the activity tried to launch.
      * @param componentName The component name of the blocked activity.
      * @param userId The user ID associated with the blocked activity.
+     * @param intentSender The original sender of the intent.
      */
-    void onActivityLaunchBlocked(int displayId, in ComponentName componentName, int userId);
+    void onActivityLaunchBlocked(int displayId, in ComponentName componentName, int userId,
+            in IntentSender intentSender);
 }
diff --git a/core/java/android/companion/virtual/VirtualDeviceInternal.java b/core/java/android/companion/virtual/VirtualDeviceInternal.java
index d8899b2..19eb497 100644
--- a/core/java/android/companion/virtual/VirtualDeviceInternal.java
+++ b/core/java/android/companion/virtual/VirtualDeviceInternal.java
@@ -38,6 +38,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.IntentSender;
 import android.hardware.display.DisplayManagerGlobal;
 import android.hardware.display.IVirtualDisplayCallback;
 import android.hardware.display.VirtualDisplay;
@@ -135,13 +136,14 @@
 
                 @Override
                 public void onActivityLaunchBlocked(int displayId, ComponentName componentName,
-                        @UserIdInt int userId) {
+                        @UserIdInt int userId, IntentSender intentSender) {
                     final long token = Binder.clearCallingIdentity();
                     try {
                         synchronized (mActivityListenersLock) {
                             for (int i = 0; i < mActivityListeners.size(); i++) {
                                 mActivityListeners.valueAt(i)
-                                        .onActivityLaunchBlocked(displayId, componentName, userId);
+                                        .onActivityLaunchBlocked(
+                                                displayId, componentName, userId, intentSender);
                             }
                         }
                     } finally {
@@ -593,9 +595,10 @@
         }
 
         public void onActivityLaunchBlocked(int displayId, ComponentName componentName,
-                @UserIdInt int userId) {
+                @UserIdInt int userId, IntentSender intentSender) {
             mExecutor.execute(() ->
-                    mActivityListener.onActivityLaunchBlocked(displayId, componentName, userId));
+                    mActivityListener.onActivityLaunchBlocked(
+                            displayId, componentName, userId, intentSender));
         }
     }
 
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index d89ffc9..8b60580 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -43,6 +43,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.IntentSender;
 import android.graphics.Point;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.VirtualDisplayFlag;
@@ -1264,13 +1265,18 @@
          * @param displayId The display ID on which the activity tried to launch.
          * @param componentName The component name of the blocked activity.
          * @param userId The user ID associated with the blocked activity.
+         * @param intentSender The original sender of the intent. May be {@code null} if the sender
+         *   expects an activity result to be reported. In that case
+         *   {@link android.app.Activity#RESULT_CANCELED} was already reported back because the
+         *   launch was blocked. This {@link IntentSender} can be used to relaunch the blocked
+         *   activity to a different display.
          *
          * @see VirtualDeviceParams#POLICY_TYPE_ACTIVITY
          * @see VirtualDevice#addActivityPolicyExemption(ComponentName)
          */
         @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API)
         default void onActivityLaunchBlocked(int displayId, @NonNull ComponentName componentName,
-                @UserIdInt int userId) {}
+                @UserIdInt int userId, @Nullable IntentSender intentSender) {}
     }
 
     /**
diff --git a/core/java/android/window/DisplayWindowPolicyController.java b/core/java/android/window/DisplayWindowPolicyController.java
index 62a7283..a16d537 100644
--- a/core/java/android/window/DisplayWindowPolicyController.java
+++ b/core/java/android/window/DisplayWindowPolicyController.java
@@ -25,12 +25,14 @@
 import android.app.WindowConfiguration;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.util.ArraySet;
 
 import java.io.PrintWriter;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Supplier;
 
 /**
  * Abstract class to control the policies of the windows that can be displayed on the virtual
@@ -136,10 +138,14 @@
      * Returns {@code true} if the given activity can be launched on this virtual display in the
      * configuration defined by the rest of the arguments. If the given intent would be intercepted
      * by the display owner then this means that the activity cannot be launched.
+     *
+     * The intentSender argument can provide an IntentSender for the original intent to be passed
+     * to any activity listeners, in case the activity cannot be launched.
      */
     public abstract boolean canActivityBeLaunched(@NonNull ActivityInfo activityInfo,
             @Nullable Intent intent, @WindowConfiguration.WindowingMode int windowingMode,
-            int launchingFromDisplayId, boolean isNewTask);
+            int launchingFromDisplayId, boolean isNewTask, boolean isResultExpected,
+            @Nullable Supplier<IntentSender> intentSender);
 
     /**
      * Returns {@code true} if the given activity can be launched on this virtual display in the
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 84b5c39..e57817f 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -33,6 +33,7 @@
 import android.content.AttributionSource;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.os.Build;
 import android.os.Handler;
@@ -51,6 +52,7 @@
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
 
 /**
  * A controller to control the policies of the windows that can be displayed on the virtual display.
@@ -73,7 +75,7 @@
      */
     public interface ActivityBlockedCallback {
         /** Called when an activity is blocked.*/
-        void onActivityBlocked(int displayId, ActivityInfo activityInfo);
+        void onActivityBlocked(int displayId, ActivityInfo activityInfo, IntentSender intentSender);
     }
     private static final ComponentName BLOCKED_APP_STREAMING_COMPONENT =
             new ComponentName("android", BlockedAppStreamingActivity.class.getName());
@@ -282,7 +284,8 @@
     @Override
     public boolean canActivityBeLaunched(@NonNull ActivityInfo activityInfo,
             @Nullable Intent intent, @WindowConfiguration.WindowingMode int windowingMode,
-            int launchingFromDisplayId, boolean isNewTask) {
+            int launchingFromDisplayId, boolean isNewTask, boolean isResultExpected,
+            @Nullable Supplier<IntentSender> intentSender) {
         if (mIntentListenerCallback != null && intent != null
                 && mIntentListenerCallback.shouldInterceptIntent(intent)) {
             logActivityLaunchBlocked("Virtual device intercepting intent");
@@ -290,7 +293,10 @@
         }
         if (!canContainActivity(activityInfo, windowingMode, launchingFromDisplayId,
                 isNewTask)) {
-            notifyActivityBlocked(activityInfo);
+            // If the sender of the original intent expects a result to be reported, do not pass the
+            // intent sender to the client callback. As the launch is blocked, the caller already
+            // received that activity result.
+            notifyActivityBlocked(activityInfo, isResultExpected ? null : intentSender);
             return false;
         }
         return true;
@@ -381,7 +387,7 @@
             // TODO(b/201712607): Add checks for the apps that use SurfaceView#setSecure.
             if ((windowFlags & FLAG_SECURE) != 0
                     || (systemWindowFlags & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
-                notifyActivityBlocked(activityInfo);
+                notifyActivityBlocked(activityInfo, /* intentSender= */ null);
                 return false;
             }
         }
@@ -454,13 +460,15 @@
                     && mDisplayCategories.contains(activityInfo.requiredDisplayCategory);
     }
 
-    private void notifyActivityBlocked(ActivityInfo activityInfo) {
+    private void notifyActivityBlocked(
+            ActivityInfo activityInfo, Supplier<IntentSender> intentSender) {
         int displayId = waitAndGetDisplayId();
         // Don't trigger activity blocked callback for mirror displays, because we can't show
         // any activity or presentation on it anyway.
         if (!waitAndGetIsMirrorDisplay() && mActivityBlockedCallback != null
                 && displayId != INVALID_DISPLAY) {
-            mActivityBlockedCallback.onActivityBlocked(displayId, activityInfo);
+            mActivityBlockedCallback.onActivityBlocked(displayId, activityInfo,
+                    intentSender == null ? null : intentSender.get());
         }
         Counter.logIncrementWithUid(
                 "virtual_devices.value_activity_blocked_count",
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 ed2c90d..2db5443 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -60,6 +60,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.graphics.PointF;
@@ -241,9 +242,11 @@
 
             @Override
             public void onActivityLaunchBlocked(int displayId,
-                    @NonNull ComponentName componentName, @UserIdInt int userId) {
+                    @NonNull ComponentName componentName, @UserIdInt int userId,
+                    @Nullable IntentSender intentSender) {
                 try {
-                    mActivityListener.onActivityLaunchBlocked(displayId, componentName, userId);
+                    mActivityListener.onActivityLaunchBlocked(
+                            displayId, componentName, userId, intentSender);
                 } catch (RemoteException e) {
                     Slog.w(TAG, "Unable to call mActivityListener for display: " + displayId, e);
                 }
@@ -1364,7 +1367,8 @@
     }
 
     @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
-    private void onActivityBlocked(int displayId, ActivityInfo activityInfo) {
+    private void onActivityBlocked(int displayId, ActivityInfo activityInfo,
+            IntentSender intentSender) {
         Intent intent = BlockedAppStreamingActivity.createIntent(activityInfo, getDisplayName());
         if (shouldShowBlockedActivityDialog(
                 activityInfo.getComponentName(), intent.getComponent())) {
@@ -1380,7 +1384,8 @@
                     displayId,
                     activityInfo.getComponentName(),
                     UserHandle.getUserHandleForUid(
-                            activityInfo.applicationInfo.uid).getIdentifier());
+                            activityInfo.applicationInfo.uid).getIdentifier(),
+                    intentSender);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index cc195ac..2f6e7de 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -28,6 +28,8 @@
 import static android.app.ActivityManager.START_SUCCESS;
 import static android.app.ActivityManager.START_TASK_TO_FRONT;
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
+import static android.app.PendingIntent.FLAG_ONE_SHOT;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
@@ -146,6 +148,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.text.DateFormat;
 import java.util.Date;
+import java.util.function.Supplier;
 
 /**
  * Controller for interpreting how and then launching an activity.
@@ -2079,9 +2082,23 @@
                         ? targetTask.getWindowingMode() : displayContent.getWindowingMode();
                 final int launchingFromDisplayId =
                         mSourceRecord != null ? mSourceRecord.getDisplayId() : DEFAULT_DISPLAY;
+                final boolean isResultExpected = r.resultTo != null;
+                Supplier<IntentSender> intentSender = null;
+                if (android.companion.virtualdevice.flags.Flags.activityControlApi()) {
+                    intentSender = () -> {
+                        IIntentSender target = mService.getIntentSenderLocked(
+                                ActivityManager.INTENT_SENDER_ACTIVITY, mRequest.callingPackage,
+                                mRequest.callingFeatureId, mCallingUid, r.mUserId,
+                                /* token= */ null, /* resultCode= */ null, /* requestCode= */ 0,
+                                new Intent[]{ mIntent }, new String[]{ r.resolvedType },
+                                FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT,
+                                mOptions == null ? null : mOptions.toBundle());
+                        return new IntentSender(target);
+                    };
+                }
                 if (!displayContent.mDwpcHelper
                         .canActivityBeLaunched(r.info, r.intent, targetWindowingMode,
-                          launchingFromDisplayId, newTask)) {
+                                launchingFromDisplayId, newTask, isResultExpected, intentSender)) {
                     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 4ec318b..dedf35a 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
@@ -24,6 +24,7 @@
 import android.companion.virtualdevice.flags.Flags;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.os.Process;
 import android.os.UserHandle;
@@ -34,6 +35,7 @@
 
 import java.io.PrintWriter;
 import java.util.List;
+import java.util.function.Supplier;
 
 class DisplayWindowPolicyControllerHelper {
     private static final String TAG = "DisplayWindowPolicyControllerHelper";
@@ -98,7 +100,8 @@
      */
     public boolean canActivityBeLaunched(ActivityInfo activityInfo,
             Intent intent, @WindowConfiguration.WindowingMode int windowingMode,
-            int launchingFromDisplayId, boolean isNewTask) {
+            int launchingFromDisplayId, boolean isNewTask, boolean isResultExpected,
+            Supplier<IntentSender> intentSender) {
         if (mDisplayWindowPolicyController == null) {
             // Missing controller means that this display has no categories for activity launch
             // restriction.
@@ -111,7 +114,7 @@
             return true;
         }
         return mDisplayWindowPolicyController.canActivityBeLaunched(activityInfo, intent,
-            windowingMode, launchingFromDisplayId, isNewTask);
+            windowingMode, launchingFromDisplayId, isNewTask, isResultExpected, intentSender);
     }
 
     private boolean hasDisplayCategory(ActivityInfo aInfo) {
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java
index 7eabfac..9317d06 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java
@@ -42,9 +42,11 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
@@ -592,13 +594,15 @@
         // register interceptor and intercept intent
         when(mIntentListenerCallback.shouldInterceptIntent(any(Intent.class))).thenReturn(true);
         assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID, /*isNewTask=*/false))
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID, /* isNewTask= */false,
+                /* isResultExpected = */ false, /* intentSender= */ null))
                 .isFalse();
 
         // unregister interceptor and launch activity
         when(mIntentListenerCallback.shouldInterceptIntent(any(Intent.class))).thenReturn(false);
         assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID, /*isNewTask=*/false))
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID, /* isNewTask= */false,
+                /* isResultExpected = */ false, /* intentSender= */ null))
                 .isTrue();
     }
 
@@ -617,13 +621,36 @@
         // register interceptor with different filter
         when(mIntentListenerCallback.shouldInterceptIntent(any(Intent.class))).thenReturn(false);
         assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID, /*isNewTask=*/false))
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID, /* isNewTask= */false,
+                /* isResultExpected = */ false, /* intentSender= */ null))
                 .isTrue();
         verify(mIntentListenerCallback, timeout(TIMEOUT_MILLIS))
                 .shouldInterceptIntent(any(Intent.class));
     }
 
     @Test
+    public void canActivityBeLaunched_resultExpected_noIntentSenderInCallback() {
+        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("testing"));
+
+        GenericWindowPolicyController gwpc = createGwpc();
+        gwpc.setDisplayId(DISPLAY_ID, /* isMirrorDisplay= */ false);
+        ActivityInfo activityInfo = getActivityInfo(
+                NONBLOCKED_APP_PACKAGE_NAME,
+                NONBLOCKED_APP_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ false,
+                /* targetDisplayCategory */ null);
+
+        IntentSender intentSender = new IntentSender(new Binder());
+        assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID, /* isNewTask= */false,
+                /* isResultExpected = */ true, /* intentSender= */ () -> intentSender))
+                .isFalse();
+
+        verify(mActivityBlockedCallback, timeout(TIMEOUT_MILLIS))
+                .onActivityBlocked(DISPLAY_ID, activityInfo, /* intentSender= */ null);
+    }
+
+    @Test
     public void onTopActivitychanged_null_noCallback() {
         GenericWindowPolicyController gwpc = createGwpc();
         gwpc.setDisplayId(DISPLAY_ID, /* isMirrorDisplay= */ false);
@@ -659,7 +686,8 @@
 
         verify(mSecureWindowCallback, after(TIMEOUT_MILLIS).never())
                 .onSecureWindowShown(DISPLAY_ID, activityInfo.applicationInfo.uid);
-        verify(mActivityBlockedCallback, never()).onActivityBlocked(DISPLAY_ID, activityInfo);
+        verify(mActivityBlockedCallback, never())
+                .onActivityBlocked(eq(DISPLAY_ID), eq(activityInfo), any());
     }
 
     @Test
@@ -678,7 +706,7 @@
         verify(mSecureWindowCallback, timeout(TIMEOUT_MILLIS)).onSecureWindowShown(DISPLAY_ID,
                 activityInfo.applicationInfo.uid);
         verify(mActivityBlockedCallback, after(TIMEOUT_MILLIS).never())
-                .onActivityBlocked(DISPLAY_ID, activityInfo);
+                .onActivityBlocked(eq(DISPLAY_ID), eq(activityInfo), any());
     }
 
     @Test
@@ -697,7 +725,8 @@
 
         verify(mSecureWindowCallback, after(TIMEOUT_MILLIS).never())
                 .onSecureWindowShown(DISPLAY_ID, activityInfo.applicationInfo.uid);
-        verify(mActivityBlockedCallback, never()).onActivityBlocked(DISPLAY_ID, activityInfo);
+        verify(mActivityBlockedCallback, never())
+                .onActivityBlocked(eq(DISPLAY_ID), eq(activityInfo), any());
     }
 
     @Test
@@ -911,11 +940,12 @@
 
     private void assertActivityCanBeLaunched(GenericWindowPolicyController gwpc, int fromDisplay,
             boolean isNewTask, int windowingMode, ActivityInfo activityInfo) {
+        IntentSender intentSender = new IntentSender(new Binder());
         assertThat(gwpc.canActivityBeLaunched(activityInfo, null, windowingMode, fromDisplay,
-                isNewTask)).isTrue();
+                isNewTask, /* isResultExpected= */ false, () -> intentSender)).isTrue();
 
         verify(mActivityBlockedCallback, after(TIMEOUT_MILLIS).never())
-                .onActivityBlocked(fromDisplay, activityInfo);
+                .onActivityBlocked(fromDisplay, activityInfo, intentSender);
         verify(mIntentListenerCallback, never()).shouldInterceptIntent(any(Intent.class));
     }
 
@@ -927,23 +957,26 @@
 
     private void assertActivityIsBlocked(GenericWindowPolicyController gwpc, int fromDisplay,
             boolean isNewTask, int windowingMode, ActivityInfo activityInfo) {
+        IntentSender intentSender = new IntentSender(new Binder());
         assertThat(gwpc.canActivityBeLaunched(activityInfo, null, windowingMode, fromDisplay,
-                isNewTask)).isFalse();
+                isNewTask, /* isResultExpected= */ false, () -> intentSender)).isFalse();
 
         verify(mActivityBlockedCallback, timeout(TIMEOUT_MILLIS))
-                .onActivityBlocked(fromDisplay, activityInfo);
+                .onActivityBlocked(fromDisplay, activityInfo, intentSender);
         verify(mIntentListenerCallback, after(TIMEOUT_MILLIS).never())
                 .shouldInterceptIntent(any(Intent.class));
     }
 
     private void assertNoActivityLaunched(GenericWindowPolicyController gwpc, int fromDisplay,
             ActivityInfo activityInfo) {
+        IntentSender intentSender = new IntentSender(new Binder());
         assertThat(gwpc.canActivityBeLaunched(activityInfo, null,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID, true))
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID, /* isNewTask= */false,
+                /* isResultExpected= */ false, () -> intentSender))
                 .isFalse();
 
         verify(mActivityBlockedCallback, after(TIMEOUT_MILLIS).never())
-                .onActivityBlocked(fromDisplay, activityInfo);
+                .onActivityBlocked(eq(fromDisplay), eq(activityInfo), any());
         verify(mIntentListenerCallback, never()).shouldInterceptIntent(any(Intent.class));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 19712ea..c288212 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -314,7 +314,8 @@
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfo, mAssociationInfo.getDisplayName());
         gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /* isNewTask= */ false,
+                /* isResultExpected = */ false, /* intentSender= */ null);
         return blockedAppIntent;
     }
 
@@ -1522,7 +1523,8 @@
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfo, mAssociationInfo.getDisplayName());
         gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /* isNewTask= */ false,
+                /* isResultExpected = */ false, /* intentSender= */ null);
 
         verify(mContext, never()).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1543,7 +1545,8 @@
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfo, mAssociationInfo.getDisplayName());
         gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /* isNewTask= */ false,
+                /* isResultExpected = */ false, /* intentSender= */ null);
 
         verify(mContext).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1564,7 +1567,8 @@
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfo, mAssociationInfo.getDisplayName());
         gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /* isNewTask= */ false,
+                /* isResultExpected = */ false, /* intentSender= */ null);
 
         verify(mContext, never()).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1585,7 +1589,8 @@
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfo, mAssociationInfo.getDisplayName());
         gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /* isNewTask= */ false,
+                /* isResultExpected = */ false, /* intentSender= */ null);
 
         verify(mContext).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1606,7 +1611,8 @@
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfo, mAssociationInfo.getDisplayName());
         gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /* isNewTask= */ false,
+                /* isResultExpected = */ false, /* intentSender= */ null);
 
         verify(mContext).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1627,7 +1633,8 @@
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfo, mAssociationInfo.getDisplayName());
         gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /* isNewTask= */ false,
+                /* isResultExpected = */ false, /* intentSender= */ null);
 
         verify(mContext).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1648,7 +1655,8 @@
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfo, mAssociationInfo.getDisplayName());
         gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /* isNewTask= */ false,
+                /* isResultExpected = */ false, /* intentSender= */ null);
 
         verify(mContext).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1669,7 +1677,8 @@
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfo, mAssociationInfo.getDisplayName());
         gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /* isNewTask= */ false,
+                /* isResultExpected = */ false, /* intentSender= */ null);
 
         verify(mContext).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1691,7 +1700,8 @@
                 /* displayOnRemoteDevices */ true,
                 /* targetDisplayCategory */ null);
         assertThat(gwpc.canActivityBeLaunched(activityInfo, null,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/ false))
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /* isNewTask= */ false,
+                /* isResultExpected = */ false, /* intentSender= */ null))
                 .isFalse();
         // Verify that BlockedAppStreamingActivity also doesn't launch for mirror displays.
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
@@ -1716,7 +1726,8 @@
                 /* displayOnRemoteDevices */ true,
                 /* targetDisplayCategory */ null);
         assertThat(gwpc.canActivityBeLaunched(activityInfo, null,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/ false))
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /* isNewTask= */ false,
+                /* isResultExpected = */ false, /* intentSender= */ null))
                 .isTrue();
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfo, mAssociationInfo.getDisplayName());
@@ -1768,7 +1779,8 @@
                 /* displayOnRemoteDevices */ true,
                 /* targetDisplayCategory */ null);
         assertThat(gwpc.canActivityBeLaunched(activityInfo, null,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /* isNewTask= */ false,
+                /* isResultExpected = */ false, /* intentSender= */ null))
                 .isTrue();
     }
 
@@ -1784,7 +1796,8 @@
                 /* displayOnRemoteDevices */ true,
                 /* targetDisplayCategory */ null);
         assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /* isNewTask= */ false,
+                /* isResultExpected = */ false, /* intentSender= */ null))
                 .isTrue();
     }
 
@@ -1815,7 +1828,8 @@
         // register interceptor and intercept intent
         mDeviceImpl.registerIntentInterceptor(interceptor, intentFilter);
         assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /* isNewTask= */ false,
+                /* isResultExpected = */ false, /* intentSender= */ null))
                 .isFalse();
         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
         verify(interceptor).onIntentIntercepted(intentCaptor.capture());
@@ -1827,7 +1841,8 @@
         // unregister interceptor and launch activity
         mDeviceImpl.unregisterIntentInterceptor(interceptor);
         assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /* isNewTask= */ false,
+                /* isResultExpected = */ false, /* intentSender= */ null))
                 .isTrue();
     }
 
@@ -1858,7 +1873,8 @@
         mDeviceImpl.registerIntentInterceptor(interceptor, intentFilter);
 
         assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
-                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /* isNewTask= */ false,
+                /* isResultExpected = */ false, /* intentSender= */ null))
                 .isTrue();
     }
 
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 bb5887d..58f8eb2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
@@ -33,6 +33,7 @@
 import android.app.WindowConfiguration;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.os.Process;
 import android.util.ArraySet;
@@ -40,12 +41,14 @@
 import android.window.DisplayWindowPolicyController;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.util.Set;
+import java.util.function.Supplier;
 
 /**
  * Tests for the {@link DisplayWindowPolicyController} class.
@@ -224,7 +227,7 @@
         assertEquals(result, START_ABORTED);
     }
 
-    private class TestDisplayWindowPolicyController extends DisplayWindowPolicyController {
+    private static class TestDisplayWindowPolicyController extends DisplayWindowPolicyController {
 
         public ComponentName DISALLOWED_ACTIVITY =
                 new ComponentName("fake.package", "DisallowedActivity");
@@ -236,7 +239,8 @@
         @Override
         public boolean canActivityBeLaunched(@NonNull ActivityInfo activity, Intent intent,
                 @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId,
-                boolean isNewTask) {
+                boolean isNewTask, boolean isResultExpected,
+                @Nullable Supplier<IntentSender> intentSender) {
             return canContainActivity(activity, windowingMode, launchingFromDisplayId, isNewTask);
         }