Merge 24Q3 to AOSP main

Bug: 357762254
Merged-In: I07a98712e6f2fb3d1ce0a2e5f97693cdfbeb3582
Change-Id: I8717132b42def7a61cb227d4eed4e581c090bd30
diff --git a/src/com/android/ons/ONSProfileActivator.java b/src/com/android/ons/ONSProfileActivator.java
index d869975..9c270a2 100644
--- a/src/com/android/ons/ONSProfileActivator.java
+++ b/src/com/android/ons/ONSProfileActivator.java
@@ -31,6 +31,7 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.UiccCardInfo;
 import android.telephony.euicc.EuiccManager;
 import android.util.Log;
 
@@ -79,7 +80,7 @@
         mONSProfileConfig = new ONSProfileConfigurator(mContext, mSubManager,
                 mCarrierConfigMgr, mEuiccManager, this);
         mONSProfileDownloader = new ONSProfileDownloader(mContext, mCarrierConfigMgr,
-                mEuiccManager, mONSProfileConfig, this);
+                mEuiccManager, mSubManager, mONSProfileConfig, this);
 
         //Monitor internet connection.
         mConnectivityManager = context.getSystemService(ConnectivityManager.class);
@@ -480,7 +481,19 @@
      * Checks if device supports eSIM.
      */
     private boolean isESIMSupported() {
-        return (mEuiccManager != null && mEuiccManager.isEnabled());
+        for (UiccCardInfo uiccCardInfo : mTelephonyManager.getUiccCardsInfo()) {
+            if (uiccCardInfo != null && !uiccCardInfo.isEuicc()) {
+                // Skip this card.
+                continue;
+            }
+
+            EuiccManager euiccManager = mEuiccManager.createForCardId(uiccCardInfo.getCardId());
+            if (euiccManager.isEnabled()) {
+                return true;
+            }
+        }
+
+        return false;
     }
 
     /**
diff --git a/src/com/android/ons/ONSProfileConfigurator.java b/src/com/android/ons/ONSProfileConfigurator.java
index c949a5c..c0f0c70 100644
--- a/src/com/android/ons/ONSProfileConfigurator.java
+++ b/src/com/android/ons/ONSProfileConfigurator.java
@@ -161,7 +161,22 @@
         PendingIntent callbackIntent = PendingIntent.getBroadcast(mContext,
                 REQUEST_CODE_ACTIVATE_SUB, intent, PendingIntent.FLAG_IMMUTABLE);
         Log.d(TAG, "Activate oppSub request sent to SubManager");
-        mEuiccManager.switchToSubscription(subId, callbackIntent);
+
+        List<SubscriptionInfo> subInfoList = mSubscriptionManager
+                .getAvailableSubscriptionInfoList();
+        for (SubscriptionInfo subInfo : subInfoList) {
+            if (subId == subInfo.getSubscriptionId()) {
+                EuiccManager euiccManager = mEuiccManager.createForCardId(subInfo.getCardId());
+                // eUICC and the platform will internally resolve a port. If there is no available
+                // port, an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned
+                // in the callback intent to prompt the user to disable an already-active
+                // subscription. However, ONS will not show any prompt to the user and silently
+                // fails to activate the subscription. ONS will try to provision again when
+                // carrier configuration change event is received.
+                euiccManager.switchToSubscription(subId, callbackIntent);
+                break;
+            }
+        }
     }
 
     /**
@@ -235,7 +250,16 @@
         intent.putExtra(PARAM_SUB_ID, subId);
         PendingIntent callbackIntent = PendingIntent.getBroadcast(mContext,
                 REQUEST_CODE_DELETE_SUB, intent, PendingIntent.FLAG_MUTABLE);
-        mEuiccManager.deleteSubscription(subId, callbackIntent);
+
+        List<SubscriptionInfo> subInfoList = mSubscriptionManager
+                .getAvailableSubscriptionInfoList();
+        for (SubscriptionInfo subInfo : subInfoList) {
+            if (subId == subInfo.getSubscriptionId()) {
+                EuiccManager euiccManager = mEuiccManager.createForCardId(subInfo.getCardId());
+                euiccManager.deleteSubscription(subId, callbackIntent);
+                break;
+            }
+        }
     }
 
     /**
diff --git a/src/com/android/ons/ONSProfileDownloader.java b/src/com/android/ons/ONSProfileDownloader.java
index 11c6237..a052e07 100644
--- a/src/com/android/ons/ONSProfileDownloader.java
+++ b/src/com/android/ons/ONSProfileDownloader.java
@@ -24,6 +24,8 @@
 import android.os.Message;
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.telephony.euicc.DownloadableSubscription;
 import android.telephony.euicc.EuiccManager;
 import android.util.Log;
@@ -51,6 +53,7 @@
     private final Context mContext;
     private final CarrierConfigManager mCarrierConfigManager;
     private final EuiccManager mEuiccManager;
+    private final SubscriptionManager mSubManager;
     private final ONSProfileConfigurator mONSProfileConfig;
     private IONSProfileDownloaderListener mListener;
 
@@ -67,12 +70,13 @@
     };
 
     public ONSProfileDownloader(Context context, CarrierConfigManager carrierConfigManager,
-                                EuiccManager euiccManager,
+                                EuiccManager euiccManager, SubscriptionManager subManager,
                                 ONSProfileConfigurator onsProfileConfigurator,
                                 IONSProfileDownloaderListener listener) {
         mContext = context;
         mListener = listener;
         mEuiccManager = euiccManager;
+        mSubManager = subManager;
         mONSProfileConfig = onsProfileConfigurator;
         mCarrierConfigManager = carrierConfigManager;
 
@@ -258,8 +262,22 @@
                 REQUEST_CODE_DOWNLOAD_SUB, intent, PendingIntent.FLAG_MUTABLE);
 
         Log.d(TAG, "Download Request sent to EUICC Manager");
-        mEuiccManager.downloadSubscription(DownloadableSubscription.forActivationCode(
-                activationCode), true, callbackIntent);
+        // TODO: Check with euicc team if card specific EUICC Manager should be used to download.
+        // Once the eSIM profile is downloaded, port is auto decided by eUICC to activate the
+        // subscription. If there is no available port, an
+        // {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback
+        // intent to prompt the user to disable an already-active subscription. However, ONS will
+        // not show any prompt to the user and silently fails to activate the subscription.
+        // ONS will try to provision again when carrier configuration change event is received.
+        SubscriptionInfo primarySubInfo = mSubManager.getActiveSubscriptionInfo(primarySubId);
+        if (primarySubInfo != null && primarySubInfo.isEmbedded()) {
+            EuiccManager euiccManager = mEuiccManager.createForCardId(primarySubInfo.getCardId());
+            euiccManager.downloadSubscription(DownloadableSubscription.forActivationCode(
+                    activationCode), true, callbackIntent);
+        } else {
+            mEuiccManager.downloadSubscription(DownloadableSubscription.forActivationCode(
+                    activationCode), true, callbackIntent);
+        }
 
         return DownloadProfileResult.SUCCESS;
     }
@@ -272,7 +290,11 @@
      */
     private String getSMDPServerAddress(int subscriptionId) {
         PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subscriptionId);
