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

Commit f36350ac authored by Android Build Merger (Role)'s avatar Android Build Merger (Role) Committed by Android (Google) Code Review
Browse files

Merge "Merge "Implementation of Remote-SIM." am: 9f7bc7d6 am: 0fd63d54 am: 6133800a"

parents a275d995 025bd52d
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -44683,6 +44683,7 @@ package android.telephony {
    method public String getNumber();
    method public int getSimSlotIndex();
    method public int getSubscriptionId();
    method public int getSubscriptionType();
    method public boolean isEmbedded();
    method public boolean isOpportunistic();
    method public void writeToParcel(android.os.Parcel, int);
@@ -44733,6 +44734,8 @@ package android.telephony {
    field public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
    field public static final int INVALID_SIM_SLOT_INDEX = -1; // 0xffffffff
    field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
    field public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0; // 0x0
    field public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1; // 0x1
  }
  public static class SubscriptionManager.OnOpportunisticSubscriptionsChangedListener {
+1 −1
Original line number Diff line number Diff line
@@ -3518,7 +3518,7 @@ Lcom/android/internal/telephony/SubscriptionController;->mDefaultPhoneId:I
Lcom/android/internal/telephony/SubscriptionController;->mLock:Ljava/lang/Object;
Lcom/android/internal/telephony/SubscriptionController;->notifySubscriptionInfoChanged()V
Lcom/android/internal/telephony/SubscriptionController;->setDefaultDataSubId(I)V
Lcom/android/internal/telephony/SubscriptionController;->setDefaultFallbackSubId(I)V
Lcom/android/internal/telephony/SubscriptionController;->setDefaultFallbackSubId(II)V
Lcom/android/internal/telephony/SubscriptionController;->setDefaultSmsSubId(I)V
Lcom/android/internal/telephony/SubscriptionController;->setDefaultVoiceSubId(I)V
Lcom/android/internal/telephony/SubscriptionController;->setPlmnSpn(IZLjava/lang/String;ZLjava/lang/String;)Z
+118 −2
Original line number Diff line number Diff line
@@ -22,6 +22,10 @@ import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.app.ActivityThread;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothMapClient;
import android.bluetooth.BluetoothProfile;
import android.content.ActivityNotFoundException;
import android.content.ContentValues;
import android.content.Context;
@@ -32,6 +36,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.telecom.PhoneAccount;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
@@ -61,6 +66,8 @@ import java.util.Map;
 */
public final class SmsManager {
    private static final String TAG = "SmsManager";
    private static final boolean DBG = false;

    /**
     * A psuedo-subId that represents the default subId at any given time. The actual subId it
     * represents changes as the default subId is changed.
@@ -339,6 +346,44 @@ public final class SmsManager {
            throw new IllegalArgumentException("Invalid message body");
        }

        // A Manager code accessing another manager is *not* acceptable, in Android.
        // In this particular case, it is unavoidable because of the following:
        // If the subscription for this SmsManager instance belongs to a remote SIM
        // then a listener to get BluetoothMapClient proxy needs to be started up.
        // Doing that is possible only in a foreground thread or as a system user.
        // i.e., Can't be done in ISms service.
        // For that reason, SubscriptionManager needs to be accessed here to determine
        // if the subscription belongs to a remote SIM.
        // Ideally, there should be another API in ISms to service messages going thru
        // remote SIM subscriptions (and ISms should be tweaked to be able to access
        // BluetoothMapClient proxy)
        Context context = ActivityThread.currentApplication().getApplicationContext();
        SubscriptionManager manager = (SubscriptionManager) context
                .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
        int subId = getSubscriptionId();
        SubscriptionInfo info = manager.getActiveSubscriptionInfo(subId);
        if (DBG) {
            Log.d(TAG, "for subId: " + subId + ", subscription-info: " + info);
        }
        if (info == null) {
            // There is no subscription for the given subId. That can only mean one thing:
            // the caller is using a SmsManager instance with an obsolete subscription id.
            // That is most probably because caller didn't invalidate SmsManager instance
            // for an already deleted subscription id.
            Log.e(TAG, "subId: " + subId + " for this SmsManager instance is obsolete.");
            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_NO_SERVICE);
        }

        /* If the Subscription associated with this SmsManager instance belongs to a remote-sim,
         * then send the message thru the remote-sim subscription.
         */
        if (info.getSubscriptionType() == SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM) {
            if (DBG) Log.d(TAG, "sending message thru bluetooth");
            sendTextMessageBluetooth(destinationAddress, scAddress, text, sentIntent,
                    deliveryIntent, info);
            return;
        }

        try {
            ISms iccISms = getISmsServiceOrThrow();
            iccISms.sendTextForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(),
@@ -350,6 +395,79 @@ public final class SmsManager {
        }
    }

    private void sendTextMessageBluetooth(String destAddr, String scAddress,
            String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
            SubscriptionInfo info) {
        BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
        if (btAdapter == null) {
            // No bluetooth service on this platform?
            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_NO_SERVICE);
            return;
        }
        BluetoothDevice device = btAdapter.getRemoteDevice(info.getIccId());
        if (device == null) {
            if (DBG) Log.d(TAG, "Bluetooth device addr invalid: " + info.getIccId());
            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_NO_SERVICE);
            return;
        }
        btAdapter.getProfileProxy(ActivityThread.currentApplication().getApplicationContext(),
                new MapMessageSender(destAddr, text, device, sentIntent, deliveryIntent),
                BluetoothProfile.MAP_CLIENT);
    }

    private class MapMessageSender implements BluetoothProfile.ServiceListener {
        final Uri[] mDestAddr;
        private String mMessage;
        final BluetoothDevice mDevice;
        final PendingIntent mSentIntent;
        final PendingIntent mDeliveryIntent;
        MapMessageSender(final String destAddr, final String message, final BluetoothDevice device,
                final PendingIntent sentIntent, final PendingIntent deliveryIntent) {
            super();
            mDestAddr = new Uri[] {new Uri.Builder()
                    .appendPath(destAddr)
                    .scheme(PhoneAccount.SCHEME_TEL)
                    .build()};
            mMessage = message;
            mDevice = device;
            mSentIntent = sentIntent;
            mDeliveryIntent = deliveryIntent;
        }

        @Override
        public void onServiceConnected(int profile, BluetoothProfile proxy) {
            if (DBG) Log.d(TAG, "Service connected");
            if (profile != BluetoothProfile.MAP_CLIENT) return;
            BluetoothMapClient mapProfile = (BluetoothMapClient) proxy;
            if (mMessage != null) {
                if (DBG) Log.d(TAG, "Sending message thru bluetooth");
                mapProfile.sendMessage(mDevice, mDestAddr, mMessage, mSentIntent, mDeliveryIntent);
                mMessage = null;
            }
            BluetoothAdapter.getDefaultAdapter()
                    .closeProfileProxy(BluetoothProfile.MAP_CLIENT, mapProfile);
        }

        @Override
        public void onServiceDisconnected(int profile) {
            if (mMessage != null) {
                if (DBG) Log.d(TAG, "Bluetooth disconnected before sending the message");
                sendErrorInPendingIntent(mSentIntent, SmsManager.RESULT_ERROR_NO_SERVICE);
                mMessage = null;
            }
        }
    }

    private void sendErrorInPendingIntent(PendingIntent intent, int errorCode) {
        try {
            intent.send(errorCode);
        } catch (PendingIntent.CanceledException e) {
            // PendingIntent is cancelled. ignore sending this error code back to
            // caller.
            if (DBG) Log.d(TAG, "PendingIntent.CanceledException: " + e.getMessage());
        }
    }

    /**
     * Send a text based SMS without writing it into the SMS Provider.
     *
@@ -888,8 +1006,6 @@ public final class SmsManager {
        }
    }



    /**
     * Get the SmsManager associated with the default subscription id. The instance will always be
     * associated with the default subscription id, even if the default subscription id is changed.
+25 −6
Original line number Diff line number Diff line
@@ -183,6 +183,11 @@ public class SubscriptionInfo implements Parcelable {
     */
    private int mProfileClass;

    /**
     * Type of subscription
     */
    private int mSubscriptionType;

    /**
     * @hide
     */
@@ -206,7 +211,8 @@ public class SubscriptionInfo implements Parcelable {
            @Nullable String groupUUID, boolean isMetered, int carrierId, int profileClass) {
        this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
                roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString, -1,
                isOpportunistic, groupUUID, isMetered, false, carrierId, profileClass);
                isOpportunistic, groupUUID, isMetered, false, carrierId, profileClass,
                SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
    }

    /**
@@ -217,7 +223,7 @@ public class SubscriptionInfo implements Parcelable {
            Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
            @Nullable UiccAccessRule[] accessRules, String cardString, int cardId,
            boolean isOpportunistic, @Nullable String groupUUID, boolean isMetered,
            boolean isGroupDisabled, int carrierid, int profileClass) {
            boolean isGroupDisabled, int carrierId, int profileClass, int subType) {
        this.mId = id;
        this.mIccId = iccId;
        this.mSimSlotIndex = simSlotIndex;
@@ -239,11 +245,11 @@ public class SubscriptionInfo implements Parcelable {
        this.mGroupUUID = groupUUID;
        this.mIsMetered = isMetered;
        this.mIsGroupDisabled = isGroupDisabled;
        this.mCarrierId = carrierid;
        this.mCarrierId = carrierId;
        this.mProfileClass = profileClass;
        this.mSubscriptionType = subType;
    }


    /**
     * @return the subscription ID.
     */
