Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 89ea9b58 authored by Christopher Tate's avatar Christopher Tate
Browse files

Move "interactive" from BroadcastOptions to ComponentOptions

Some parts of the system interact with PendingIntent options via
ActivityOptions even when the underlying PendingIntent might be a
broadcast, so we need accommodate that pattern.

Bug: 254290593
Test: atest FrameworksMockingServicesTests:BroadcastQueueModernImplTest
Test: atest FrameworksMockingServicesTests:BroadcastQueueTest
Test: atest android.app.activity.BroadcastTest#testBroadcastOption_interactive
Change-Id: Ia1e5e2c337d9a4fe557202e794cae23dfa64911b
parent 560f3927
Loading
Loading
Loading
Loading
+0 −34
Original line number Original line Diff line number Diff line
@@ -63,7 +63,6 @@ public class BroadcastOptions extends ComponentOptions {
    private long mRequireCompatChangeId = CHANGE_INVALID;
    private long mRequireCompatChangeId = CHANGE_INVALID;
    private boolean mRequireCompatChangeEnabled = true;
    private boolean mRequireCompatChangeEnabled = true;
    private boolean mIsAlarmBroadcast = false;
    private boolean mIsAlarmBroadcast = false;
    private boolean mIsInteractiveBroadcast = false;
    private long mIdForResponseEvent;
    private long mIdForResponseEvent;
    private @Nullable IntentFilter mRemoveMatchingFilter;
    private @Nullable IntentFilter mRemoveMatchingFilter;
    private @DeliveryGroupPolicy int mDeliveryGroupPolicy;
    private @DeliveryGroupPolicy int mDeliveryGroupPolicy;
@@ -170,13 +169,6 @@ public class BroadcastOptions extends ComponentOptions {
    public static final String KEY_ALARM_BROADCAST =
    public static final String KEY_ALARM_BROADCAST =
            "android:broadcast.is_alarm";
            "android:broadcast.is_alarm";


    /**
     * Corresponds to {@link #setInteractiveBroadcast(boolean)}
     * @hide
     */
    public static final String KEY_INTERACTIVE_BROADCAST =
            "android:broadcast.is_interactive";

    /**
    /**
     * @hide
     * @hide
     * @deprecated Use {@link android.os.PowerExemptionManager#
     * @deprecated Use {@link android.os.PowerExemptionManager#
@@ -308,7 +300,6 @@ public class BroadcastOptions extends ComponentOptions {
        mRequireCompatChangeEnabled = opts.getBoolean(KEY_REQUIRE_COMPAT_CHANGE_ENABLED, true);
        mRequireCompatChangeEnabled = opts.getBoolean(KEY_REQUIRE_COMPAT_CHANGE_ENABLED, true);
        mIdForResponseEvent = opts.getLong(KEY_ID_FOR_RESPONSE_EVENT);
        mIdForResponseEvent = opts.getLong(KEY_ID_FOR_RESPONSE_EVENT);
        mIsAlarmBroadcast = opts.getBoolean(KEY_ALARM_BROADCAST, false);
        mIsAlarmBroadcast = opts.getBoolean(KEY_ALARM_BROADCAST, false);
        mIsInteractiveBroadcast = opts.getBoolean(KEY_INTERACTIVE_BROADCAST, false);
        mRemoveMatchingFilter = opts.getParcelable(KEY_REMOVE_MATCHING_FILTER,
        mRemoveMatchingFilter = opts.getParcelable(KEY_REMOVE_MATCHING_FILTER,
                IntentFilter.class);
                IntentFilter.class);
        mDeliveryGroupPolicy = opts.getInt(KEY_DELIVERY_GROUP_POLICY,
        mDeliveryGroupPolicy = opts.getInt(KEY_DELIVERY_GROUP_POLICY,
@@ -628,28 +619,6 @@ public class BroadcastOptions extends ComponentOptions {
        return mIsAlarmBroadcast;
        return mIsAlarmBroadcast;
    }
    }


    /**
     * When set, this 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 broadcastIsInteractive
     * @see #isInteractiveBroadcast()
     */
    @RequiresPermission(android.Manifest.permission.BROADCAST_OPTION_INTERACTIVE)
    public void setInteractiveBroadcast(boolean broadcastIsInteractive) {
        mIsInteractiveBroadcast = broadcastIsInteractive;
    }

    /**
     * Did this broadcast originate with a direct user interaction?
     * @return true if this broadcast is the result of an interaction, false otherwise
     * @hide
     */
    public boolean isInteractiveBroadcast() {
        return mIsInteractiveBroadcast;
    }

    /**
    /**
     * Did this broadcast originate from a push message from the server?
     * Did this broadcast originate from a push message from the server?
     *
     *
@@ -837,9 +806,6 @@ public class BroadcastOptions extends ComponentOptions {
        if (mIsAlarmBroadcast) {
        if (mIsAlarmBroadcast) {
            b.putBoolean(KEY_ALARM_BROADCAST, true);
            b.putBoolean(KEY_ALARM_BROADCAST, true);
        }
        }
        if (mIsInteractiveBroadcast) {
            b.putBoolean(KEY_INTERACTIVE_BROADCAST, true);
        }
        if (mMinManifestReceiverApiLevel != 0) {
        if (mMinManifestReceiverApiLevel != 0) {
            b.putInt(KEY_MIN_MANIFEST_RECEIVER_API_LEVEL, mMinManifestReceiverApiLevel);
            b.putInt(KEY_MIN_MANIFEST_RECEIVER_API_LEVEL, mMinManifestReceiverApiLevel);
        }
        }
+34 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package android.app;
package android.app;


import android.annotation.RequiresPermission;
import android.os.Bundle;
import android.os.Bundle;


/**
/**
@@ -45,8 +46,15 @@ public class ComponentOptions {
    public static final String KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION =
    public static final String KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION =
            "android.pendingIntent.backgroundActivityAllowedByPermission";
            "android.pendingIntent.backgroundActivityAllowedByPermission";


    /**
     * Corresponds to {@link #setInteractive(boolean)}
     * @hide
     */
    public static final String KEY_INTERACTIVE = "android:component.isInteractive";

    private boolean mPendingIntentBalAllowed = PENDING_INTENT_BAL_ALLOWED_DEFAULT;
    private boolean mPendingIntentBalAllowed = PENDING_INTENT_BAL_ALLOWED_DEFAULT;
    private boolean mPendingIntentBalAllowedByPermission = false;
    private boolean mPendingIntentBalAllowedByPermission = false;
    private boolean mIsInteractive = false;


    ComponentOptions() {
    ComponentOptions() {
    }
    }
@@ -61,6 +69,29 @@ public class ComponentOptions {
        setPendingIntentBackgroundActivityLaunchAllowedByPermission(
        setPendingIntentBackgroundActivityLaunchAllowedByPermission(
                opts.getBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION,
                opts.getBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION,
                        false));
                        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;
    }
    }


    /**
    /**
@@ -103,6 +134,9 @@ public class ComponentOptions {
            b.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION,
            b.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION,
                    mPendingIntentBalAllowedByPermission);
                    mPendingIntentBalAllowedByPermission);
        }
        }
        if (mIsInteractive) {
            b.putBoolean(KEY_INTERACTIVE, true);
        }
        return b;
        return b;
    }
    }
}
}
+3 −3
Original line number Original line Diff line number Diff line
@@ -3177,10 +3177,10 @@
    <permission android:name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"
    <permission android:name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"
                android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier|role"/>
                android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier|role"/>


    <!-- Allows an application to hint that a broadcast is associated with an
    <!-- Allows an application to hint that a component lifecycle operation such as sending
         "interactive" usage scenario
         a broadcast is associated with an "interactive" usage scenario.
         @hide -->
         @hide -->
    <permission android:name="android.permission.BROADCAST_OPTION_INTERACTIVE"
    <permission android:name="android.permission.COMPONENT_OPTION_INTERACTIVE"
                android:protectionLevel="signature|privileged" />
                android:protectionLevel="signature|privileged" />


    <!-- @SystemApi Must be required by activities that handle the intent action
    <!-- @SystemApi Must be required by activities that handle the intent action
+6 −6
Original line number Original line Diff line number Diff line
@@ -541,35 +541,35 @@ public class BroadcastTest extends ActivityTestsBase {


    public void testBroadcastOption_interactive() throws Exception {
    public void testBroadcastOption_interactive() throws Exception {
        final BroadcastOptions options = BroadcastOptions.makeBasic();
        final BroadcastOptions options = BroadcastOptions.makeBasic();
        options.setInteractiveBroadcast(true);
        options.setInteractive(true);
        final Intent intent = makeBroadcastIntent(BROADCAST_REGISTERED);
        final Intent intent = makeBroadcastIntent(BROADCAST_REGISTERED);


        try {
        try {
            getContext().sendBroadcast(intent, null, options.toBundle());
            getContext().sendBroadcast(intent, null, options.toBundle());
            fail("No exception thrown with BroadcastOptions.setInteractiveBroadcast(true)");
            fail("No exception thrown with BroadcastOptions.setInteractive(true)");
        } catch (SecurityException se) {
        } catch (SecurityException se) {
            // Expected, correct behavior - this case intentionally empty
            // Expected, correct behavior - this case intentionally empty
        } catch (Exception e) {
        } catch (Exception e) {
            fail("Unexpected exception " + e.getMessage()
            fail("Unexpected exception " + e.getMessage()
                    + " thrown with BroadcastOptions.setInteractiveBroadcast(true)");
                    + " thrown with BroadcastOptions.setInteractive(true)");
        }
        }
    }
    }


    public void testBroadcastOption_interactive_PendingIntent() throws Exception {
    public void testBroadcastOption_interactive_PendingIntent() throws Exception {
        final BroadcastOptions options = BroadcastOptions.makeBasic();
        final BroadcastOptions options = BroadcastOptions.makeBasic();
        options.setInteractiveBroadcast(true);
        options.setInteractive(true);
        final Intent intent = makeBroadcastIntent(BROADCAST_REGISTERED);
        final Intent intent = makeBroadcastIntent(BROADCAST_REGISTERED);
        PendingIntent brPending = PendingIntent.getBroadcast(getContext(),
        PendingIntent brPending = PendingIntent.getBroadcast(getContext(),
                1, intent, PendingIntent.FLAG_IMMUTABLE);
                1, intent, PendingIntent.FLAG_IMMUTABLE);


        try {
        try {
            brPending.send(getContext(), 1, null, null, null, null, options.toBundle());
            brPending.send(getContext(), 1, null, null, null, null, options.toBundle());
            fail("No exception thrown with BroadcastOptions.setInteractiveBroadcast(true)");
            fail("No exception thrown with BroadcastOptions.setInteractive(true)");
        } catch (SecurityException se) {
        } catch (SecurityException se) {
            // Expected, correct behavior - this case intentionally empty
            // Expected, correct behavior - this case intentionally empty
        } catch (Exception e) {
        } catch (Exception e) {
            fail("Unexpected exception " + e.getMessage()
            fail("Unexpected exception " + e.getMessage()
                    + " thrown with BroadcastOptions.setInteractiveBroadcast(true)");
                    + " thrown with BroadcastOptions.setInteractive(true)");
        } finally {
        } finally {
            brPending.cancel();
            brPending.cancel();
        }
        }
+4 −3
Original line number Original line Diff line number Diff line
@@ -181,6 +181,7 @@ import android.app.ApplicationErrorReport;
import android.app.ApplicationExitInfo;
import android.app.ApplicationExitInfo;
import android.app.ApplicationThreadConstants;
import android.app.ApplicationThreadConstants;
import android.app.BroadcastOptions;
import android.app.BroadcastOptions;
import android.app.ComponentOptions;
import android.app.ContentProviderHolder;
import android.app.ContentProviderHolder;
import android.app.IActivityController;
import android.app.IActivityController;
import android.app.IActivityManager;
import android.app.IActivityManager;
@@ -13914,10 +13915,10 @@ public class ActivityManagerService extends IActivityManager.Stub
                throw new SecurityException(
                throw new SecurityException(
                        "Non-system callers may not flag broadcasts as alarm");
                        "Non-system callers may not flag broadcasts as alarm");
            }
            }
            if (options.containsKey(BroadcastOptions.KEY_INTERACTIVE_BROADCAST)) {
            if (options.containsKey(ComponentOptions.KEY_INTERACTIVE)) {
                enforceCallingPermission(
                enforceCallingPermission(
                        android.Manifest.permission.BROADCAST_OPTION_INTERACTIVE,
                        android.Manifest.permission.COMPONENT_OPTION_INTERACTIVE,
                        "setInteractiveBroadcast");
                        "setInteractive");
            }
            }
        }
        }
    }
    }
Loading