-        return config.getString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING);
+        if (config != null) {
+            return config.getString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING);
+        } else {
+            return null;
+        }
     }
 
     /**
diff --git a/src/com/android/ons/ONSProfileSelector.java b/src/com/android/ons/ONSProfileSelector.java
index 95287fc..d9e5d07 100644
--- a/src/com/android/ons/ONSProfileSelector.java
+++ b/src/com/android/ons/ONSProfileSelector.java
@@ -371,7 +371,16 @@
                     TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SIM_PORT_NOT_AVAILABLE);
             return;
         }
-        mEuiccManager.switchToSubscription(subId, availableSIMPortIndex, replyIntent);
+
+        List<SubscriptionInfo> subInfoList = mSubscriptionManager
+                .getAvailableSubscriptionInfoList();
+        for (SubscriptionInfo subInfo : subInfoList) {
+            if (subId == subInfo.getSubscriptionId()) {
+                EuiccManager euiccManager = mEuiccManager.createForCardId(subInfo.getCardId());
+                euiccManager.switchToSubscription(subId, availableSIMPortIndex, replyIntent);
+                break;
+            }
+        }
     }
 
     @VisibleForTesting
diff --git a/src/com/android/ons/OpportunisticNetworkService.java b/src/com/android/ons/OpportunisticNetworkService.java
index ebc110e..3e9a52a 100644
--- a/src/com/android/ons/OpportunisticNetworkService.java
+++ b/src/com/android/ons/OpportunisticNetworkService.java
@@ -509,9 +509,11 @@
         enableOpportunisticNetwork(getPersistentEnableState());
         mONSProfileActivator = new ONSProfileActivator(mContext, mONSStats);
         mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
-        // Registers for carrier config changes and runs on handler thread
-        mCarrierConfigManager.registerCarrierConfigChangeListener(mHandler::post,
-                mCarrierConfigChangeListener);
+        if (mCarrierConfigManager != null) {
+            // Registers for carrier config changes and runs on handler thread
+            mCarrierConfigManager.registerCarrierConfigChangeListener(mHandler::post,
+                    mCarrierConfigChangeListener);
+        }
         mUserManager = mContext.getSystemService(UserManager.class);
         mPackageManager = mContext.getPackageManager();
         mVendorApiLevel = SystemProperties.getInt(
diff --git a/tests/src/com/android/ons/ONSProfileActivatorTest.java b/tests/src/com/android/ons/ONSProfileActivatorTest.java
index 478f23a..3a259b8 100644
--- a/tests/src/com/android/ons/ONSProfileActivatorTest.java
+++ b/tests/src/com/android/ons/ONSProfileActivatorTest.java
@@ -33,6 +33,8 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.UiccCardInfo;
+import android.telephony.UiccPortInfo;
 import android.telephony.euicc.EuiccManager;
 import android.util.Log;
 
@@ -79,6 +81,8 @@
     Resources mMockResources;
     @Mock
     ONSStats mMockONSStats;
+    @Mock
+    EuiccManager mMockEuiccManagerCard1;
 
     @Before
     public void setUp() throws Exception {
@@ -99,6 +103,25 @@
         persistableBundle.putBoolean(CarrierConfigManager
                 .KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL, true);
         doReturn(persistableBundle).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUBID_1);
+
+        ArrayList<UiccCardInfo> uiccCardInfoList = new ArrayList<>();
+        ArrayList<UiccPortInfo> uiccPortInfoList =  new ArrayList<>();
+        uiccPortInfoList.add(
+                new UiccPortInfo("123451234567890" /* iccId */,
+                0 /* portIdx */,
+                0 /* logicalSlotIdx */,
+                true /* isActive */));
+        UiccCardInfo uiccCardInfo = new UiccCardInfo(true, /* isEuicc */
+                1 /* cardId */,
+                "123451234567890" /* eid */,
+                0 /* physicalSlotIndex */,
+                true /* isRemovable */,
+                true /* isMultipleEnabledProfilesSupported */,
+                uiccPortInfoList /* portList */);
+        uiccCardInfoList.add(uiccCardInfo);
+        doReturn(mMockEuiccManagerCard1).when(mMockEuiccManager).createForCardId(1);
+        doReturn(true).when(mMockEuiccManagerCard1).isEnabled();
+        doReturn(uiccCardInfoList).when(mMockTeleManager).getUiccCardsInfo();
     }
 
     // Worker thread is used for testing asynchronous APIs and Message Handlers.