@@ -486,6 +492,16 @@ public class SubscriptionInfo implements Parcelable {
        return this.mProfileClass;
    }

    /**
     * This method returns the type of a subscription. It can be
     * {@link SubscriptionManager#SUBSCRIPTION_TYPE_LOCAL_SIM} or
     * {@link SubscriptionManager#SUBSCRIPTION_TYPE_REMOTE_SIM}.
     * @return the type of subscription
     */
    public @SubscriptionManager.SubscriptionType int getSubscriptionType() {
        return mSubscriptionType;
    }

    /**
     * Checks whether the app with the given context is authorized to manage this subscription
     * according to its metadata. Only supported for embedded subscriptions (if {@link #isEmbedded}
@@ -612,11 +628,12 @@ public class SubscriptionInfo implements Parcelable {
            boolean isGroupDisabled = source.readBoolean();
            int carrierid = source.readInt();
            int profileClass = source.readInt();
            int subType = source.readInt();

            return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
                    nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
                    isEmbedded, accessRules, cardString, cardId, isOpportunistic, groupUUID,
                    isMetered, isGroupDisabled, carrierid, profileClass);
                    isMetered, isGroupDisabled, carrierid, profileClass, subType);
        }

        @Override
@@ -650,6 +667,7 @@ public class SubscriptionInfo implements Parcelable {
        dest.writeBoolean(mIsGroupDisabled);
        dest.writeInt(mCarrierId);
        dest.writeInt(mProfileClass);
        dest.writeInt(mSubscriptionType);
    }

    @Override
@@ -686,7 +704,8 @@ public class SubscriptionInfo implements Parcelable {
                + " cardString=" + cardStringToPrint + " cardId=" + mCardId
                + " isOpportunistic " + mIsOpportunistic + " mGroupUUID=" + mGroupUUID
                + " isMetered=" + mIsMetered + " mIsGroupDisabled=" + mIsGroupDisabled
                + " profileClass=" + mProfileClass + "}";
                + " profileClass=" + mProfileClass
                + " subscriptionType=" + mSubscriptionType + "}";
    }

    @Override
+130 −8
Original line number Diff line number Diff line
@@ -247,7 +247,9 @@ public class SubscriptionManager {
    public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";

    /**
     * TelephonyProvider column name for SIM ICC Identifier
     * TelephonyProvider column name for a unique identifier for the subscription within the
     * specific subscription type. For example, it contains SIM ICC Identifier subscriptions
     * on Local SIMs. and Mac-address for Remote-SIM Subscriptions for Bluetooth devices.
     * <P>Type: TEXT (String)</P>
     */
    /** @hide */
