Merge "Implementation of Remote-SIM."

This commit is contained in:
Scott Randolph
2019-01-24 05:01:05 +00:00
committed by Gerrit Code Review
6 changed files with 304 additions and 24 deletions

View File

@@ -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);
@@ -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 {

View File

@@ -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

View File

@@ -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.

View File

@@ -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}
@@ -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
@@ -649,6 +666,7 @@ public class SubscriptionInfo implements Parcelable {
dest.writeBoolean(mIsGroupDisabled);
dest.writeInt(mCarrierId);
dest.writeInt(mProfileClass);
dest.writeInt(mSubscriptionType);
}
@Override
@@ -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

View File

@@ -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>
@@ -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}
@@ -1428,23 +1487,86 @@ public class SubscriptionManager {
logd("[addSubscriptionInfoRecord]- invalid slotIndex");
}
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);
} else {
logd("[addSubscriptionInfoRecord]- ISub service is null");
}
} catch (RemoteException ex) {
// ignore it
}
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) {
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("successfully added new subscription");
}
} catch (RemoteException ex) {
// ignore it
}
}
/**
* 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
}
}
/**
* Set SIM icon tint color by simInfo index
* @param tint the RGB value of icon tint color of the SIM

View File

@@ -52,8 +52,8 @@ interface ISub {
/**
* Get the active SubscriptionInfo associated with the slotIndex
* @param slotIndex the slot which the subscription is inserted
* @param callingPackage The package maing the call.
* @return SubscriptionInfo, maybe null if its not active
* @param callingPackage The package making the call.
* @return SubscriptionInfo, null for Remote-SIMs or non-active slotIndex.
*/
SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex, String callingPackage);
@@ -114,6 +114,26 @@ interface ISub {
*/
int addSubInfoRecord(String iccId, int slotIndex);
/**
* Add a new subscription info record, 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 device
* @param subscriptionType the type of subscription to be added.
* @return 0 if success, < 0 on error.
*/
int addSubInfo(String uniqueId, String displayName, int slotIndex, int subscriptionType);
/**
* Remove subscription info record for the given device.
* @param uniqueId This is the unique identifier for the subscription within the specific
* subscription type.
* @param subscriptionType the type of subscription to be removed
* @return 0 if success, < 0 on error.
*/
int removeSubInfo(String uniqueId, int subscriptionType);
/**
* Set SIM icon tint color by simInfo index
* @param tint the icon tint color of the SIM