@@ -157,6 +180,7 @@
 
         doReturn(true).when(mMockResources).getBoolean(R.bool.enable_ons_auto_provisioning);
         doReturn(false).when(mMockEuiccManager).isEnabled();
+        doReturn(false).when(mMockEuiccManagerCard1).isEnabled();
 
         ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext,
                 mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager,
@@ -637,7 +661,9 @@
         doReturn(null).when(mMockSubInfo).getGroupUuid();
 
         final int maxRetryCount = 5;
-        final int retryBackoffTime = 1; //1 second
+
+        // Retry immediately without wait. To reduce UT execution time.
+        final int retryBackoffTime = 0;
 
         PersistableBundle persistableBundle = new PersistableBundle();
         persistableBundle.putBoolean(CarrierConfigManager
diff --git a/tests/src/com/android/ons/ONSProfileConfiguratorTest.java b/tests/src/com/android/ons/ONSProfileConfiguratorTest.java
index 7c88658..c13acbc 100644
--- a/tests/src/com/android/ons/ONSProfileConfiguratorTest.java
+++ b/tests/src/com/android/ons/ONSProfileConfiguratorTest.java
@@ -21,7 +21,6 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
 import android.app.PendingIntent;
-import android.content.Context;
 import android.content.Intent;
 import android.os.Looper;
 import android.os.Message;
@@ -30,7 +29,6 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
 import android.telephony.euicc.EuiccManager;
 
 import org.junit.After;
@@ -45,20 +43,29 @@
 public class ONSProfileConfiguratorTest extends ONSBaseTest {
     private static final String TAG = ONSProfileConfiguratorTest.class.getName();
     private static final int TEST_SUB_ID = 1;
-    @Mock SubscriptionManager mMockSubManager;
-    @Mock SubscriptionInfo mMockSubscriptionInfo1;
-    @Mock SubscriptionInfo mMockSubscriptionInfo2;
-    @Mock EuiccManager mMockEuiccMngr;
-    @Mock TelephonyManager mMockTelephonyManager;
-    @Mock CarrierConfigManager mMockCarrierConfigManager;
-    @Mock private Context mMockContext;
-    @Mock private ONSProfileActivator mMockONSProfileActivator;
-    @Mock private ONSProfileConfigurator.ONSProfConfigListener mMockConfigListener;
+    @Mock
+    SubscriptionManager mMockSubManager;
+    @Mock
+    SubscriptionInfo mMockSubscriptionInfo1;
+    @Mock
+    SubscriptionInfo mMockSubscriptionInfo2;
+    @Mock
+    EuiccManager mMockEuiccMngr;
+    @Mock
+    EuiccManager mMockEuiccMngrCard1;
+    @Mock
+    EuiccManager mMockEuiccMngrCard2;
+    @Mock
+    CarrierConfigManager mMockCarrierConfigManager;
+    @Mock
+    private ONSProfileConfigurator.ONSProfConfigListener mMockConfigListener;
 
     @Before
     public void setUp() throws Exception {
         super.setUp("ONSTest");
         MockitoAnnotations.initMocks(this);
+        doReturn(mMockEuiccMngrCard1).when(mMockEuiccMngr).createForCardId(1);
+        doReturn(mMockEuiccMngrCard2).when(mMockEuiccMngr).createForCardId(2);
         Looper.prepare();
     }
 
@@ -130,8 +137,19 @@
                         intent,
                         PendingIntent.FLAG_IMMUTABLE);
 
+        ArrayList<SubscriptionInfo> activeSubInfos = new ArrayList<>();
+
+        doReturn(1).when(mMockSubscriptionInfo1).getSubscriptionId();
+        doReturn(1).when(mMockSubscriptionInfo1).getCardId();
+        activeSubInfos.add(mMockSubscriptionInfo1);
+
+        doReturn(2).when(mMockSubscriptionInfo2).getSubscriptionId();
+        doReturn(2).when(mMockSubscriptionInfo2).getCardId();
+        activeSubInfos.add(mMockSubscriptionInfo2);
+        doReturn(activeSubInfos).when(mMockSubManager).getAvailableSubscriptionInfoList();
+
         mOnsProfileConfigurator.activateSubscription(TEST_SUB_ID);
-        verify(mMockEuiccMngr).switchToSubscription(TEST_SUB_ID, callbackIntent);
+        verify(mMockEuiccMngrCard1).switchToSubscription(TEST_SUB_ID, callbackIntent);
     }
 
     @Test
