Loading api/current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -42864,6 +42864,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); Loading Loading @@ -42914,6 +42915,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 { config/hiddenapi-greylist.txt +1 −1 Original line number Diff line number Diff line Loading @@ -3612,7 +3612,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 Loading telephony/java/android/telephony/SmsManager.java +118 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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(), Loading @@ -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. * Loading Loading @@ -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. Loading telephony/java/android/telephony/SubscriptionInfo.java +25 −6 Original line number Diff line number Diff line Loading @@ -183,6 +183,11 @@ public class SubscriptionInfo implements Parcelable { */ private int mProfileClass; /** * Type of subscription */ private int mSubscriptionType; /** * @hide */ Loading @@ -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); } /** Loading @@ -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; Loading @@ -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. */ Loading Loading @@ -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} Loading Loading @@ -611,11 +627,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 Loading Loading @@ -649,6 +666,7 @@ public class SubscriptionInfo implements Parcelable { dest.writeBoolean(mIsGroupDisabled); dest.writeInt(mCarrierId); dest.writeInt(mProfileClass); dest.writeInt(mSubscriptionType); } @Override Loading Loading @@ -685,7 +703,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 Loading telephony/java/android/telephony/SubscriptionManager.java +130 −8 Original line number Diff line number Diff line Loading @@ -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 */ Loading @@ -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> Loading Loading @@ -1146,7 +1205,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} Loading Loading @@ -1428,21 +1487,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 Loading
api/current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -42864,6 +42864,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); Loading Loading @@ -42914,6 +42915,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 {
config/hiddenapi-greylist.txt +1 −1 Original line number Diff line number Diff line Loading @@ -3612,7 +3612,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 Loading
telephony/java/android/telephony/SmsManager.java +118 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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(), Loading @@ -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. * Loading Loading @@ -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. Loading
telephony/java/android/telephony/SubscriptionInfo.java +25 −6 Original line number Diff line number Diff line Loading @@ -183,6 +183,11 @@ public class SubscriptionInfo implements Parcelable { */ private int mProfileClass; /** * Type of subscription */ private int mSubscriptionType; /** * @hide */ Loading @@ -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); } /** Loading @@ -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; Loading @@ -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. */ Loading Loading @@ -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} Loading Loading @@ -611,11 +627,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 Loading Loading @@ -649,6 +666,7 @@ public class SubscriptionInfo implements Parcelable { dest.writeBoolean(mIsGroupDisabled); dest.writeInt(mCarrierId); dest.writeInt(mProfileClass); dest.writeInt(mSubscriptionType); } @Override Loading Loading @@ -685,7 +703,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 Loading
telephony/java/android/telephony/SubscriptionManager.java +130 −8 Original line number Diff line number Diff line Loading @@ -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 */ Loading @@ -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> Loading Loading @@ -1146,7 +1205,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} Loading Loading @@ -1428,21 +1487,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