@@ -264,6 +266,63 @@ public class SubscriptionManager {
    /** @hide */
    public static final int SIM_NOT_INSERTED = -1;

    /**
     * The slot-index for Bluetooth Remote-SIM subscriptions
     * @hide
     */
    public static final int SLOT_INDEX_FOR_REMOTE_SIM_SUB = INVALID_SIM_SLOT_INDEX;

    /**
     * TelephonyProvider column name Subscription-type.
     * <P>Type: INTEGER (int)</P> {@link #SUBSCRIPTION_TYPE_LOCAL_SIM} for Local-SIM Subscriptions,
     * {@link #SUBSCRIPTION_TYPE_REMOTE_SIM} for Remote-SIM Subscriptions.
     * Default value is 0.
     */
    /** @hide */
    public static final String SUBSCRIPTION_TYPE = "subscription_type";

    /**
     * This constant is to designate a subscription as a Local-SIM Subscription.
     * <p> A Local-SIM can be a physical SIM inserted into a sim-slot in the device, or eSIM on the
     * device.
     * </p>
     */
    public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0;

    /**
     * This constant is to designate a subscription as a Remote-SIM Subscription.
     * <p>
     * A Remote-SIM subscription is for a SIM on a phone connected to this device via some
     * connectivity mechanism, for example bluetooth. Similar to Local SIM, this subscription can
     * be used for SMS, Voice and data by proxying data through the connected device.
     * Certain data of the SIM, such as IMEI, are not accessible for Remote SIMs.
     * </p>
     *
     * <p>
     * A Remote-SIM is available only as long the phone stays connected to this device.
     * When the phone disconnects, Remote-SIM subscription is removed from this device and is
     * no longer known. All data associated with the subscription, such as stored SMS, call logs,
     * contacts etc, are removed from this device.
     * </p>
     *
     * <p>
     * If the phone re-connects to this device, a new Remote-SIM subscription is created for
     * the phone. The Subscription Id associated with the new subscription is different from
     * the Subscription Id of the previous Remote-SIM subscription created (and removed) for the
     * phone; i.e., new Remote-SIM subscription treats the reconnected phone as a Remote-SIM that
     * was never seen before.
     * </p>
     */
    public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1;

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = {"SUBSCRIPTION_TYPE_"},
        value = {
            SUBSCRIPTION_TYPE_LOCAL_SIM,
            SUBSCRIPTION_TYPE_REMOTE_SIM})
    public @interface SubscriptionType {}

    /**
     * TelephonyProvider column name for user displayed name.
     * <P>Type: TEXT (String)</P>
@@ -1145,7 +1204,7 @@ public class SubscriptionManager {
    }

    /**
     * Get the SubscriptionInfo(s) of the currently inserted SIM(s). The records will be sorted
     * Get the SubscriptionInfo(s) of the currently active SIM(s). The records will be sorted
     * by {@link SubscriptionInfo#getSimSlotIndex} then by {@link SubscriptionInfo#getSubscriptionId}.
     *
     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -1427,21 +1486,84 @@ public class SubscriptionManager {
            logd("[addSubscriptionInfoRecord]- invalid slotIndex");
        }

        addSubscriptionInfoRecord(iccId, null, slotIndex, SUBSCRIPTION_TYPE_LOCAL_SIM);

        // FIXME: Always returns null?
        return null;

    }

    /**
     * Add a new SubscriptionInfo to SubscriptionInfo database if needed
     * @param uniqueId This is the unique identifier for the subscription within the
     *                 specific subscription type.
     * @param displayName human-readable name of the device the subscription corresponds to.
     * @param slotIndex the slot assigned to this subscription. It is ignored for subscriptionType
     *                  of {@link #SUBSCRIPTION_TYPE_REMOTE_SIM}.
     * @param subscriptionType the {@link #SUBSCRIPTION_TYPE}
     * @hide
     */
    public void addSubscriptionInfoRecord(String uniqueId, String displayName, int slotIndex,
            int subscriptionType) {
        if (VDBG) {
            logd("[addSubscriptionInfoRecord]+ uniqueId:" + uniqueId
                    + ", displayName:" + displayName + ", slotIndex:" + slotIndex
                    + ", subscriptionType: " + subscriptionType);
        }
        if (uniqueId == null) {
            Log.e(LOG_TAG, "[addSubscriptionInfoRecord]- uniqueId is null");
            return;
        }

        try {
            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
            if (iSub != null) {
                // FIXME: This returns 1 on success, 0 on error should should we return it?
                iSub.addSubInfoRecord(iccId, slotIndex);
            if (iSub == null) {
                Log.e(LOG_TAG, "[addSubscriptionInfoRecord]- ISub service is null");
                return;
            }
            int result = iSub.addSubInfo(uniqueId, displayName, slotIndex, subscriptionType);
            if (result < 0) {
                Log.e(LOG_TAG, "Adding of subscription didn't succeed: error = " + result);
            } else {
                logd("[addSubscriptionInfoRecord]- ISub service is null");
                logd("successfully added new subscription");
            }
        } catch (RemoteException ex) {
            // ignore it
        }
    }

        // FIXME: Always returns null?
        return null;
    /**
     * Remove SubscriptionInfo record from the SubscriptionInfo database
     * @param uniqueId This is the unique identifier for the subscription within the specific
     *                 subscription type.
     * @param subscriptionType the {@link #SUBSCRIPTION_TYPE}
     * @hide
     */
    public void removeSubscriptionInfoRecord(String uniqueId, int subscriptionType) {
        if (VDBG) {
            logd("[removeSubscriptionInfoRecord]+ uniqueId:" + uniqueId
                    + ", subscriptionType: " + subscriptionType);
        }
        if (uniqueId == null) {
            Log.e(LOG_TAG, "[addSubscriptionInfoRecord]- uniqueId is null");
            return;
        }

        try {
            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
            if (iSub == null) {
                Log.e(LOG_TAG, "[removeSubscriptionInfoRecord]- ISub service is null");
                return;
            }
            int result = iSub.removeSubInfo(uniqueId, subscriptionType);
            if (result < 0) {
                Log.e(LOG_TAG, "Removal of subscription didn't succeed: error = " + result);
            } else {
                logd("successfully removed subscription");
            }
        } catch (RemoteException ex) {
            // ignore it
        }
    }

    /**
Loading