@@ -155,15 +173,18 @@
                 mMockSubManager, mMockCarrierConfigManager, mMockEuiccMngr, mMockConfigListener);
 
         doReturn(1).when(mMockSubscriptionInfo1).getSubscriptionId();
+        doReturn(1).when(mMockSubscriptionInfo1).getCardId();
         doReturn(true).when(mMockSubManager).isActiveSubscriptionId(1);
 
         doReturn(2).when(mMockSubscriptionInfo2).getSubscriptionId();
+        doReturn(2).when(mMockSubscriptionInfo2).getCardId();
         doReturn(false).when(mMockSubManager).isActiveSubscriptionId(2);
 
         ArrayList<SubscriptionInfo> oppSubList = new ArrayList<>();
         oppSubList.add(mMockSubscriptionInfo1);
         oppSubList.add(mMockSubscriptionInfo2);
         doReturn(oppSubList).when(mMockSubManager).getOpportunisticSubscriptions();
+        doReturn(oppSubList).when(mMockSubManager).getAvailableSubscriptionInfoList();
 
         Intent intent = new Intent(mContext, ONSProfileResultReceiver.class);
         intent.setAction(ONSProfileConfigurator.ACTION_ONS_ESIM_CONFIG);
@@ -179,8 +200,8 @@
                         PendingIntent.FLAG_MUTABLE);
 
         boolean res = mOnsProfileConfigurator.deleteInactiveOpportunisticSubscriptions(2);
