Added API to verify that SubscriptionInfo is converted and to update carriers that support pSIM conversion.
Bug: b/315884067
Test: atest SubscriptionDatabaseManagerTest, SubscriptionInfoInternalTest, SubscriptionInfoTest
Change-Id: Ia45a4fd99f95c00f95d2280e6b6025e1ebd8220a
diff --git a/flags/subscription.aconfig b/flags/subscription.aconfig
index d2c36d6..fa77fc3 100644
--- a/flags/subscription.aconfig
+++ b/flags/subscription.aconfig
@@ -26,4 +26,11 @@
namespace: "telephony"
description: "Support emergency call only for data only cellular service."
bug: "296097429"
+}
+
+flag {
+ name: "support_psim_to_esim_conversion"
+ namespace: "telephony"
+ description: "Support the psim to esim conversion."
+ bug: "315073761"
}
\ No newline at end of file
diff --git a/src/java/com/android/internal/telephony/euicc/EuiccController.java b/src/java/com/android/internal/telephony/euicc/EuiccController.java
index a24ab43..400f8be 100644
--- a/src/java/com/android/internal/telephony/euicc/EuiccController.java
+++ b/src/java/com/android/internal/telephony/euicc/EuiccController.java
@@ -72,6 +72,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
@@ -79,6 +80,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
/** Backing implementation of {@link android.telephony.euicc.EuiccManager}. */
public class EuiccController extends IEuiccController.Stub {
@@ -121,6 +123,7 @@
// the phone process, 3) values are updated remotely by server flags.
private List<String> mSupportedCountries;
private List<String> mUnsupportedCountries;
+ private List<Integer> mPsimConversionSupportedCarrierIds;
/** Initialize the instance. Should only be called once. */
public static EuiccController init(Context context, FeatureFlags featureFlags) {
@@ -2073,6 +2076,34 @@
return changeEnabled;
}
+
+ @Override
+ public void setPsimConversionSupportedCarriers(int[] carrierIds) {
+ if (!callerCanWriteEmbeddedSubscriptions()) {
+ throw new SecurityException(
+ "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to "
+ + "set pSIM conversion supported carriers");
+ }
+ mPsimConversionSupportedCarrierIds = Arrays.stream(carrierIds).boxed()
+ .collect(Collectors.toList());
+ }
+
+
+
+ @Override
+ public boolean isPsimConversionSupported(int carrierId) {
+ if (!callerCanWriteEmbeddedSubscriptions()) {
+ throw new SecurityException(
+ "Must have WRITE_EMBEDDED_SUBSCRIPTIONS "
+ + "to check if the carrier is supported pSIM conversion");
+ }
+ if (mPsimConversionSupportedCarrierIds == null
+ || mPsimConversionSupportedCarrierIds.isEmpty()) {
+ return false;
+ }
+ return mPsimConversionSupportedCarrierIds.contains(carrierId);
+ }
+
/**
* Make sure the device has required telephony feature
*
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java
index bbe88a8..e20b295 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java
@@ -284,7 +284,10 @@
SubscriptionInfoInternal::getOnlyNonTerrestrialNetwork),
new AbstractMap.SimpleImmutableEntry<>(
SimInfo.COLUMN_SERVICE_CAPABILITIES,
- SubscriptionInfoInternal::getServiceCapabilities)
+ SubscriptionInfoInternal::getServiceCapabilities),
+ new AbstractMap.SimpleImmutableEntry<>(
+ SimInfo.COLUMN_TRANSFER_STATUS,
+ SubscriptionInfoInternal::getTransferStatus)
);
/**
@@ -418,7 +421,10 @@
SubscriptionDatabaseManager::setNtn),
new AbstractMap.SimpleImmutableEntry<>(
SimInfo.COLUMN_SERVICE_CAPABILITIES,
- SubscriptionDatabaseManager::setServiceCapabilities)
+ SubscriptionDatabaseManager::setServiceCapabilities),
+ new AbstractMap.SimpleImmutableEntry<>(
+ SimInfo.COLUMN_TRANSFER_STATUS,
+ SubscriptionDatabaseManager::setTransferStatus)
);
/**
@@ -2335,6 +2341,10 @@
builder.setOnlyNonTerrestrialNetwork(cursor.getInt(cursor.getColumnIndexOrThrow(
SimInfo.COLUMN_IS_NTN)));
}
+ if (mFeatureFlags.supportPsimToEsimConversion()) {
+ builder.setTransferStatus(cursor.getInt(cursor.getColumnIndexOrThrow(
+ SimInfo.COLUMN_TRANSFER_STATUS)));
+ }
return builder.build();
}
@@ -2409,6 +2419,25 @@
}
/**
+ * Set the transfer status of the subscriptionInfo that corresponds to subId.
+ *
+ * @param subId Subscription ID.
+ * @param status The transfer status to change.
+ *
+ * @throws IllegalArgumentException if the subscription does not exist.
+ */
+ public void setTransferStatus(int subId, int status) {
+ if (!mFeatureFlags.supportPsimToEsimConversion()) {
+ log("SubscriptionDatabaseManager:supportPsimToEsimConversion is false");
+ return;
+ }
+
+ writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_TRANSFER_STATUS,
+ status,
+ SubscriptionInfoInternal.Builder::setTransferStatus);
+ }
+
+ /**
* Log debug messages.
*
* @param s debug messages
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java
index aa460d5..e646418 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java
@@ -474,6 +474,11 @@
private final int mServiceCapabilities;
/**
+ * The transfer status of the subscription
+ */
+ private final int mTransferStatus;
+
+ /**
* Constructor from builder.
*
* @param builder Builder of {@link SubscriptionInfoInternal}.
@@ -549,6 +554,7 @@
this.mCardId = builder.mCardId;
this.mIsGroupDisabled = builder.mIsGroupDisabled;
this.mServiceCapabilities = builder.mServiceCapabilities;
+ this.mTransferStatus = builder.mTransferStatus;
}
/**
@@ -1205,6 +1211,12 @@
public int getServiceCapabilities() {
return mServiceCapabilities;
}
+ /**
+ * @return Transfer status.
+ */
+ public int getTransferStatus() {
+ return mTransferStatus;
+ }
/** @return converted {@link SubscriptionInfo}. */
@NonNull
@@ -1244,6 +1256,7 @@
.setOnlyNonTerrestrialNetwork(mIsOnlyNonTerrestrialNetwork == 1)
.setServiceCapabilities(
SubscriptionManager.getServiceCapabilitiesSet(mServiceCapabilities))
+ .setTransferStatus(mTransferStatus)
.build();
}
@@ -1304,6 +1317,7 @@
+ " getOnlyNonTerrestrialNetwork=" + mIsOnlyNonTerrestrialNetwork
+ " isGroupDisabled=" + mIsGroupDisabled
+ " serviceCapabilities=" + mServiceCapabilities
+ + " transferStatus=" + mTransferStatus
+ "]";
}
@@ -1361,7 +1375,8 @@
that.mNumberFromCarrier) && mNumberFromIms.equals(that.mNumberFromIms)
&& mIsSatelliteAttachEnabledForCarrier == that.mIsSatelliteAttachEnabledForCarrier
&& mIsOnlyNonTerrestrialNetwork == that.mIsOnlyNonTerrestrialNetwork
- && mServiceCapabilities == that.mServiceCapabilities;
+ && mServiceCapabilities == that.mServiceCapabilities
+ && mTransferStatus == that.mTransferStatus;
}
@Override
@@ -1384,7 +1399,7 @@
mNumberFromIms, mPortIndex, mUsageSetting, mLastUsedTPMessageReference, mUserId,
mIsSatelliteEnabled, mCardId, mIsGroupDisabled,
mIsSatelliteAttachEnabledForCarrier, mIsOnlyNonTerrestrialNetwork,
- mServiceCapabilities);
+ mServiceCapabilities, mTransferStatus);
result = 31 * result + Arrays.hashCode(mNativeAccessRules);
result = 31 * result + Arrays.hashCode(mCarrierConfigAccessRules);
result = 31 * result + Arrays.hashCode(mRcsConfig);
@@ -1777,6 +1792,11 @@
private int mServiceCapabilities;
/**
+ * The transfer status of the subscription
+ */
+ private int mTransferStatus;
+
+ /**
* Default constructor.
*/
public Builder() {
@@ -1855,6 +1875,7 @@
mCardId = info.mCardId;
mIsGroupDisabled = info.mIsGroupDisabled;
mServiceCapabilities = info.mServiceCapabilities;
+ mTransferStatus = info.mTransferStatus;
}
/**
@@ -2787,6 +2808,18 @@
}
/**
+ * Set the transfer status of the subscription.
+ *
+ * @param status The transfer status
+ * @return The builder.
+ */
+ @NonNull
+ public Builder setTransferStatus(int status) {
+ mTransferStatus = status;
+ return this;
+ }
+
+ /**
* Build the {@link SubscriptionInfoInternal}.
*
* @return The {@link SubscriptionInfoInternal} instance.
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
index ddf80a8..0d03f91 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
@@ -22,6 +22,7 @@
import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.ColorInt;
+import android.annotation.EnforcePermission;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -1219,7 +1220,11 @@
builder.setCardString(mUiccController.convertToCardString(cardId));
}
+ if (mFeatureFlags.supportPsimToEsimConversion()) {
+ builder.setTransferStatus(subInfo.getTransferStatus());
+ }
embeddedSubs.add(subInfo.getSubscriptionId());
+
subInfo = builder.build();
log("updateEmbeddedSubscriptions: update subscription " + subInfo);
mSubscriptionDatabaseManager.updateSubscription(subInfo);
@@ -4299,6 +4304,36 @@
}
}
+
+
+ /**
+ * Set the transfer status of the subscriptionInfo that corresponds to subId.
+ * @param subId The unique SubscriptionInfo key in database.
+ * @param status The transfer status to change. This value must be one of the following.
+ * {@link SubscriptionManager#TRANSFER_STATUS_NONE},
+ * {@link SubscriptionManager#TRANSFER_STATUS_TRANSFERRED_OUT} or
+ * {@link SubscriptionManager#TRANSFER_STATUS_CONVERTED}
+ *
+ */
+ @Override
+ @EnforcePermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
+ public void setTransferStatus(int subId, int status) {
+ setTransferStatus_enforcePermission();
+ if (mContext.checkCallingOrSelfPermission(
+ Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must have WRITE_EMBEDDED_SUBSCRIPTIONS to"
+ + "setTransferStatus");
+ }
+ long token = Binder.clearCallingIdentity();
+ try {
+ mSubscriptionDatabaseManager.setTransferStatus(subId, status);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+
/**
* Get the current calling package name.
* @return the current calling package name
diff --git a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
index 7dd4093..d52e4ee 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
@@ -132,7 +132,8 @@
+ Telephony.SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER
+ " INTEGER DEFAULT 1, "
+ Telephony.SimInfo.COLUMN_IS_NTN + " INTEGER DEFAULT 0,"
- + Telephony.SimInfo.COLUMN_SERVICE_CAPABILITIES + " INTEGER DEFAULT 7"
+ + Telephony.SimInfo.COLUMN_SERVICE_CAPABILITIES + " INTEGER DEFAULT 7,"
+ + Telephony.SimInfo.COLUMN_TRANSFER_STATUS + " INTEGER DEFAULT 0"
+ ");";
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java
index 4afdfe9..ac92b8f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java
@@ -68,6 +68,7 @@
.setOnlyNonTerrestrialNetwork(true)
.setServiceCapabilities(SubscriptionManager.getServiceCapabilitiesSet(
SubscriptionManager.SERVICE_CAPABILITY_DATA_BITMASK))
+ .setTransferStatus(1)
.build();
}
@@ -92,6 +93,9 @@
}
assertThat(mSubscriptionInfoUT.getServiceCapabilities()).isEqualTo(
Set.of(SubscriptionManager.SERVICE_CAPABILITY_DATA));
+ if (Flags.supportPsimToEsimConversion()) {
+ assertThat(mSubscriptionInfoUT.getTransferStatus()).isEqualTo(1);
+ }
}
@Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java
index 1a89c15..130ebef 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java
@@ -134,6 +134,9 @@
private FeatureFlags mFeatureFlags;
+ static final int FAKE_TRANSFER_STATUS_TRANSFERRED_OUT = 1;
+ static final int FAKE_TRANSFER_STATUS_CONVERTED = 2;
+
static final SubscriptionInfoInternal FAKE_SUBSCRIPTION_INFO1 =
new SubscriptionInfoInternal.Builder()
.setId(1)
@@ -204,6 +207,7 @@
.setOnlyNonTerrestrialNetwork(FAKE_SATELLITE_IS_NTN_DISABLED)
.setGroupDisabled(false)
.setServiceCapabilities(FAKE_SERVICE_CAPABILITIES_1)
+ .setTransferStatus(FAKE_TRANSFER_STATUS_TRANSFERRED_OUT)
.build();
static final SubscriptionInfoInternal FAKE_SUBSCRIPTION_INFO2 =
@@ -276,6 +280,7 @@
.setOnlyNonTerrestrialNetwork(FAKE_SATELLITE_IS_NTN_ENABLED)
.setGroupDisabled(false)
.setServiceCapabilities(FAKE_SERVICE_CAPABILITIES_2)
+ .setTransferStatus(FAKE_TRANSFER_STATUS_CONVERTED)
.build();
private SubscriptionDatabaseManager mDatabaseManagerUT;
@@ -436,6 +441,7 @@
doReturn(2).when(mUiccController).convertToPublicCardId(eq(FAKE_ICCID2));
when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
when(mFeatureFlags.dataOnlyCellularService()).thenReturn(true);
+ when(mFeatureFlags.supportPsimToEsimConversion()).thenReturn(true);
mDatabaseManagerUT = new SubscriptionDatabaseManager(mContext, Looper.myLooper(),
mFeatureFlags, mSubscriptionDatabaseManagerCallback);
logd("SubscriptionDatabaseManagerTest -Setup!");
@@ -2239,4 +2245,37 @@
mDatabaseManagerUT.getSubscriptionInfoInternal(1).getServiceCapabilities())
.isEqualTo(FAKE_SERVICE_CAPABILITIES_1);
}
+
+ @Test
+ public void testSetTransferStatus() throws Exception {
+ // exception is expected if there is nothing in the database.
+ assertThrows(IllegalArgumentException.class,
+ () -> mDatabaseManagerUT.setTransferStatus(
+ FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(),
+ FAKE_TRANSFER_STATUS_TRANSFERRED_OUT));
+
+ SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1);
+ mDatabaseManagerUT.setTransferStatus(FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(),
+ FAKE_TRANSFER_STATUS_TRANSFERRED_OUT);
+ processAllMessages();
+
+ subInfo = new SubscriptionInfoInternal.Builder(subInfo)
+ .setTransferStatus(FAKE_TRANSFER_STATUS_TRANSFERRED_OUT)
+ .build();
+ verifySubscription(subInfo);
+ verify(mSubscriptionDatabaseManagerCallback, times(1)).onSubscriptionChanged(eq(1));
+
+ assertThat(mDatabaseManagerUT.getSubscriptionProperty(
+ FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(),
+ SimInfo.COLUMN_TRANSFER_STATUS)).isEqualTo(FAKE_TRANSFER_STATUS_TRANSFERRED_OUT);
+
+ mDatabaseManagerUT.setSubscriptionProperty(FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(),
+ SimInfo.COLUMN_TRANSFER_STATUS, FAKE_TRANSFER_STATUS_CONVERTED);
+ assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(
+ FAKE_SUBSCRIPTION_INFO1.getSubscriptionId()).getTransferStatus())
+ .isEqualTo(FAKE_TRANSFER_STATUS_CONVERTED);
+ assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(
+ FAKE_SUBSCRIPTION_INFO1.getSubscriptionId()).getTransferStatus())
+ .isNotEqualTo(FAKE_TRANSFER_STATUS_TRANSFERRED_OUT);
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java
index d9addd1..ff45bf9 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java
@@ -115,6 +115,7 @@
.setOnlyNonTerrestrialNetwork(1)
.setServiceCapabilities(
SubscriptionManager.SERVICE_CAPABILITY_DATA_BITMASK)
+ .setTransferStatus(1)
.build();
private final SubscriptionInfoInternal mSubInfoNull =
@@ -141,6 +142,7 @@
.setRcsConfig(new byte[0])
.setAllowedNetworkTypesForReasons("")
.setDeviceToDeviceStatusSharingContacts("")
+ .setTransferStatus(1)
.build();
@Rule
@@ -237,6 +239,7 @@
assertThat(mSubInfo.getOnlyNonTerrestrialNetwork()).isEqualTo(1);
assertThat(mSubInfo.getServiceCapabilities()).isEqualTo(
SubscriptionManager.SERVICE_CAPABILITY_DATA_BITMASK);
+ assertThat(mSubInfo.getTransferStatus()).isEqualTo(1);
}
@Test
@@ -303,6 +306,7 @@
assertThat(subInfo.isOnlyNonTerrestrialNetwork()).isTrue();
assertThat(subInfo.getServiceCapabilities()).isEqualTo(
Set.of(SubscriptionManager.SERVICE_CAPABILITY_DATA));
+ assertThat(mSubInfo.getTransferStatus()).isEqualTo(1);
}
@Test