diff --git a/core/api/current.txt b/core/api/current.txt
index 53dcd75cf59a11aeff3beebb8bb355220d674ea3..ca322a46a2734a7074c1e2337065c8c2a2ae0ebe 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -5279,10 +5279,28 @@ package android.app {
   }
 
   public class BroadcastOptions {
-    ctor public BroadcastOptions();
+    method public void clearDeferralPolicy();
+    method public void clearDeliveryGroupMatchingFilter();
+    method public void clearDeliveryGroupMatchingKey();
+    method public void clearDeliveryGroupPolicy();
+    method @NonNull public static android.app.BroadcastOptions fromBundle(@NonNull android.os.Bundle);
+    method public int getDeferralPolicy();
+    method @Nullable public android.content.IntentFilter getDeliveryGroupMatchingFilter();
+    method @Nullable public String getDeliveryGroupMatchingKey();
+    method public int getDeliveryGroupPolicy();
     method public boolean isShareIdentityEnabled();
+    method @NonNull public static android.app.BroadcastOptions makeBasic();
+    method @NonNull public android.app.BroadcastOptions setDeferralPolicy(int);
+    method @NonNull public android.app.BroadcastOptions setDeliveryGroupMatchingFilter(@NonNull android.content.IntentFilter);
+    method @NonNull public android.app.BroadcastOptions setDeliveryGroupMatchingKey(@NonNull String, @NonNull String);
+    method @NonNull public android.app.BroadcastOptions setDeliveryGroupPolicy(int);
     method @NonNull public android.app.BroadcastOptions setShareIdentityEnabled(boolean);
     method @NonNull public android.os.Bundle toBundle();
+    field public static final int DEFERRAL_POLICY_DEFAULT = 0; // 0x0
+    field public static final int DEFERRAL_POLICY_NONE = 1; // 0x1
+    field public static final int DEFERRAL_POLICY_UNTIL_ACTIVE = 2; // 0x2
+    field public static final int DELIVERY_GROUP_POLICY_ALL = 0; // 0x0
+    field public static final int DELIVERY_GROUP_POLICY_MOST_RECENT = 1; // 0x1
   }
 
   public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 05f31a5a8a86ac9044782774e4eb8845f5a19d2d..8f5505d483c7a778ede6a95ab0e869e0c89755b2 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -834,23 +834,13 @@ package android.app {
   }
 
   public class BroadcastOptions {
-    method public void clearDeliveryGroupMatchingFilter();
-    method public void clearDeliveryGroupMatchingKey();
-    method public void clearDeliveryGroupPolicy();
     method public void clearRequireCompatChange();
-    method @Nullable public android.content.IntentFilter getDeliveryGroupMatchingFilter();
-    method @Nullable public String getDeliveryGroupMatchingKey();
-    method public int getDeliveryGroupPolicy();
     method public int getPendingIntentBackgroundActivityStartMode();
-    method public boolean isDeferUntilActive();
+    method @Deprecated public boolean isDeferUntilActive();
     method @Deprecated public boolean isPendingIntentBackgroundActivityLaunchAllowed();
-    method @Deprecated @NonNull public static android.app.BroadcastOptions makeBasic();
     method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS) public void recordResponseEventWhileInBackground(@IntRange(from=0) long);
     method @RequiresPermission(android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND) public void setBackgroundActivityStartsAllowed(boolean);
-    method @NonNull public android.app.BroadcastOptions setDeferUntilActive(boolean);
-    method @NonNull public android.app.BroadcastOptions setDeliveryGroupMatchingFilter(@NonNull android.content.IntentFilter);
-    method @NonNull public android.app.BroadcastOptions setDeliveryGroupMatchingKey(@NonNull String, @NonNull String);
-    method @NonNull public android.app.BroadcastOptions setDeliveryGroupPolicy(int);
+    method @Deprecated @NonNull public android.app.BroadcastOptions setDeferUntilActive(boolean);
     method public void setDontSendToRestrictedApps(boolean);
     method @Deprecated public void setPendingIntentBackgroundActivityLaunchAllowed(boolean);
     method @NonNull public android.app.BroadcastOptions setPendingIntentBackgroundActivityStartMode(int);