-        verify(mMockEuiccMngr).deleteSubscription(2, callbackIntent2);
-        verifyNoMoreInteractions(mMockEuiccMngr);
+        verify(mMockEuiccMngrCard2).deleteSubscription(2, callbackIntent2);
+        verifyNoMoreInteractions(mMockEuiccMngrCard2);
         //verify(mMockEuiccManager).deleteSubscription(2, callbackIntent2);
         // verify(mOnsProfileConfigurator).deleteOldOpportunisticESimsOfPSIMOperator(TEST_SUB_ID);
         assertEquals(res, true);
diff --git a/tests/src/com/android/ons/ONSProfileDownloaderTest.java b/tests/src/com/android/ons/ONSProfileDownloaderTest.java
index e82df6a..e8a0912 100644
--- a/tests/src/com/android/ons/ONSProfileDownloaderTest.java
+++ b/tests/src/com/android/ons/ONSProfileDownloaderTest.java
@@ -31,6 +31,7 @@
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.telephony.euicc.DownloadableSubscription;
 import android.telephony.euicc.EuiccManager;
 import android.util.Log;
@@ -47,12 +48,17 @@
 public class ONSProfileDownloaderTest extends ONSBaseTest {
     private static final String TAG = ONSProfileDownloaderTest.class.getName();
     private static final int TEST_SUB_ID = 1;
+    private static final int TEST_EUICC_CARD_ID = 1;
     private static final String TEST_SMDP_ADDRESS = "TEST-ESIM.COM";
 
     @Mock
     Context mMockContext;
     @Mock
-    EuiccManager mMockEUICCManager;
+    EuiccManager mMockEuiccManager;
+    @Mock
+    EuiccManager mMockEuiccManagerForCard1;
+    @Mock
+    SubscriptionManager mMockSubManager;
     @Mock
     SubscriptionInfo mMockSubInfo;
     @Mock
@@ -97,13 +103,16 @@
         PersistableBundle config = new PersistableBundle();
         config.putString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING, null);
         doReturn(config).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUB_ID);
+        doReturn(mMockSubInfo).when(mMockSubManager).getActiveSubscriptionInfo(TEST_SUB_ID);
+        doReturn(false).when(mMockSubInfo).isEmbedded();
 
         ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mMockContext,
