Support multi-sim in mms service

Also fixed bug related to LINE1 macro in mms config b/17945978

b/16681645
b/17945978

Change-Id: I79e33d6f1b72f18fb7a12afef903ef96e98ce052
diff --git a/res/xml-mcc310-mnc004/mms_config.xml b/res/xml-mcc310-mnc004/mms_config.xml
index f0615f7..346218b 100644
--- a/res/xml-mcc310-mnc004/mms_config.xml
+++ b/res/xml-mcc310-mnc004/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-up-calling-line-id: 1##LINE1##|X-VzW-MDN: 1##LINE1##</string>
+    <string name="httpParams">x-up-calling-line-id: 1##LINE1NOCOUNTRYCODE##|X-VzW-MDN: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc310-mnc005/mms_config.xml b/res/xml-mcc310-mnc005/mms_config.xml
index f0615f7..346218b 100644
--- a/res/xml-mcc310-mnc005/mms_config.xml
+++ b/res/xml-mcc310-mnc005/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-up-calling-line-id: 1##LINE1##|X-VzW-MDN: 1##LINE1##</string>
+    <string name="httpParams">x-up-calling-line-id: 1##LINE1NOCOUNTRYCODE##|X-VzW-MDN: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc012/mms_config.xml b/res/xml-mcc311-mnc012/mms_config.xml
index f0615f7..346218b 100644
--- a/res/xml-mcc311-mnc012/mms_config.xml
+++ b/res/xml-mcc311-mnc012/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-up-calling-line-id: 1##LINE1##|X-VzW-MDN: 1##LINE1##</string>
+    <string name="httpParams">x-up-calling-line-id: 1##LINE1NOCOUNTRYCODE##|X-VzW-MDN: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc220/mms_config.xml b/res/xml-mcc311-mnc220/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc220/mms_config.xml
+++ b/res/xml-mcc311-mnc220/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc221/mms_config.xml b/res/xml-mcc311-mnc221/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc221/mms_config.xml
+++ b/res/xml-mcc311-mnc221/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc222/mms_config.xml b/res/xml-mcc311-mnc222/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc222/mms_config.xml
+++ b/res/xml-mcc311-mnc222/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc223/mms_config.xml b/res/xml-mcc311-mnc223/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc223/mms_config.xml
+++ b/res/xml-mcc311-mnc223/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc224/mms_config.xml b/res/xml-mcc311-mnc224/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc224/mms_config.xml
+++ b/res/xml-mcc311-mnc224/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc225/mms_config.xml b/res/xml-mcc311-mnc225/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc225/mms_config.xml
+++ b/res/xml-mcc311-mnc225/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc226/mms_config.xml b/res/xml-mcc311-mnc226/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc226/mms_config.xml
+++ b/res/xml-mcc311-mnc226/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc227/mms_config.xml b/res/xml-mcc311-mnc227/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc227/mms_config.xml
+++ b/res/xml-mcc311-mnc227/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc228/mms_config.xml b/res/xml-mcc311-mnc228/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc228/mms_config.xml
+++ b/res/xml-mcc311-mnc228/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc229/mms_config.xml b/res/xml-mcc311-mnc229/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc229/mms_config.xml
+++ b/res/xml-mcc311-mnc229/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc230/mms_config.xml b/res/xml-mcc311-mnc230/mms_config.xml
index 3a81c58..b82f1d6 100755
--- a/res/xml-mcc311-mnc230/mms_config.xml
+++ b/res/xml-mcc311-mnc230/mms_config.xml
@@ -90,6 +90,6 @@
     <bool name="enableMMSDeliveryReports">false</bool>
 
     <!-- Reference for additional http parameters used in MMS http request. -->
-    <string name="httpParams">X-CS3G-MDN: 1##LINE1##</string>
+    <string name="httpParams">X-CS3G-MDN: 1##LINE1NOCOUNTRYCODE##</string>
 
 </mms_config>
