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

Commit 78db9158 authored by Jordan Liu's avatar Jordan Liu Committed by Android (Google) Code Review
Browse files

Merge "Fix ordered background broadcast API"

parents a6983622 2bc01a87
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -11167,7 +11167,7 @@ package android.telephony {
  }
  public class CellBroadcastIntents {
    method public static void sendOrderedBroadcastForBackgroundReceivers(@NonNull android.content.Context, @Nullable android.os.UserHandle, @NonNull android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
    method public static void sendSmsCbReceivedBroadcast(@NonNull android.content.Context, @Nullable android.os.UserHandle, @NonNull android.telephony.SmsCbMessage, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, int);
  }
  public abstract class CellBroadcastService extends android.app.Service {
+56 −32
Original line number Diff line number Diff line
@@ -16,22 +16,23 @@

package android.telephony;

import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Telephony;

/**
 * A static helper class used to send Intents with prepopulated flags.
 * <p>
 * This is intended to be used by the CellBroadcastService and will throw a security exception if
 * used from a UID besides the network stack UID.
 * This is intended to be used by the CellBroadcastService and does nothing if the caller does not
 * have permission to broadcast {@link Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION}.
 *
 * @hide
 */
@@ -39,6 +40,8 @@ import android.os.UserHandle;
public class CellBroadcastIntents {
    private static final String LOG_TAG = "CellBroadcastIntents";

    private static final String EXTRA_MESSAGE = "message";

    /**
     * @hide
     */
@@ -46,50 +49,71 @@ public class CellBroadcastIntents {
    }

    /**
     * Returns an intent which can be received by background BroadcastReceivers. This is only
     * intended to be used by the CellBroadcastService and will throw a security exception if called
     * from another UID.
     * Broadcasts an SMS_CB_RECEIVED_ACTION intent which can be received by background
     * BroadcastReceivers. This is only intended to be used by the CellBroadcastService and will
     * do nothing if the caller does not have permission to broadcast
     * {@link Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION}.
     *
     * @param context            The context from which to send the broadcast
     * @param user               The user from which to send the broadcast
     * @param intent             The Intent to broadcast; all receivers matching this Intent will
     *                           receive the broadcast.
     * @param receiverPermission String naming a permissions that a receiver must hold in order to
     *                           receive your broadcast. If null, no permission is required.
     * @param receiverAppOp      The app op associated with the broadcast. If null, no appOp is
     *                           required. If both receiverAppOp and receiverPermission are
     *                           non-null, a receiver must have both of them to receive the
     *                           broadcast
     * @param smsCbMessage       The SmsCbMessage to include with the intent
     * @param resultReceiver     Your own BroadcastReceiver to treat as the final receiver of the
     *                           broadcast.
     * @param scheduler          A custom Handler with which to schedule the resultReceiver
     *                           callback; if null it will be scheduled in the Context's main
     *                           thread.
     * @param initialCode        An initial value for the result code.  Often Activity.RESULT_OK.
     * @param initialData        An initial value for the result data.  Often null.
     * @param initialExtras      An initial value for the result extras.  Often null.
     * @param slotIndex          The slot index to include in the intent
     */
    public static void sendOrderedBroadcastForBackgroundReceivers(@NonNull Context context,
            @Nullable UserHandle user, @NonNull Intent intent, @Nullable String receiverPermission,
            @Nullable String receiverAppOp, @Nullable BroadcastReceiver resultReceiver,
            @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
            @Nullable Bundle initialExtras) {
        int status = context.checkCallingOrSelfPermission(
                "android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS");
        if (status == PackageManager.PERMISSION_DENIED) {
            throw new SecurityException(
                    "Caller does not have permission to send broadcast for background receivers");
        }
        Intent backgroundIntent = new Intent(intent);
    public static void sendSmsCbReceivedBroadcast(@NonNull Context context,
            @Nullable UserHandle user, @NonNull SmsCbMessage smsCbMessage,
            @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler,
            int initialCode, int slotIndex) {
        Intent backgroundIntent = new Intent(Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION);
        backgroundIntent.putExtra(EXTRA_MESSAGE, smsCbMessage);
        backgroundIntent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        putPhoneIdAndSubIdExtra(context, backgroundIntent, slotIndex);

        String receiverPermission = Manifest.permission.RECEIVE_SMS;
        String receiverAppOp = AppOpsManager.OPSTR_RECEIVE_SMS;
        if (user != null) {
            context.createContextAsUser(user, 0).sendOrderedBroadcast(backgroundIntent,
                    receiverPermission, receiverAppOp, resultReceiver, scheduler, initialCode,
                    initialData, initialExtras);
                    null, null);
        } else {
            context.sendOrderedBroadcast(backgroundIntent, receiverPermission,
                    receiverAppOp, resultReceiver, scheduler, initialCode, initialData,
                    initialExtras);
                    receiverAppOp, resultReceiver, scheduler, initialCode, null, null);
        }
    }

    /**
     * Put the phone ID and sub ID into an intent as extras.
     */
    private static void putPhoneIdAndSubIdExtra(Context context, Intent intent, int phoneId) {
        int subId = getSubIdForPhone(context, phoneId);
        if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
            intent.putExtra("subscription", subId);
            intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
        }
        intent.putExtra("phone", phoneId);
        intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId);
    }

    /**
     * Get the subscription ID for a phone ID, or INVALID_SUBSCRIPTION_ID if the phone does not
     * have an active sub
     * @param phoneId the phoneId to use
     * @return the associated sub id
     */
    private static int getSubIdForPhone(Context context, int phoneId) {
        SubscriptionManager subMan =
                (SubscriptionManager) context.getSystemService(
                        Context.TELEPHONY_SUBSCRIPTION_SERVICE);
        int[] subIds = subMan.getSubscriptionIds(phoneId);
        if (subIds != null) {
            return subIds[0];
        } else {
            return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
        }
    }
}