-                mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig, null);
+                mMockCarrierConfigManager, mMockEuiccManager, mMockSubManager,
+                mMockONSProfileConfig, null);
 
         onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId());
 
-        verify(mMockEUICCManager, never()).downloadSubscription(null, true, null);
+        verify(mMockEuiccManager, never()).downloadSubscription(null, true, null);
     }
 
     @Test
@@ -132,9 +141,12 @@
         Runnable runnable = new Runnable() {
             @Override
             public void run() {
+                doReturn(mMockSubInfo).when(mMockSubManager).getActiveSubscriptionInfo(TEST_SUB_ID);
+                doReturn(false).when(mMockSubInfo).isEmbedded();
+
                 ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mMockContext,
-                        mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig,
-                        mListener);
+                        mMockCarrierConfigManager, mMockEuiccManager, mMockSubManager,
+                        mMockONSProfileConfig, mListener);
 
                 Intent intent = new Intent(mContext, ONSProfileResultReceiver.class);
                 intent.setAction(ONSProfileDownloader.ACTION_ONS_ESIM_DOWNLOAD);
@@ -174,9 +186,12 @@
         Runnable runnable = new Runnable() {
             @Override
             public void run() {
+                doReturn(mMockSubInfo).when(mMockSubManager).getActiveSubscriptionInfo(TEST_SUB_ID);
+                doReturn(false).when(mMockSubInfo).isEmbedded();
+
                 ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mMockContext,
-                        mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig,
-                        mMockDownloadListener);
+                        mMockCarrierConfigManager, mMockEuiccManager, mMockSubManager,
+                        mMockONSProfileConfig, mMockDownloadListener);
 
                 Intent intent = new Intent(mContext, ONSProfileResultReceiver.class);
                 intent.setAction(ONSProfileDownloader.ACTION_ONS_ESIM_DOWNLOAD);
@@ -199,7 +214,7 @@
             e.printStackTrace();
         }
 
-        verifyZeroInteractions(mMockEUICCManager);
+        verifyZeroInteractions(mMockEuiccManager);
         workerThread.exit();
     }
 
@@ -209,9 +224,12 @@
         Runnable runnable = new Runnable() {
             @Override
             public void run() {
+                doReturn(mMockSubInfo).when(mMockSubManager).getActiveSubscriptionInfo(TEST_SUB_ID);
+                doReturn(false).when(mMockSubInfo).isEmbedded();
+
                 ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mMockContext,
-                        mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig,
-                        mMockDownloadListener);
+                        mMockCarrierConfigManager, mMockEuiccManager, mMockSubManager,
+                        mMockONSProfileConfig, mMockDownloadListener);
 
                 Intent intent = new Intent(mContext, ONSProfileResultReceiver.class);
                 intent.setAction(ONSProfileDownloader.ACTION_ONS_ESIM_DOWNLOAD);
@@ -256,9 +274,12 @@
         Runnable runnable = new Runnable() {
             @Override
             public void run() {
+                doReturn(mMockSubInfo).when(mMockSubManager).getActiveSubscriptionInfo(TEST_SUB_ID);
+                doReturn(false).when(mMockSubInfo).isEmbedded();
+
                 ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mContext,
-                        mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig,
-                        mMockDownloadListener);
+                        mMockCarrierConfigManager, mMockEuiccManager, mMockSubManager,
+                        mMockONSProfileConfig, mMockDownloadListener);
 
                 Intent intent = new Intent(mContext, ONSProfileResultReceiver.class);
                 intent.setAction(ONSProfileDownloader.ACTION_ONS_ESIM_DOWNLOAD);