diff --git a/res/xml-mcc311-mnc480/mms_config.xml b/res/xml-mcc311-mnc480/mms_config.xml
index cd9f0c7..1929b6a 100644
--- a/res/xml-mcc311-mnc480/mms_config.xml
+++ b/res/xml-mcc311-mnc480/mms_config.xml
@@ -22,7 +22,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-up-calling-line-id: 1##LINE1##|X-VzW-MDN: 1##LINE1##</string>
+    <string name="httpParams">x-up-calling-line-id: 1##LINE1NOCOUNTRYCODE##|X-VzW-MDN: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc580/mms_config.xml b/res/xml-mcc311-mnc580/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc580/mms_config.xml
+++ b/res/xml-mcc311-mnc580/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc581/mms_config.xml b/res/xml-mcc311-mnc581/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc581/mms_config.xml
+++ b/res/xml-mcc311-mnc581/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc582/mms_config.xml b/res/xml-mcc311-mnc582/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc582/mms_config.xml
+++ b/res/xml-mcc311-mnc582/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc583/mms_config.xml b/res/xml-mcc311-mnc583/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc583/mms_config.xml
+++ b/res/xml-mcc311-mnc583/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc584/mms_config.xml b/res/xml-mcc311-mnc584/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc584/mms_config.xml
+++ b/res/xml-mcc311-mnc584/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc585/mms_config.xml b/res/xml-mcc311-mnc585/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc585/mms_config.xml
+++ b/res/xml-mcc311-mnc585/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc586/mms_config.xml b/res/xml-mcc311-mnc586/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc586/mms_config.xml
+++ b/res/xml-mcc311-mnc586/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc587/mms_config.xml b/res/xml-mcc311-mnc587/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc587/mms_config.xml
+++ b/res/xml-mcc311-mnc587/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc588/mms_config.xml b/res/xml-mcc311-mnc588/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc588/mms_config.xml
+++ b/res/xml-mcc311-mnc588/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc311-mnc589/mms_config.xml b/res/xml-mcc311-mnc589/mms_config.xml
index a3613f0..196d4f7 100644
--- a/res/xml-mcc311-mnc589/mms_config.xml
+++ b/res/xml-mcc311-mnc589/mms_config.xml
@@ -35,7 +35,7 @@
 
     <!-- Additional http parameters used in MMS http request.
          Parameters are seperated by '|'. Optional. -->
-    <string name="httpParams">x-vzw-mdn: 1##LINE1##</string>
+    <string name="httpParams">x-vzw-mdn: 1##LINE1NOCOUNTRYCODE##</string>
 
     <!-- Maximum height for an attached image -->
     <int name="maxImageHeight">1944</int>
diff --git a/res/xml-mcc312-mnc530/mms_config.xml b/res/xml-mcc312-mnc530/mms_config.xml
index 8c1ae11..7b1b093 100755
--- a/res/xml-mcc312-mnc530/mms_config.xml
+++ b/res/xml-mcc312-mnc530/mms_config.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2013 The Android Open Source Project
+<!-- Copyright 2014 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<mms_config version="4">
+<mms_config version="1">
     <!-- Flag indicating whether MMS should be enabled -->
     <bool name="enabledMMS">true</bool>
 
diff --git a/src/com/android/mms/service/DownloadRequest.java b/src/com/android/mms/service/DownloadRequest.java
index 3805d1c..4300694 100644
--- a/src/com/android/mms/service/DownloadRequest.java
+++ b/src/com/android/mms/service/DownloadRequest.java
@@ -87,7 +87,7 @@
     }
 
     @Override