@@ -859,8 +849,6 @@ package android.app {
     method public void setRequireNoneOfPermissions(@Nullable String[]);
     method @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppAllowlist(long, int, int, @Nullable String);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppWhitelistDuration(long);
-    field public static final int DELIVERY_GROUP_POLICY_ALL = 0; // 0x0
-    field public static final int DELIVERY_GROUP_POLICY_MOST_RECENT = 1; // 0x1
   }
 
   public class DownloadManager {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 777faa7fe5aa1adefb7c605d54fe8ecd46c57a2a..d2b97e4f52424626f40ef7e1eaaf6826dadf353f 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -269,6 +269,7 @@ package android.app {
   }
 
   public class BroadcastOptions extends android.app.ComponentOptions {
+    ctor public BroadcastOptions();
     ctor public BroadcastOptions(@NonNull android.os.Bundle);
     method @Deprecated public int getMaxManifestReceiverApiLevel();
     method public long getTemporaryAppAllowlistDuration();
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index f48181b958927315c0863b2a1f5b90dbcc7edeca..481f671d3350d3c139cdeea511e6c98a50af2ea1 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -64,6 +64,7 @@ public class BroadcastOptions extends ComponentOptions {
     private @Nullable String mDeliveryGroupMatchingKey;
     private @Nullable BundleMerger mDeliveryGroupExtrasMerger;
     private @Nullable IntentFilter mDeliveryGroupMatchingFilter;
+    private @DeferralPolicy int mDeferralPolicy;
 
     /** @hide */
     @IntDef(flag = true, prefix = { "FLAG_" }, value = {
@@ -71,8 +72,8 @@ public class BroadcastOptions extends ComponentOptions {
             FLAG_ALLOW_BACKGROUND_ACTIVITY_STARTS,
             FLAG_REQUIRE_COMPAT_CHANGE_ENABLED,
             FLAG_IS_ALARM_BROADCAST,
-            FLAG_IS_DEFER_UNTIL_ACTIVE,
             FLAG_SHARE_IDENTITY,
+            FLAG_INTERACTIVE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Flags {}
@@ -81,8 +82,8 @@ public class BroadcastOptions extends ComponentOptions {
     private static final int FLAG_ALLOW_BACKGROUND_ACTIVITY_STARTS = 1 << 1;
     private static final int FLAG_REQUIRE_COMPAT_CHANGE_ENABLED = 1 << 2;
     private static final int FLAG_IS_ALARM_BROADCAST = 1 << 3;
-    private static final int FLAG_IS_DEFER_UNTIL_ACTIVE = 1 << 4;
-    private static final int FLAG_SHARE_IDENTITY = 1 << 5;
+    private static final int FLAG_SHARE_IDENTITY = 1 << 4;
+    private static final int FLAG_INTERACTIVE = 1 << 5;
 
     /**
      * Change ID which is invalid.
@@ -212,12 +213,18 @@ public class BroadcastOptions extends ComponentOptions {
     private static final String KEY_DELIVERY_GROUP_MATCHING_FILTER =
             "android:broadcast.deliveryGroupMatchingFilter";
 
+    /**
+     * Corresponds to {@link #setDeferralPolicy(int)}
+     */
+    private static final String KEY_DEFERRAL_POLICY =
+            "android:broadcast.deferralPolicy";
+
     /**
      * The list of delivery group policies which specify how multiple broadcasts belonging to
      * the same delivery group has to be handled.
      * @hide
      */
-    @IntDef(flag = true, prefix = { "DELIVERY_GROUP_POLICY_" }, value = {
+    @IntDef(prefix = { "DELIVERY_GROUP_POLICY_" }, value = {
             DELIVERY_GROUP_POLICY_ALL,
             DELIVERY_GROUP_POLICY_MOST_RECENT,
             DELIVERY_GROUP_POLICY_MERGED,
@@ -228,19 +235,13 @@ public class BroadcastOptions extends ComponentOptions {
     /**
      * Delivery group policy that indicates that all the broadcasts in the delivery group
      * need to be delivered as is.
-     *
-     * @hide
      */
-    @SystemApi
     public static final int DELIVERY_GROUP_POLICY_ALL = 0;
 
     /**
      * Delivery group policy that indicates that only the most recent broadcast in the delivery
      * group need to be delivered and the rest can be dropped.
-     *
-     * @hide
      */
-    @SystemApi
     public static final int DELIVERY_GROUP_POLICY_MOST_RECENT = 1;
 
     /**
@@ -251,24 +252,62 @@ public class BroadcastOptions extends ComponentOptions {
      */
     public static final int DELIVERY_GROUP_POLICY_MERGED = 2;
 
+    /** {@hide} */
+    @IntDef(prefix = { "DEFERRAL_POLICY_" }, value = {
+            DEFERRAL_POLICY_DEFAULT,
+            DEFERRAL_POLICY_NONE,
+            DEFERRAL_POLICY_UNTIL_ACTIVE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DeferralPolicy {}
+
+    /**
+     * Deferral policy that indicates no desire has been expressed, and that the
+     * system should use a reasonable default behavior.
+     */
+    public static final int DEFERRAL_POLICY_DEFAULT = 0;
+
+    /**
+     * Deferral policy that indicates a strong desire that no receiver of this
+     * broadcast should be deferred.
+     */
+    public static final int DEFERRAL_POLICY_NONE = 1;
+
+    /**
+     * Deferral policy that indicates a strong desire that each receiver of this
+     * broadcast should be deferred until that receiver's process is in an
+     * active (non-cached) state. Whether an app's process state is considered
+     * active is independent of its standby bucket.
+     * <p>
+     * This policy only applies to runtime registered receivers of a broadcast,
+     * and does not apply to ordered broadcasts, alarm broadcasts, interactive
+     * broadcasts, or manifest broadcasts.
+     * <p>
+     * This policy means that a runtime registered receiver will not typically
+     * execute until that receiver's process is brought to an active state by
+     * some other action, such as a job, alarm, or service binding. As a result,
+     * the receiver may be delayed indefinitely.
+     * <p>
+     * When this policy is set on an unordered broadcast with a completion
+     * callback, the completion callback will run once all eligible processes
+     * have finished receiving the broadcast. Processes in inactive process
+     * state are not considered eligible and may not receive the broadcast prior
+     * to the completion callback.
+     */
+    public static final int DEFERRAL_POLICY_UNTIL_ACTIVE = 2;
+
     /**
      * Creates a basic {@link BroadcastOptions} with no options initially set.
      *
      * @return an instance of {@code BroadcastOptions} against which options can be set
-     *
-     * @deprecated Use {@link BroadcastOptions#BroadcastOptions()} instead.
-     * @hide
      */
-    @Deprecated
-    @SystemApi
     public static @NonNull BroadcastOptions makeBasic() {
         BroadcastOptions opts = new BroadcastOptions();
         return opts;
     }
 
-    /**
-     * Creates a new {@code BroadcastOptions} with no options initially set.
-     */
+    /** @hide */
+    @TestApi
     public BroadcastOptions() {
         super();
         resetTemporaryAppAllowlist();
@@ -303,6 +342,7 @@ public class BroadcastOptions extends ComponentOptions {
                 BundleMerger.class);
         mDeliveryGroupMatchingFilter = opts.getParcelable(KEY_DELIVERY_GROUP_MATCHING_FILTER,
                 IntentFilter.class);
+        mDeferralPolicy = opts.getInt(KEY_DEFERRAL_POLICY, DEFERRAL_POLICY_DEFAULT);
     }
 
     /**
@@ -728,60 +768,56 @@ public class BroadcastOptions extends ComponentOptions {
         return mIdForResponseEvent;
     }
 
-    /**
-     * Sets whether the broadcast should not run until the process is in an active process state
-     * (ie, a process exists for the app and the app is not in a cached process state).
-     *
-     * Whether an app's process state is considered active is independent of its standby bucket.
-     *
-     * A broadcast that is deferred until the process is active will not execute until the process
-     * is brought to an active state by some other action, like a job, alarm, or service binding. As
-     * a result, the broadcast may be delayed indefinitely. This deferral only applies to runtime
-     * registered receivers of a broadcast. Any manifest receivers will run immediately, similar to
-     * how a manifest receiver would start a new process in order to run a broadcast receiver.
-     *
-     * Ordered broadcasts, alarm broadcasts, interactive broadcasts, and manifest broadcasts are
-     * never deferred.
-     *
-     * Unordered broadcasts and unordered broadcasts with completion callbacks may be
-     * deferred. Completion callbacks for broadcasts deferred until active are
-     * best-effort. Completion callbacks will run when all eligible processes have finished
-     * executing the broadcast. Processes in inactive process states that defer the broadcast are
-     * not considered eligible and may not execute the broadcast prior to the completion callback.
-     *
-     * @hide
-     */
+    /** {@hide} */
     @SystemApi
+    @Deprecated
+    // STOPSHIP: remove entirely after this API change lands in AOSP
     public @NonNull BroadcastOptions setDeferUntilActive(boolean shouldDefer) {
         if (shouldDefer) {
-            mFlags |= FLAG_IS_DEFER_UNTIL_ACTIVE;
+            setDeferralPolicy(DEFERRAL_POLICY_UNTIL_ACTIVE);
         } else {
-            mFlags &= ~FLAG_IS_DEFER_UNTIL_ACTIVE;
+            setDeferralPolicy(DEFERRAL_POLICY_NONE);
         }
         return this;
     }
 
-    /**
-     * Returns if this broadcast should not run until the process is in an active process state.
-     *
-     * @return {@code true} if this broadcast should not run until the process is in an active
-     *                      process state. Otherwise, {@code false}.
-     * @see #setDeferUntilActive(boolean)
-     *
-     * @hide
-     */
+    /** {@hide} */
     @SystemApi
+    @Deprecated
+    // STOPSHIP: remove entirely after this API change lands in AOSP
     public boolean isDeferUntilActive() {
-        return (mFlags & FLAG_IS_DEFER_UNTIL_ACTIVE) != 0;
+        return (mDeferralPolicy == DEFERRAL_POLICY_UNTIL_ACTIVE);
+    }
+
+    /**
+     * Sets deferral policy for this broadcast that specifies how this broadcast
+     * can be deferred for delivery at some future point.
+     */
+    public @NonNull BroadcastOptions setDeferralPolicy(@DeferralPolicy int deferralPolicy) {
+        mDeferralPolicy = deferralPolicy;
+        return this;
+    }
+
+    /**
+     * Gets deferral policy for this broadcast that specifies how this broadcast
+     * can be deferred for delivery at some future point.
+     */
+    public @DeferralPolicy int getDeferralPolicy() {
+        return mDeferralPolicy;
+    }
+
+    /**
+     * Clears any deferral policy for this broadcast that specifies how this
+     * broadcast can be deferred for delivery at some future point.
+     */
+    public void clearDeferralPolicy() {
+        mDeferralPolicy = DEFERRAL_POLICY_DEFAULT;
     }
 
     /**
      * Set delivery group policy for this broadcast to specify how multiple broadcasts belonging to
      * the same delivery group has to be handled.
-     *
-     * @hide
      */
-    @SystemApi
     @NonNull
     public BroadcastOptions setDeliveryGroupPolicy(@DeliveryGroupPolicy int policy) {
         mDeliveryGroupPolicy = policy;
@@ -791,10 +827,7 @@ public class BroadcastOptions extends ComponentOptions {
     /**
      * Get the delivery group policy for this broadcast that specifies how multiple broadcasts
      * belonging to the same delivery group has to be handled.
-     *
-     * @hide
      */
-    @SystemApi
     public @DeliveryGroupPolicy int getDeliveryGroupPolicy() {
         return mDeliveryGroupPolicy;
     }
@@ -803,10 +836,7 @@ public class BroadcastOptions extends ComponentOptions {
      * Clears any previously set delivery group policies using
      * {@link #setDeliveryGroupMatchingKey(String, String)} and resets the delivery group policy to
      * the default value ({@link #DELIVERY_GROUP_POLICY_ALL}).
-     *
-     * @hide
      */
-    @SystemApi
     public void clearDeliveryGroupPolicy() {
         mDeliveryGroupPolicy = DELIVERY_GROUP_POLICY_ALL;
     }
@@ -821,10 +851,7 @@ public class BroadcastOptions extends ComponentOptions {
      * <p> If neither matching key using this API nor matching filter using
      * {@link #setDeliveryGroupMatchingFilter(IntentFilter)} is specified, then by default
      * {@link Intent#filterEquals(Intent)} will be used to identify the delivery group.
-     *
-     * @hide
      */
-    @SystemApi
     @NonNull
     public BroadcastOptions setDeliveryGroupMatchingKey(@NonNull String namespace,
             @NonNull String key) {
@@ -842,9 +869,7 @@ public class BroadcastOptions extends ComponentOptions {
      *
      * @return the delivery group namespace and key that was previously set using
      *         {@link #setDeliveryGroupMatchingKey(String, String)}, concatenated with a {@code :}.
-     * @hide
      */
-    @SystemApi
     @Nullable
     public String getDeliveryGroupMatchingKey() {
         return mDeliveryGroupMatchingKey;
@@ -853,10 +878,7 @@ public class BroadcastOptions extends ComponentOptions {
     /**
      * Clears the namespace and key that was previously set using
      * {@link #setDeliveryGroupMatchingKey(String, String)}.
-     *
-     * @hide
      */
-    @SystemApi
     public void clearDeliveryGroupMatchingKey() {
         mDeliveryGroupMatchingKey = null;
     }
@@ -871,10 +893,7 @@ public class BroadcastOptions extends ComponentOptions {
      * <p> If neither matching key using {@link #setDeliveryGroupMatchingKey(String, String)} nor
      * matching filter using this API is specified, then by default
      * {@link Intent#filterEquals(Intent)} will be used to identify the delivery group.
-     *
-     * @hide
      */
-    @SystemApi
     @NonNull
     public BroadcastOptions setDeliveryGroupMatchingFilter(@NonNull IntentFilter matchingFilter) {
         mDeliveryGroupMatchingFilter = Objects.requireNonNull(matchingFilter);
@@ -887,9 +906,7 @@ public class BroadcastOptions extends ComponentOptions {
      *
      * @return the {@link IntentFilter} object that was previously set using
      *         {@link #setDeliveryGroupMatchingFilter(IntentFilter)}.
-     * @hide
      */
-    @SystemApi
     @Nullable
     public IntentFilter getDeliveryGroupMatchingFilter() {
         return mDeliveryGroupMatchingFilter;
@@ -898,10 +915,7 @@ public class BroadcastOptions extends ComponentOptions {
     /**
      * Clears the {@link IntentFilter} object that was previously set using
      * {@link #setDeliveryGroupMatchingFilter(IntentFilter)}.
-     *
-     * @hide
      */
-    @SystemApi
     public void clearDeliveryGroupMatchingFilter() {
         mDeliveryGroupMatchingFilter = null;
     }
@@ -943,6 +957,36 @@ public class BroadcastOptions extends ComponentOptions {
         mDeliveryGroupExtrasMerger = null;
     }
 
+    /**
+     * Sets whether the broadcast should be considered as having originated from
+     * some direct interaction by the user such as a notification tap or button
+     * press. This signal is used internally to ensure the broadcast is
+     * delivered quickly with low latency.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.BROADCAST_OPTION_INTERACTIVE)
+    public @NonNull BroadcastOptions setInteractive(boolean interactive) {
+        if (interactive) {
+            mFlags |= FLAG_INTERACTIVE;
+        } else {
+            mFlags &= ~FLAG_INTERACTIVE;
+        }
+        return this;
+    }
+
+    /**
+     * Returns whether the broadcast should be considered as having originated
+     * from some direct interaction by the user such as a notification tap or
+     * button press.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.BROADCAST_OPTION_INTERACTIVE)
+    public boolean isInteractive() {
+        return (mFlags & FLAG_INTERACTIVE) != 0;
+    }
+
     /**
      * Set PendingIntent activity is allowed to be started in the background if the caller
      * can start background activities.
@@ -1064,11 +1108,22 @@ public class BroadcastOptions extends ComponentOptions {
         if (mDeliveryGroupMatchingFilter != null) {
             b.putParcelable(KEY_DELIVERY_GROUP_MATCHING_FILTER, mDeliveryGroupMatchingFilter);
         }
-        return b.isEmpty() ? null : b;
+        if (mDeferralPolicy != DEFERRAL_POLICY_DEFAULT) {
+            b.putInt(KEY_DEFERRAL_POLICY, mDeferralPolicy);
+        }
+        return b;
     }
 
-    /** @hide */
-    public static @Nullable BroadcastOptions fromBundle(@Nullable Bundle options) {
+    /**
+     * Returns a {@link BroadcastOptions} parsed from the given {@link Bundle},
+     * typically generated from {@link #toBundle()}.
+     */
+    public static @NonNull BroadcastOptions fromBundle(@NonNull Bundle options) {
+        return new BroadcastOptions(options);
+    }
+
+    /** {@hide} */
+    public static @Nullable BroadcastOptions fromBundleNullable(@Nullable Bundle options) {
         return (options != null) ? new BroadcastOptions(options) : null;
     }
 }
diff --git a/core/java/android/app/ComponentOptions.java b/core/java/android/app/ComponentOptions.java
index ceb9e9000a3190e57004e609262f33a6f3e96395..e0e2855252081189d3dab9ce293c98b3d4b204d7 100644
--- a/core/java/android/app/ComponentOptions.java
+++ b/core/java/android/app/ComponentOptions.java
@@ -19,7 +19,6 @@ package android.app;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
 import android.annotation.TestApi;
 import android.os.Bundle;
@@ -53,15 +52,8 @@ public class ComponentOptions {
     public static final String KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION =
             "android.pendingIntent.backgroundActivityAllowedByPermission";
 
-    /**
-     * Corresponds to {@link #setInteractive(boolean)}
-     * @hide
-     */
-    private static final String KEY_INTERACTIVE = "android:component.isInteractive";
-
     private @Nullable Boolean mPendingIntentBalAllowed = null;
     private boolean mPendingIntentBalAllowedByPermission = false;
-    private boolean mIsInteractive = false;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -106,29 +98,6 @@ public class ComponentOptions {
         setPendingIntentBackgroundActivityLaunchAllowedByPermission(
                 opts.getBoolean(
                         KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION, false));
-        mIsInteractive = opts.getBoolean(KEY_INTERACTIVE, false);
-    }
-
-    /**
-     * When set, a broadcast will be understood as having originated from
-     * some direct interaction by the user such as a notification tap or button
-     * press.  Only the OS itself may use this option.
-     * @hide
-     * @param interactive
-     * @see #isInteractive()
-     */
-    @RequiresPermission(android.Manifest.permission.COMPONENT_OPTION_INTERACTIVE)
-    public void setInteractive(boolean interactive) {
-        mIsInteractive = interactive;
-    }
-
-    /**
-     * Did this PendingIntent send originate with a direct user interaction?
-     * @return true if this is the result of an interaction, false otherwise
-     * @hide
-     */
-    public boolean isInteractive() {
-        return mIsInteractive;
     }
 
     /**
@@ -232,9 +201,6 @@ public class ComponentOptions {
             b.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION,
                     mPendingIntentBalAllowedByPermission);
         }
-        if (mIsInteractive) {
-            b.putBoolean(KEY_INTERACTIVE, true);
-        }
         return b;
     }
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b73623031dc1a1d4c427caed227462a7f2b62a2b..b52534e35f5aca84862628fee38b7253737df07f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3770,10 +3770,9 @@
     <permission android:name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"
                 android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier|role"/>
 
-    <!-- Allows an application to hint that a component lifecycle operation such as sending
-         a broadcast is associated with an "interactive" usage scenario.
+    <!-- Allows an application to request interactive options when sending a broadcast.
          @hide -->
-    <permission android:name="android.permission.COMPONENT_OPTION_INTERACTIVE"
+    <permission android:name="android.permission.BROADCAST_OPTION_INTERACTIVE"
                 android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Must be required by activities that handle the intent action
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index 116aa4899b2eabb0f99fdefe5eea1776806d235a..fe639ffb1cc6d1e6f94d3ba799f4d4ccf8f9e787 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -24,7 +24,7 @@
         <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
         <permission name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"/>
         <permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/>
-        <permission name="android.permission.COMPONENT_OPTION_INTERACTIVE"/>
+        <permission name="android.permission.BROADCAST_OPTION_INTERACTIVE"/>
         <permission name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"/>
         <permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
         <permission name="android.permission.CONTROL_VPN"/>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 71f438eb0455d12f9cd2a609cffa35f1b18d85ba..6176c61d363abeed5027393107eee4bd508c104e 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -181,8 +181,8 @@
     <!-- Doze mode temp whitelisting for notification dispatching. -->
     <uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" />
 
-    <!-- Tag user-initiated PendingIntent invocations as "interactive" when appropriate -->
-    <uses-permission android:name="android.permission.COMPONENT_OPTION_INTERACTIVE" />
+    <!-- Adjust delivery policies for broadcast intents -->
+    <uses-permission android:name="android.permission.BROADCAST_OPTION_INTERACTIVE" />
 
     <!-- Listen for keyboard attachment / detachment -->
     <uses-permission android:name="android.permission.TABLET_MODE" />
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 9e62817fcc672c68f236c85a737395d3faee111a..55fa47951fe1a37c91c798fad24cc8faebea2a91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -122,7 +122,6 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn
         options.setLaunchDisplayId(displayId);
         options.setCallerDisplayId(displayId);
         options.setPendingIntentBackgroundActivityLaunchAllowed(true);
-        options.setInteractive(true);
         return options.toBundle();
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1960c330cc7319ac41d720aece0b4e2b2ceb83d6..13f3efe53b2e81d751cf816759bf02d89480f9ac 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -14285,7 +14285,8 @@ public class ActivityManagerService extends IActivityManager.Stub
     // Apply permission policy around the use of specific broadcast options
     void enforceBroadcastOptionPermissionsInternal(
             @Nullable Bundle options, int callingUid) {
-        enforceBroadcastOptionPermissionsInternal(BroadcastOptions.fromBundle(options), callingUid);
+        enforceBroadcastOptionPermissionsInternal(BroadcastOptions.fromBundleNullable(options),
+                callingUid);
     }
 
     void enforceBroadcastOptionPermissionsInternal(
@@ -14301,7 +14302,7 @@ public class ActivityManagerService extends IActivityManager.Stub
             }
             if (options.isInteractive()) {
                 enforceCallingPermission(
-                        android.Manifest.permission.COMPONENT_OPTION_INTERACTIVE,
+                        android.Manifest.permission.BROADCAST_OPTION_INTERACTIVE,
                         "setInteractive");
             }
         }
@@ -14338,9 +14339,9 @@ public class ActivityManagerService extends IActivityManager.Stub
         final int res = broadcastIntentLockedTraced(callerApp, callerPackage, callerFeatureId,
                 intent, resolvedType, resultToApp, resultTo, resultCode, resultData, resultExtras,
                 requiredPermissions, excludedPermissions, excludedPackages, appOp,
-                BroadcastOptions.fromBundle(bOptions), ordered, sticky, callingPid, callingUid,
-                realCallingUid, realCallingPid, userId, backgroundStartPrivileges,
-                broadcastAllowList, filterExtrasForReceiver);
+                BroadcastOptions.fromBundleNullable(bOptions), ordered, sticky,
+                callingPid, callingUid, realCallingUid, realCallingPid, userId,
+                backgroundStartPrivileges, broadcastAllowList, filterExtrasForReceiver);
         BroadcastQueue.traceEnd(cookie);
         return res;
     }