@@ -310,9 +331,12 @@
         Runnable runnable = new Runnable() {
             @Override
             public void run() {
+                doReturn(mMockSubInfo).when(mMockSubManager).getActiveSubscriptionInfo(TEST_SUB_ID);
+                doReturn(false).when(mMockSubInfo).isEmbedded();
+
                 ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mContext,
-                        mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig,
-                        mMockDownloadListener);
+                        mMockCarrierConfigManager, mMockEuiccManager, mMockSubManager,
+                        mMockONSProfileConfig, mMockDownloadListener);
 
                 Intent intent = new Intent(mContext, ONSProfileResultReceiver.class);
                 intent.setAction(ONSProfileDownloader.ACTION_ONS_ESIM_DOWNLOAD);
@@ -364,9 +388,12 @@
         Runnable runnable = new Runnable() {
             @Override
             public void run() {
+                doReturn(mMockSubInfo).when(mMockSubManager).getActiveSubscriptionInfo(TEST_SUB_ID);
+                doReturn(false).when(mMockSubInfo).isEmbedded();
+
                 ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mContext,
-                        mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig,
-                        mMockDownloadListener);
+                        mMockCarrierConfigManager, mMockEuiccManager, mMockSubManager,
+                        mMockONSProfileConfig, mMockDownloadListener);
 
                 Intent intent = new Intent(mContext, ONSProfileResultReceiver.class);
                 intent.setAction(ONSProfileDownloader.ACTION_ONS_ESIM_DOWNLOAD);
@@ -418,9 +445,12 @@
         Runnable runnable = new Runnable() {
             @Override
             public void run() {
+                doReturn(mMockSubInfo).when(mMockSubManager).getActiveSubscriptionInfo(TEST_SUB_ID);
+                doReturn(false).when(mMockSubInfo).isEmbedded();
+
                 ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mContext,
-                        mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig,
-                        mMockDownloadListener);
+                        mMockCarrierConfigManager, mMockEuiccManager, mMockSubManager,
+                        mMockONSProfileConfig, mMockDownloadListener);
 
                 Intent intent = new Intent(mContext, ONSProfileResultReceiver.class);
                 intent.setAction(ONSProfileDownloader.ACTION_ONS_ESIM_DOWNLOAD);
@@ -459,9 +489,12 @@
         Runnable runnable = new Runnable() {
             @Override
             public void run() {
+                doReturn(mMockSubInfo).when(mMockSubManager).getActiveSubscriptionInfo(TEST_SUB_ID);
+                doReturn(false).when(mMockSubInfo).isEmbedded();
+
                 ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mMockContext,
-                        mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig,
-                        mMockDownloadListener);
+                        mMockCarrierConfigManager, mMockEuiccManager, mMockSubManager,
+                        mMockONSProfileConfig, mMockDownloadListener);
 
                 ONSProfileDownloader.DownloadHandler downloadHandler =
                         onsProfileDownloader.new DownloadHandler();
@@ -598,17 +631,19 @@
         PersistableBundle config = new PersistableBundle();
         config.putString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING, TEST_SMDP_ADDRESS);
         doReturn(config).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUB_ID);
+        doReturn(mMockSubInfo).when(mMockSubManager).getActiveSubscriptionInfo(TEST_SUB_ID);
+        doReturn(false).when(mMockSubInfo).isEmbedded();
 
         ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mContext,
-                mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig,
-                mMockDownloadListener);
+                mMockCarrierConfigManager, mMockEuiccManager, mMockSubManager,
+                mMockONSProfileConfig, mMockDownloadListener);
 
         //When multiple download requests are received, download should be triggered only once.
         onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId());
         onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId());
         onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId());
         onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId());
-        verify(mMockEUICCManager, times(1)).downloadSubscription(any(), eq(true), any());
+        verify(mMockEuiccManager, times(1)).downloadSubscription(any(), eq(true), any());
 
         //Simulate response for download request from LPA.
         Intent intent = new Intent(mContext, ONSProfileResultReceiver.class);
@@ -635,12 +670,15 @@
         onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId());
         onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId());
         onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId());