-    protected int getRunningQueue() {
+    protected int getQueueType() {
         return MmsService.QUEUE_INDEX_DOWNLOAD;
     }
 
@@ -188,7 +188,7 @@
                 intent);
 
         if (carrierPackages == null || carrierPackages.size() != 1) {
-            mRequestManager.addRunning(this);
+            mRequestManager.addSimRequest(this);
         } else {
             intent.setPackage(carrierPackages.get(0));
             intent.putExtra(Telephony.Mms.Intents.EXTRA_MMS_LOCATION_URL, mLocationUrl);
diff --git a/src/com/android/mms/service/MmsConfig.java b/src/com/android/mms/service/MmsConfig.java
index 5e692d9..5777e40 100755
--- a/src/com/android/mms/service/MmsConfig.java
+++ b/src/com/android/mms/service/MmsConfig.java
@@ -16,11 +16,10 @@
 
 package com.android.mms.service;
 
-import android.content.ContentValues;
 import android.content.Context;
 import android.content.res.XmlResourceParser;
 import android.os.Bundle;
-import android.os.SystemProperties;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Base64;
@@ -133,6 +132,8 @@
      */
     // The raw phone number from TelephonyManager.getLine1Number
     public static final String MACRO_LINE1 = "LINE1";
+    // The phone number without country code
+    public static final String MACRO_LINE1NOCOUNTRYCODE = "LINE1NOCOUNTRYCODE";
     // NAI (Network Access Identifier), used by Sprint for authentication
     public static final String MACRO_NAI = "NAI";
 
@@ -499,9 +500,11 @@
          */
         public String getHttpParamMacro(Context context, String macro) {
             if (MACRO_LINE1.equals(macro)) {
-                return getLine1(context);
+                return getLine1(context, mBase.getSubId());
+            } else if (MACRO_LINE1NOCOUNTRYCODE.equals(macro)) {
+                return getLine1NoCountryCode(context, mBase.getSubId());
             } else if (MACRO_NAI.equals(macro)) {
-                return getNai(context);
+                return getNai(context, mBase.getSubId());
             }
             return null;
         }
@@ -509,22 +512,30 @@
         /**
          * @return the phone number
          */
-        private static String getLine1(Context context) {
-            // TODO: for MSIM, we will need to pass in the subId
+        private static String getLine1(Context context, int subId) {
             final TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
                     Context.TELEPHONY_SERVICE);
-            return telephonyManager.getLine1Number();
+            return telephonyManager.getLine1NumberForSubscriber(subId);
+        }
+
+        private static String getLine1NoCountryCode(Context context, int subId) {
+            final TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
+                    Context.TELEPHONY_SERVICE);
+            return PhoneUtils.getNationalNumber(
+                    telephonyManager,
+                    subId,
+                    telephonyManager.getLine1NumberForSubscriber(subId));
         }
 
         /**
          * @return the NAI (Network Access Identifier) from SystemProperties
          */
-        private String getNai(Context context) {
+        private String getNai(Context context, int subId) {
             final TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
                     Context.TELEPHONY_SERVICE);
-            String nai = telephonyManager.getNai();
+            String nai = telephonyManager.getNai(SubscriptionManager.getSlotId(subId));
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                Log.v(TAG, "MmsConfig:Nai=" + nai);
+                Log.v(TAG, "MmsConfig.getNai: nai=" + nai);
             }
 
             if (!TextUtils.isEmpty(nai)) {
diff --git a/src/com/android/mms/service/MmsNetworkManager.java b/src/com/android/mms/service/MmsNetworkManager.java
index a9c5eca..36a17ea 100644
--- a/src/com/android/mms/service/MmsNetworkManager.java
+++ b/src/com/android/mms/service/MmsNetworkManager.java
@@ -51,7 +51,8 @@
     private static final long httpKeepAliveDurationMs =
             Long.parseLong(System.getProperty("http.keepAliveDuration", "300000"));  // 5 minutes.
 
-    private Context mContext;
+    private final Context mContext;
+
     // The requested MMS {@link android.net.Network} we are holding
     // We need this when we unbind from it. This is also used to indicate if the
     // MMS network is available.
@@ -59,13 +60,8 @@
     // The current count of MMS requests that require the MMS network
     // If mMmsRequestCount is 0, we should release the MMS network.
     private int mMmsRequestCount;
-
     // This is really just for using the capability
-    private NetworkRequest mNetworkRequest = new NetworkRequest.Builder()
-            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-            .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS)
-            .build();
-
+    private final NetworkRequest mNetworkRequest;
     // The callback to register when we request MMS network
     private ConnectivityManager.NetworkCallback mNetworkCallback;
 
@@ -77,8 +73,10 @@
     // The MMS HTTP client for this network
     private MmsHttpClient mMmsHttpClient;
 
-    // TODO: we need to re-architect this when we support MSIM, like maybe one manager for each SIM?
-    public MmsNetworkManager(Context context) {
+    // The SIM ID which we use to connect
+    private final int mSubId;
+
+    public MmsNetworkManager(Context context, int subId) {
         mContext = context;
         mNetworkCallback = null;
         mNetwork = null;
@@ -86,6 +84,12 @@
         mConnectivityManager = null;
         mConnectionPool = null;
         mMmsHttpClient = null;
+        mSubId = subId;
+        mNetworkRequest = new NetworkRequest.Builder()
+                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS)
+                .setNetworkSpecifier(Integer.toString(mSubId))
+                .build();
     }
 
     /**
diff --git a/src/com/android/mms/service/MmsRequest.java b/src/com/android/mms/service/MmsRequest.java
index adaf083..82f1485 100644
--- a/src/com/android/mms/service/MmsRequest.java
+++ b/src/com/android/mms/service/MmsRequest.java
@@ -44,19 +44,19 @@
      */
     public static interface RequestManager {
         /**
-         * Add a request to pending queue when it is executed by carrier app
+         * Add a request to be executed by carrier app
          *
          * @param key The message ref key from carrier app
          * @param request The request in pending
          */
-        public void addPending(int key, MmsRequest request);
+        public void addCarrierAppRequest(int key, MmsRequest request);
 
         /**
-         * Enqueue an MMS request for running
+         * Enqueue an MMS request
          *
          * @param request the request to enqueue
          */
-        public void addRunning(MmsRequest request);
+        public void addSimRequest(MmsRequest request);
 
         /*
          * @return Whether to auto persist received MMS
@@ -109,7 +109,7 @@
                     if (resultExtras != null && resultExtras.containsKey(EXTRA_MESSAGE_REF)) {
                         final int ref = resultExtras.getInt(EXTRA_MESSAGE_REF);
                         Log.d(MmsService.TAG, "messageref = " + ref);
-                        mRequestManager.addPending(ref, MmsRequest.this);
+                        mRequestManager.addCarrierAppRequest(ref, MmsRequest.this);
                     } else {
                         // Bad, no message ref provided
                         Log.e(MmsService.TAG, "Can't find messageref in result extras.");
@@ -117,7 +117,7 @@
                 } else {
                     // No carrier app present, sending normally
                     Log.d(MmsService.TAG, "Sending/downloading MMS by IP failed.");
-                    mRequestManager.addRunning(MmsRequest.this);
+                    mRequestManager.addSimRequest(MmsRequest.this);
                 }
             } else {
                 Log.e(MmsService.TAG, "unexpected BroadcastReceiver action: " + action);
@@ -136,6 +136,10 @@
         mMmsConfig = null;
     }
 
+    public int getSubId() {
+        return mSubId;
+    }
+
     private boolean ensureMmsConfigLoaded() {
         if (mMmsConfig == null) {
             // Not yet retrieved from mms config manager. Try getting it.
@@ -262,9 +266,9 @@
     protected abstract PendingIntent getPendingIntent();
 
     /**
-     * @return The running queue should be used by this request
+     * @return The queue should be used by this request, 0 is sending and 1 is downloading
      */
-    protected abstract int getRunningQueue();
+    protected abstract int getQueueType();
 
     /**
      * Update database status of the message represented by this request
diff --git a/src/com/android/mms/service/MmsService.java b/src/com/android/mms/service/MmsService.java
index 602bac1..e4332e4 100644
--- a/src/com/android/mms/service/MmsService.java
+++ b/src/com/android/mms/service/MmsService.java
@@ -16,21 +16,6 @@
 
 package com.android.mms.service;
 
-import com.google.android.mms.MmsException;
-import com.google.android.mms.pdu.DeliveryInd;
-import com.google.android.mms.pdu.GenericPdu;
-import com.google.android.mms.pdu.NotificationInd;
-import com.google.android.mms.pdu.PduComposer;
-import com.google.android.mms.pdu.PduParser;
-import com.google.android.mms.pdu.PduPersister;
-import com.google.android.mms.pdu.ReadOrigInd;
-import com.google.android.mms.pdu.RetrieveConf;
-import com.google.android.mms.pdu.SendReq;
-import com.google.android.mms.util.SqliteWrapper;
-
-import com.android.internal.telephony.IMms;
-import com.android.internal.telephony.SmsApplication;
-
 import android.app.PendingIntent;
 import android.app.Service;
 import android.content.ContentResolver;
@@ -47,17 +32,35 @@
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
-import android.os.Message;
 import android.os.RemoteException;
 import android.provider.Telephony;
 import android.telephony.SmsManager;
+import android.telephony.SubscriptionManager;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.telephony.IMms;
+import com.android.internal.telephony.SmsApplication;
+import com.google.android.mms.MmsException;
+import com.google.android.mms.pdu.DeliveryInd;
+import com.google.android.mms.pdu.GenericPdu;
+import com.google.android.mms.pdu.NotificationInd;
+import com.google.android.mms.pdu.PduComposer;
+import com.google.android.mms.pdu.PduParser;
+import com.google.android.mms.pdu.PduPersister;
+import com.google.android.mms.pdu.ReadOrigInd;
+import com.google.android.mms.pdu.RetrieveConf;
+import com.google.android.mms.pdu.SendReq;
+import com.google.android.mms.util.SqliteWrapper;
 
 import java.io.IOException;
+import java.util.ArrayDeque;
 import java.util.Arrays;
+import java.util.Queue;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutorService;
@@ -86,14 +89,32 @@
 
     // Pending requests that are currently executed by carrier app
     // TODO: persist this in case MmsService crashes
-    private final ConcurrentHashMap<Integer, MmsRequest> mPendingRequests =
-            new ConcurrentHashMap<Integer, MmsRequest>();
+    private final ConcurrentHashMap<Integer, MmsRequest> mPendingCarrierAppRequests =
+            new ConcurrentHashMap<>();
+
+    // Pending requests that are waiting for the SIM to be available
+    // If a different SIM is currently used by previous requests, the following
+    // requests will stay in this queue until that SIM finishes its current requests in
+    // RequestQueue.
+    // Requests are not reordered. So, e.g. if current SIM is SIM1, a request for SIM2 will be
+    // blocked in the queue. And a later request for SIM1 will be appended to the queue, ordered
+    // after the request for SIM2, instead of being put into the running queue.
+    // TODO: persist this in case MmsService crashes
+    private final Queue<MmsRequest> mPendingSimRequestQueue = new ArrayDeque<>();
 
     private final ExecutorService mExecutor = Executors.newCachedThreadPool();
 
+    // A cache of MmsNetworkManager for SIMs
+    private final SparseArray<MmsNetworkManager> mNetworkManagerCache = new SparseArray<>();
+
+    // The current SIM ID for the running requests. Only one SIM can send/download MMS at a time.
+    private int mCurrentSubId;
+    // The current running MmsRequest count.
+    private int mRunningRequestCount;
+
     @Override
-    public void addPending(int key, MmsRequest request) {
-        mPendingRequests.put(key, request);
+    public void addCarrierAppRequest(int key, MmsRequest request) {
+        mPendingCarrierAppRequests.put(key, request);
     }
 
     /**
@@ -108,17 +129,49 @@
         public void handleMessage(Message msg) {
             final MmsRequest request = (MmsRequest) msg.obj;
             if (request != null) {
-                request.execute(MmsService.this, mMmsNetworkManager);
+                try {
+                    request.execute(MmsService.this, getNetworkManager(request.getSubId()));
+                } finally {
+                    synchronized (MmsService.this) {
+                        mRunningRequestCount--;
+                        if (mRunningRequestCount <= 0) {
+                            movePendingSimRequestsToRunningSynchronized();
+                        }
+                    }
+                }
+            } else {
+                Log.e(TAG, "RequestQueue: handling empty request");
             }
         }
     }
 
+    private MmsNetworkManager getNetworkManager(int subId) {
+        synchronized (mNetworkManagerCache) {
+            MmsNetworkManager manager = mNetworkManagerCache.get(subId);
+            if (manager == null) {
+                manager = new MmsNetworkManager(this, subId);
+                mNetworkManagerCache.put(subId, manager);
+            }
+            return manager;
+        }
+    }
+
     private void enforceSystemUid() {
         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
             throw new SecurityException("Only system can call this service");
         }
     }
 
+    private int checkSubId(int subId) {
+        if (!SubscriptionManager.isValidSubId(subId)) {
+            throw new RuntimeException("Invalid subId " + subId);
+        }
+        if (subId == SubscriptionManager.DEFAULT_SUB_ID) {
+            return SubscriptionManager.getDefaultSmsSubId();
+        }
+        return subId;
+    }
+
     private IMms.Stub mStub = new IMms.Stub() {
         @Override
         public void sendMessage(int subId, String callingPkg, Uri contentUri,
@@ -126,6 +179,8 @@
                         throws RemoteException {
             Log.d(TAG, "sendMessage");
             enforceSystemUid();
+            // Make sure the subId is correct
+            subId = checkSubId(subId);
             final SendRequest request = new SendRequest(MmsService.this, subId, contentUri,
                     null/*messageUri*/, locationUrl, sentIntent, callingPkg, configOverrides);
             if (SmsApplication.shouldWriteMessageForPackage(callingPkg, MmsService.this)) {
@@ -142,6 +197,8 @@
                 PendingIntent downloadedIntent) throws RemoteException {
             Log.d(TAG, "downloadMessage: " + locationUrl);
             enforceSystemUid();
+            // Make sure the subId is correct
+            subId = checkSubId(subId);
             final DownloadRequest request = new DownloadRequest(MmsService.this, subId,
                     locationUrl, contentUri, downloadedIntent, callingPkg, configOverrides);
             // Try downloading via carrier app
@@ -153,14 +210,14 @@
             Log.d(TAG, "updateMmsSendStatus: ref=" + messageRef
                     + ", pdu=" + (pdu == null ? null : pdu.length) + ", status=" + status);
             enforceSystemUid();
-            final MmsRequest request = mPendingRequests.get(messageRef);
+            final MmsRequest request = mPendingCarrierAppRequests.remove(messageRef);
             if (request != null) {
                 if (status != SmsManager.MMS_ERROR_RETRY) {
                     // Sent completed (maybe success or fail) by carrier app, finalize the request.
                     request.processResult(MmsService.this, status, pdu, 0/*httpStatusCode*/);
                 } else {
                     // Failed, try sending via carrier network
-                    addRunning(request);
+                    addSimRequest(request);
                 }
             } else {
                 // Really wrong here: can't find the request to update
@@ -172,7 +229,7 @@
         public void updateMmsDownloadStatus(int messageRef, int status) {
             Log.d(TAG, "updateMmsDownloadStatus: ref=" + messageRef + ", status=" + status);
             enforceSystemUid();
-            final MmsRequest request = mPendingRequests.get(messageRef);
+            final MmsRequest request = mPendingCarrierAppRequests.remove(messageRef);
             if (request != null) {
                 if (status != SmsManager.MMS_ERROR_RETRY) {
                     // Downloaded completed (maybe success or fail) by carrier app, finalize the
@@ -181,7 +238,7 @@
                             MmsService.this, status, null/*response*/, 0/*httpStatusCode*/);
                 } else {
                     // Failed, try downloading via the carrier network
-                    addRunning(request);
+                    addSimRequest(request);
                 }
             } else {
                 // Really wrong here: can't find the request to update
@@ -192,6 +249,8 @@
         @Override
         public Bundle getCarrierConfigValues(int subId) {
             Log.d(TAG, "getCarrierConfigValues");
+            // Make sure the subId is correct
+            subId = checkSubId(subId);
             final MmsConfig mmsConfig = MmsConfigManager.getInstance().getMmsConfigBySubId(subId);
             if (mmsConfig == null) {
                 return new Bundle();
@@ -329,13 +388,10 @@
         }
     };
 
-    // Request queue threads
+    // Running request queues, one thread per queue
     // 0: send queue
     // 1: download queue
-    private final RequestQueue[] mRequestQueues = new RequestQueue[2];
-
-    // Manages MMS connectivity related stuff
-    private final MmsNetworkManager mMmsNetworkManager = new MmsNetworkManager(this);
+    private final RequestQueue[] mRunningRequestQueues = new RequestQueue[2];
 
     /**
      * Lazy start the request queue threads
@@ -343,29 +399,81 @@
      * @param queueIndex index of the queue to start
      */
     private void startRequestQueueIfNeeded(int queueIndex) {
-        if (queueIndex < 0 || queueIndex >= mRequestQueues.length) {
+        if (queueIndex < 0 || queueIndex >= mRunningRequestQueues.length) {
+            Log.e(TAG, "Start request queue if needed: invalid queue " + queueIndex);
             return;
         }
         synchronized (this) {
-            if (mRequestQueues[queueIndex] == null) {
+            if (mRunningRequestQueues[queueIndex] == null) {
                 final HandlerThread thread =
                         new HandlerThread("MmsService RequestQueue " + queueIndex);
                 thread.start();
-                mRequestQueues[queueIndex] = new RequestQueue(thread.getLooper());
+                mRunningRequestQueues[queueIndex] = new RequestQueue(thread.getLooper());
             }
         }
     }
 
     @Override
-    public void addRunning(MmsRequest request) {
+    public void addSimRequest(MmsRequest request) {
         if (request == null) {
+            Log.e(TAG, "Add running or pending: empty request");
             return;
         }
-        final int queue = request.getRunningQueue();
+        Log.d(TAG, "Current running=" + mRunningRequestCount + ", "
+                + "current subId=" + mCurrentSubId + ", "
+                + "pending=" + mPendingSimRequestQueue.size());
+        synchronized (this) {
+            if (mPendingSimRequestQueue.size() > 0 ||
+                    (mRunningRequestCount > 0 && request.getSubId() != mCurrentSubId)) {
+                Log.d(TAG, "Add request to pending queue."
+                        + " Request subId=" + request.getSubId() + ","
+                        + " current subId=" + mCurrentSubId);
+                mPendingSimRequestQueue.add(request);
+                if (mRunningRequestCount <= 0) {
+                    Log.e(TAG, "Nothing's running but queue's not empty");
+                    // Nothing is running but we are accumulating on pending queue.
+                    // This should not happen. But just in case...
+                    movePendingSimRequestsToRunningSynchronized();
+                }
+            } else {
+                addToRunningRequestQueueSynchronized(request);
+            }
+        }
+    }
+
+    private void addToRunningRequestQueueSynchronized(MmsRequest request) {
+        Log.d(TAG, "Add request to running queue for subId " + request.getSubId());
+        // Update current state of running requests
+        mCurrentSubId = request.getSubId();
+        mRunningRequestCount++;
+        // Send to the corresponding request queue for execution
+        final int queue = request.getQueueType();
         startRequestQueueIfNeeded(queue);
         final Message message = Message.obtain();
         message.obj = request;
-        mRequestQueues[queue].sendMessage(message);
+        mRunningRequestQueues[queue].sendMessage(message);
+    }
+
+    private void movePendingSimRequestsToRunningSynchronized() {
+        Log.d(TAG, "Schedule requests pending on SIM");
+        mCurrentSubId = SubscriptionManager.INVALID_SUB_ID;
+        while (mPendingSimRequestQueue.size() > 0) {
+            final MmsRequest request = mPendingSimRequestQueue.peek();
+            if (request != null) {
+                if (mCurrentSubId == SubscriptionManager.INVALID_SUB_ID ||
+                        mCurrentSubId == request.getSubId()) {
+                    // First or subsequent requests with same SIM ID
+                    mPendingSimRequestQueue.remove();
+                    addToRunningRequestQueueSynchronized(request);
+                } else {
+                    // Stop if we see a different SIM ID
+                    break;
+                }
+            } else {
+                Log.e(TAG, "Schedule pending: found empty request");
+                mPendingSimRequestQueue.remove();
+            }
+        }
     }
 
     @Override
@@ -382,8 +490,12 @@
         super.onCreate();
         Log.d(TAG, "onCreate");
         // Load mms_config
-        // TODO (ywen): make sure we start request queues after mms_config is loaded
         MmsConfigManager.getInstance().init(this);
+        // Initialize running request state
+        synchronized (this) {
+            mCurrentSubId = SubscriptionManager.INVALID_SUB_ID;
+            mRunningRequestCount = 0;
+        }
     }
 
     private Uri importSms(String address, int type, String text, long timestampMillis,
diff --git a/src/com/android/mms/service/PhoneUtils.java b/src/com/android/mms/service/PhoneUtils.java
new file mode 100644
index 0000000..fc1ff4b
--- /dev/null
+++ b/src/com/android/mms/service/PhoneUtils.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mms.service;
+
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+import com.android.i18n.phonenumbers.NumberParseException;
+import com.android.i18n.phonenumbers.PhoneNumberUtil;
+import com.android.i18n.phonenumbers.Phonenumber;
+
+import java.util.Locale;
+
+/**
+ * Utility to handle phone numbers.
+ */
+public class PhoneUtils {
+
+    /**
+     * Get a canonical national format phone number. If parsing fails, just return the
+     * original number.
+     *
+     * @param telephonyManager
+     * @param subId The SIM ID associated with this number
+     * @param phoneText The input phone number text
+     * @return The formatted number or the original phone number if failed to parse
+     */
+    public static String getNationalNumber(TelephonyManager telephonyManager, int subId,
+            String phoneText) {
+        final String country = getSimOrDefaultLocaleCountry(telephonyManager, subId);
+        final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
+        final Phonenumber.PhoneNumber parsed = getParsedNumber(phoneNumberUtil, phoneText, country);
+        if (parsed == null) {
+            return phoneText;
+        }
+        return phoneNumberUtil
+                .format(parsed, PhoneNumberUtil.PhoneNumberFormat.NATIONAL)
+                .replaceAll("\\D", "");
+    }
+
+    // Parse the input number into internal format
+    private static Phonenumber.PhoneNumber getParsedNumber(PhoneNumberUtil phoneNumberUtil,
+            String phoneText, String country) {
+        try {
+            final Phonenumber.PhoneNumber phoneNumber = phoneNumberUtil.parse(phoneText, country);
+            if (phoneNumberUtil.isValidNumber(phoneNumber)) {
+                return phoneNumber;
+            } else {
+                Log.e(MmsService.TAG, "getParsedNumber: not a valid phone number " + phoneText
+                        + " for country " + country);
+                return null;
+            }
+        } catch (final NumberParseException e) {
+            Log.e(MmsService.TAG, "getParsedNumber: Not able to parse phone number " + phoneText);
+            return null;
+        }
+    }
+
+    // Get the country/region either from the SIM ID or from locale
+    private static String getSimOrDefaultLocaleCountry(TelephonyManager telephonyManager,
+            int subId) {
+        String country = getSimCountry(telephonyManager, subId);
+        if (TextUtils.isEmpty(country)) {
+            country = Locale.getDefault().getCountry();
+        }
+
+        return country;
+    }
+
+    // Get country/region from SIM ID
+    private static String getSimCountry(TelephonyManager telephonyManager, int subId) {
+        final String country = telephonyManager.getSimCountryIso(subId);
+        if (TextUtils.isEmpty(country)) {
+            return null;
+        }
+        return country.toUpperCase();
+    }
+}
diff --git a/src/com/android/mms/service/SendRequest.java b/src/com/android/mms/service/SendRequest.java
index 64c47f1..8950fb4 100644
--- a/src/com/android/mms/service/SendRequest.java
+++ b/src/com/android/mms/service/SendRequest.java
@@ -87,7 +87,7 @@
     }
 
     @Override
-    protected int getRunningQueue() {
+    protected int getQueueType() {
         return MmsService.QUEUE_INDEX_SEND;
     }
 
@@ -239,7 +239,7 @@
                 intent);
 
         if (carrierPackages == null || carrierPackages.size() != 1) {
-            mRequestManager.addRunning(this);
+            mRequestManager.addSimRequest(this);
         } else {
             intent.setPackage(carrierPackages.get(0));
             intent.putExtra(Telephony.Mms.Intents.EXTRA_MMS_CONTENT_URI, mPduUri);