-        verify(mMockEUICCManager, times(1)).downloadSubscription(any(), eq(true), any());
+        verify(mMockEuiccManager, times(1)).downloadSubscription(any(), eq(true), any());
     }
 
     @Test
     public void testDownloadRequestFailures() {
         doReturn(TEST_SUB_ID).when(mMockSubInfo).getSubscriptionId();
+        doReturn(mMockSubInfo).when(mMockSubManager).getActiveSubscriptionInfo(TEST_SUB_ID);
+        doReturn(false).when(mMockSubInfo).isEmbedded();
+
         PersistableBundle invalidConfig = new PersistableBundle();
         invalidConfig.putString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING, "");
 
@@ -653,13 +691,9 @@
                 .when(mMockCarrierConfigManager)
                 .getConfigForSubId(TEST_SUB_ID);
 
-        ONSProfileDownloader onsProfileDownloader =
-                new ONSProfileDownloader(
-                        mContext,
-                        mMockCarrierConfigManager,
-                        mMockEUICCManager,
-                        mMockONSProfileConfig,
-                        mMockDownloadListener);
+        ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mContext,
+                mMockCarrierConfigManager, mMockEuiccManager, mMockSubManager,
+                mMockONSProfileConfig, mMockDownloadListener);
 
         // First download request to be failed with INVALID_SMDP_ADDRESS error because of empty SMDP
         // server address in configuration.
@@ -667,12 +701,12 @@
                 onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId());
         assertEquals(DownloadProfileResult.INVALID_SMDP_ADDRESS, retryResultCode);
 
-        verify(mMockEUICCManager, never()).downloadSubscription(any(), eq(true), any());
+        verify(mMockEuiccManager, never()).downloadSubscription(any(), eq(true), any());
 
         // Second Download request should be success and processed to EuiccManager.
         retryResultCode = onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId());
         assertEquals(DownloadProfileResult.SUCCESS, retryResultCode);
-        verify(mMockEUICCManager).downloadSubscription(any(), eq(true), any());
+        verify(mMockEuiccManager).downloadSubscription(any(), eq(true), any());
 
         // Since download request is in progress, no further request to be sent to EuiccManager.
         // They should return with DUPLICATE_REQUEST error.
@@ -682,7 +716,33 @@
         retryResultCode = onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId());
         assertEquals(DownloadProfileResult.DUPLICATE_REQUEST, retryResultCode);
 
-        verify(mMockEUICCManager).downloadSubscription(any(), eq(true), any());
+        verify(mMockEuiccManager).downloadSubscription(any(), eq(true), any());
+    }
+
+    @Test
+    public void testDownloadRequestWithPrimaryESim() {
+        doReturn(TEST_SUB_ID).when(mMockSubInfo).getSubscriptionId();
+        doReturn(TEST_SUB_ID).when(mMockSubInfo).getCardId();
+        doReturn(true).when(mMockSubInfo).isEmbedded();
+        doReturn(mMockEuiccManagerForCard1).when(mMockEuiccManager)
+                .createForCardId(TEST_EUICC_CARD_ID);
+        PersistableBundle config = new PersistableBundle();
+        config.putInt(CarrierConfigManager.KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT, 1);
+        config.putInt(CarrierConfigManager.KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT, 2);
+        config.putString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING, TEST_SMDP_ADDRESS);
+        doReturn(config).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUB_ID);
+
+        // Check null subscription info - eSIM case
+        doReturn(null).when(mMockSubManager).getActiveSubscriptionInfo(TEST_SUB_ID);
+        verify(mMockEuiccManagerForCard1, never()).downloadSubscription(any(), eq(true), any());
+
+        doReturn(mMockSubInfo).when(mMockSubManager).getActiveSubscriptionInfo(TEST_SUB_ID);
+        ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mContext,
+                mMockCarrierConfigManager, mMockEuiccManager, mMockSubManager,
+                mMockONSProfileConfig, mMockDownloadListener);
+
+        onsProfileDownloader.downloadProfile(TEST_SUB_ID);
+        verify(mMockEuiccManagerForCard1, times(1)).downloadSubscription(any(), eq(true), any());
     }
 
     @After