merge in lmp-mr1-release history after reset to lmp-mr1-dev
diff --git a/src/java/android/telephony/CarrierMessagingServiceManager.java b/src/java/android/telephony/CarrierMessagingServiceManager.java
new file mode 100644
index 0000000..768d97b
--- /dev/null
+++ b/src/java/android/telephony/CarrierMessagingServiceManager.java
@@ -0,0 +1,99 @@
+/*
+ * 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 android.telephony;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.service.carrier.CarrierMessagingService;
+import android.service.carrier.ICarrierMessagingService;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Provides basic structure for platform to connect to the carrier messaging service.
+ * <p>
+ * <code>
+ * CarrierMessagingServiceManager carrierMessagingServiceManager =
+ *     new CarrierMessagingServiceManagerImpl();
+ * if (carrierMessagingServiceManager.bindToCarrierMessagingService(context, carrierPackageName)) {
+ *   // wait for onServiceReady callback
+ * } else {
+ *   // Unable to bind: handle error.
+ * }
+ * </code>
+ * <p> Upon completion {@link #disposeConnection} should be called to unbind the
+ * CarrierMessagingService.
+ * @hide
+ */
+public abstract class CarrierMessagingServiceManager {
+    // Populated by bindToCarrierMessagingService. bindToCarrierMessagingService must complete
+    // prior to calling disposeConnection so that mCarrierMessagingServiceConnection is initialized.
+    private volatile CarrierMessagingServiceConnection mCarrierMessagingServiceConnection;
+
+    /**
+     * Binds to the carrier messaging service under package {@code carrierPackageName}. This method
+     * should be called exactly once.
+     *
+     * @param context the context
+     * @param carrierPackageName the carrier package name
+     * @return true upon successfully binding to a carrier messaging service, false otherwise
+     */
+    public boolean bindToCarrierMessagingService(Context context, String carrierPackageName) {
+        Preconditions.checkState(mCarrierMessagingServiceConnection == null);
+
+        Intent intent = new Intent(CarrierMessagingService.SERVICE_INTERFACE);
+        intent.setPackage(carrierPackageName);
+        mCarrierMessagingServiceConnection = new CarrierMessagingServiceConnection();
+        return context.bindService(intent, mCarrierMessagingServiceConnection,
+                Context.BIND_AUTO_CREATE);
+    }
+
+    /**
+     * Unbinds the carrier messaging service. This method should be called exactly once.
+     *
+     * @param context the context
+     */
+    public void disposeConnection(Context context) {
+        Preconditions.checkNotNull(mCarrierMessagingServiceConnection);
+        context.unbindService(mCarrierMessagingServiceConnection);
+        mCarrierMessagingServiceConnection = null;
+    }
+
+    /**
+     * Implemented by subclasses to use the carrier messaging service once it is ready.
+     *
+     * @param carrierMessagingService the carrier messaing service interface
+     */
+    protected abstract void onServiceReady(ICarrierMessagingService carrierMessagingService);
+
+    /**
+     * A basic {@link ServiceConnection}.
+     */
+    private final class CarrierMessagingServiceConnection implements ServiceConnection {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            onServiceReady(ICarrierMessagingService.Stub.asInterface(service));
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+        }
+    }
+}
diff --git a/src/java/android/telephony/SmsManager.java b/src/java/android/telephony/SmsManager.java
index bb6aea9..547f0a9 100644
--- a/src/java/android/telephony/SmsManager.java
+++ b/src/java/android/telephony/SmsManager.java
@@ -278,10 +278,12 @@
      * @param format is the format of SMS pdu (3gpp or 3gpp2)
      * @param receivedIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is successfully received by the
-     *  android application framework. This intent is broadcasted at
+     *  android application framework, or failed. This intent is broadcasted at
      *  the same time an SMS received from radio is acknowledged back.
+     *  The result code will be <code>RESULT_SMS_HANDLED</code> for success, or
+     *  <code>RESULT_SMS_GENERIC_ERROR</code> for error.
      *
-     *  @throws IllegalArgumentException if format is not one of 3gpp and 3gpp2.
+     * @throws IllegalArgumentException if format is not one of 3gpp and 3gpp2.
      */
     public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) {
         if (!format.equals(SmsMessage.FORMAT_3GPP) && !format.equals(SmsMessage.FORMAT_3GPP2)) {
@@ -300,26 +302,9 @@
     }
 
     /**
-     * Update the status of a pending (send-by-IP) SMS message and resend by PSTN if necessary.
-     * This outbound message was handled by the carrier app. If the carrier app fails to send
-     * this message, it would be resent by PSTN.
-     *
-     * The caller should have carrier privileges.
-     * @see android.telephony.TelephonyManager.hasCarrierPrivileges
-     *
-     * @param messageRef the reference number of the SMS message.
-     * @param success True if and only if the message was sent successfully. If its value is
-     *  false, this message should be resent via PSTN.
+     * TODO: remove this method.
      */
     public void updateSmsSendStatus(int messageRef, boolean success) {
-        try {
-            ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
-            if (iccISms != null) {
-                iccISms.updateSmsSendStatus(messageRef, success);
-            }
-        } catch (RemoteException ex) {
-          // ignore it
-        }
     }
 
     /**
@@ -1029,69 +1014,17 @@
     public static final String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
 
     /**
-     * Update the status of a pending (send-by-IP) MMS message handled by the carrier app.
-     * If the carrier app fails to send this message, it may be resent via carrier network
-     * depending on the status code.
-     *
-     * The caller should have carrier privileges.
-     * @see android.telephony.TelephonyManager.hasCarrierPrivileges
-     *
-     * @param context application context
-     * @param messageRef the reference number of the MMS message.
-     * @param pdu non-empty (contains the SendConf PDU) if the message was sent successfully,
-     *   otherwise, this param should be null.
-     * @param status send status. It can be Activity.RESULT_OK or one of the MMS error codes.
-     *   If status is Activity.RESULT_OK, the MMS was sent successfully.
-     *   If status is MMS_ERROR_RETRY, this message would be resent via carrier
-     *   network. The message will not be resent for other MMS error statuses.
-     * @param contentUri the URI of the sent message
+     * TODO: remove this method.
      */
     public void updateMmsSendStatus(Context context, int messageRef, byte[] pdu, int status,
             Uri contentUri) {
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms == null) {
-                return;
-            }
-            iMms.updateMmsSendStatus(messageRef, pdu, status);
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        if (contentUri != null) {
-            context.revokeUriPermission(contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        }
     }
 
     /**
-     * Update the status of a pending (download-by-IP) MMS message handled by the carrier app.
-     * If the carrier app fails to download this message, it may be re-downloaded via carrier
-     * network depending on the status code.
-     *
-     * The caller should have carrier privileges.
-     * @see android.telephony.TelephonyManager.hasCarrierPrivileges
-     *
-     * @param context application context
-     * @param messageRef the reference number of the MMS message.
-     * @param status download status.  It can be Activity.RESULT_OK or one of the MMS error codes.
-     *   If status is Activity.RESULT_OK, the MMS was downloaded successfully.
-     *   If status is MMS_ERROR_RETRY, this message would be re-downloaded via carrier
-     *   network. The message will not be re-downloaded for other MMS error statuses.
-     * @param contentUri the URI of the downloaded message
+     * TODO: remove this method.
      */
     public void updateMmsDownloadStatus(Context context, int messageRef, int status,
             Uri contentUri) {
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms == null) {
-                return;
-            }
-            iMms.updateMmsDownloadStatus(messageRef, status);
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        if (contentUri != null) {
-            context.revokeUriPermission(contentUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-        }
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index 42bddd4..a7e98b3 100644
--- a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -173,7 +173,7 @@
             networkCapabilities = sender.getNetworkCapabilities(apnType);
         }
         ServiceState ss = sender.getServiceState();
-        if (ss != null) roaming = ss.getRoaming();
+        if (ss != null) roaming = ss.getDataRoaming();
 
         try {
             if (mRegistry != null) {
diff --git a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
index e5fdb15..3af4d95 100644
--- a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
+++ b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
@@ -425,21 +425,6 @@
     }
 
     /**
-     * Update the status of a pending (send-by-IP) SMS message and resend by PSTN if necessary.
-     * This outbound message was handled by the carrier app. If the carrier app fails to send
-     * this message, it would be resent by PSTN.
-     *
-     * @param messageRef the reference number of the SMS message.
-     * @param success True if and only if the message was sent successfully. If its value is
-     *  false, this message should be resent via PSTN.
-     * {@hide}
-     */
-    public void updateSmsSendStatus(int messageRef, boolean success) {
-        enforceCarrierPrivilege();
-        mDispatcher.updateSmsSendStatus(messageRef, success);
-    }
-
-    /**
      * Send a multi-part text based SMS.
      *
      * @param destAddr the address to send the message to
diff --git a/src/java/com/android/internal/telephony/ImsSMSDispatcher.java b/src/java/com/android/internal/telephony/ImsSMSDispatcher.java
index 9bc5517..9ad7169 100644
--- a/src/java/com/android/internal/telephony/ImsSMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/ImsSMSDispatcher.java
@@ -196,60 +196,6 @@
     }
 
     @Override
-    protected void updateSmsSendStatus(int messageRef, boolean success) {
-        if (isCdmaMo()) {
-            updateSmsSendStatusHelper(messageRef, mCdmaDispatcher.sendPendingList,
-                                      mCdmaDispatcher, success);
-            updateSmsSendStatusHelper(messageRef, mGsmDispatcher.sendPendingList,
-                                      null, success);
-        } else {
-            updateSmsSendStatusHelper(messageRef, mGsmDispatcher.sendPendingList,
-                                      mGsmDispatcher, success);
-            updateSmsSendStatusHelper(messageRef, mCdmaDispatcher.sendPendingList,
-                                      null, success);
-        }
-    }
-
-    /**
-     * Find a tracker in a list to update its status. If the status is successful,
-     * send an EVENT_SEND_SMS_COMPLETE message. Otherwise, resend the message by PSTN if
-     * feasible.
-     *
-     * @param messageRef the reference number of the tracker.
-     * @param sendPendingList the list of trackers to look into.
-     * @param smsDispatcher the dispatcher for resending the message by PSTN.
-     * @param success true iff the message was sent successfully.
-     */
-    private void updateSmsSendStatusHelper(int messageRef,
-                                           List<SmsTracker> sendPendingList,
-                                           SMSDispatcher smsDispatcher,
-                                           boolean success) {
-        synchronized (sendPendingList) {
-            for (int i = 0, count = sendPendingList.size(); i < count; i++) {
-                SmsTracker tracker = sendPendingList.get(i);
-                if (tracker.mMessageRef == messageRef) {
-                    // Found it.  Remove from list and broadcast.
-                    sendPendingList.remove(i);
-                    if (success) {
-                        Rlog.d(TAG, "Sending SMS by IP succeeded.");
-                        sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE,
-                                                  new AsyncResult(tracker, null, null)));
-                    } else {
-                        Rlog.d(TAG, "Sending SMS by IP failed.");
-                        if (smsDispatcher != null) {
-                            smsDispatcher.sendSmsByPstn(tracker);
-                        } else {
-                            Rlog.e(TAG, "No feasible way to send this SMS.");
-                        }
-                    }
-                    // Only expect to see one tracker matching this messageref.
-                    break;
-                }
-            }
-        }
-    }
-
-    @Override
     protected void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent,
             PendingIntent deliveryIntent, Uri messageUri, String callingPkg) {
         Rlog.d(TAG, "sendText");
@@ -388,6 +334,11 @@
     }
 
     @Override
+    protected void sendSubmitPdu(SmsTracker tracker) {
+        sendRawPdu(tracker);
+    }
+
+    @Override
     protected String getFormat() {
         // this function should be defined in Gsm/CdmaDispatcher.
         Rlog.e(TAG, "getFormat should never be called from here!");
@@ -402,12 +353,13 @@
     }
 
     @Override
-    protected void sendNewSubmitPdu(String destinationAddress, String scAddress, String message,
-            SmsHeader smsHeader, int format, PendingIntent sentIntent,
+    protected SmsTracker getNewSubmitPduTracker(String destinationAddress, String scAddress,
+            String message, SmsHeader smsHeader, int format, PendingIntent sentIntent,
             PendingIntent deliveryIntent, boolean lastPart,
             AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
             String fullMessageText) {
         Rlog.e(TAG, "Error! Not implemented for IMS.");
+        return null;
     }
 
     @Override
diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java
index f5ef0b1..670ee86 100644
--- a/src/java/com/android/internal/telephony/InboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java
@@ -47,12 +47,11 @@
 import android.preference.PreferenceManager;
 import android.provider.Telephony;
 import android.provider.Telephony.Sms.Intents;
-import android.service.carriermessaging.CarrierMessagingService;
-import android.service.carriermessaging.CarrierMessagingService.SendSmsResponse;
-import android.service.carriermessaging.CarrierMessagingServiceManager;
-import android.service.carriermessaging.ICarrierMessagingCallback;
-import android.service.carriermessaging.ICarrierMessagingService;
-import android.service.carriermessaging.MessagePdu;
+import android.service.carrier.CarrierMessagingService;
+import android.service.carrier.ICarrierMessagingCallback;
+import android.service.carrier.ICarrierMessagingService;
+import android.service.carrier.MessagePdu;
+import android.telephony.CarrierMessagingServiceManager;
 import android.telephony.Rlog;
 import android.telephony.SmsManager;
 import android.telephony.SmsMessage;
@@ -1089,7 +1088,7 @@
             try {
                 carrierMessagingService.filterSms(
                         new MessagePdu(Arrays.asList(mPdus)), mSmsFormat, mDestPort,
-                        mSmsFilterCallback);
+                        mPhone.getSubId(), mSmsFilterCallback);
             } catch (RemoteException e) {
                 loge("Exception filtering the SMS: " + e);
                 mSmsFilterCallback.onFilterComplete(true);
@@ -1128,12 +1127,12 @@
         }
 
         @Override
-        public void onSendSmsComplete(int result, SendSmsResponse sendSmsResponse) {
+        public void onSendSmsComplete(int result, int messageRef) {
             loge("Unexpected onSendSmsComplete call with result: " + result);
         }
 
         @Override
-        public void onSendMultipartSmsComplete(int result, List<SendSmsResponse> sendSmsResponse) {
+        public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
             loge("Unexpected onSendMultipartSmsComplete call with result: " + result);
         }
 
diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java
index 833c1f0..660e560 100644
--- a/src/java/com/android/internal/telephony/PhoneFactory.java
+++ b/src/java/com/android/internal/telephony/PhoneFactory.java
@@ -317,18 +317,6 @@
             Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim Voice Call Values");
         }
 
-        // FIXME can this be removed? We should not set defaults
-        int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
-        // Set subscription to 0 if current subscription is invalid.
-        // Ex: multisim.config property is TSTS and subscription is 2.
-        // If user is trying to set multisim.config to DSDS and reboots
-        // in this case index 2 is invalid so need to set to 0.
-        if (phoneId < 0 || phoneId >= TelephonyManager.getDefault().getPhoneCount()) {
-            Rlog.i(LOG_TAG, "Subscription is invalid..." + subId + " Set to 0");
-            subId = 0;
-            setVoiceSubscription(subId);
-        }
-
         return subId;
     }
 
@@ -391,14 +379,6 @@
             Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim Data Call Values");
         }
 
-        // FIXME can this be removed? We should not set defaults
-        int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
-        if (phoneId < 0 || phoneId >= TelephonyManager.getDefault().getPhoneCount()) {
-            subId = 0;
-            Rlog.i(LOG_TAG, "Subscription is invalid..." + subId + " Set to 0");
-            setDataSubscription(subId);
-        }
-
         return subId;
     }
 
@@ -412,60 +392,9 @@
             Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim SMS Values");
         }
 
-        // FIXME can this be removed? We should not set defaults
-        int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
-        if (phoneId < 0 || phoneId >= TelephonyManager.getDefault().getPhoneCount()) {
-            Rlog.i(LOG_TAG, "Subscription is invalid..." + subId + " Set to 0");
-            subId = 0;
-            setSMSSubscription(subId);
-        }
-
         return subId;
     }
 
-    //FIXME can this be removed, it is only called in getVoiceSubscription
-    static public void setVoiceSubscription(int subId) {
-        Settings.Global.putInt(sContext.getContentResolver(),
-                Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, subId);
-        Rlog.d(LOG_TAG, "setVoiceSubscription : " + subId);
-    }
-
-    //FIXME can this be removed, it is only called in getDataSubscription
-    static public void setDataSubscription(int subId) {
-        boolean enabled;
-
-        Settings.Global.putInt(sContext.getContentResolver(),
-                Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION, subId);
-        Rlog.d(LOG_TAG, "setDataSubscription: " + subId);
-
-        // Update the current mobile data flag
-        enabled = TelephonyManager.getIntWithSubId(sContext.getContentResolver(),
-                Settings.Global.MOBILE_DATA, subId, 0) != 0;
-        Settings.Global.putInt(sContext.getContentResolver(),
-                Settings.Global.MOBILE_DATA + subId, enabled ? 1 : 0);
-        Rlog.d(LOG_TAG, "set mobile_data: " + enabled);
-
-        // Update the current data roaming flag
-        enabled = TelephonyManager.getIntWithSubId(sContext.getContentResolver(),
-                Settings.Global.DATA_ROAMING, subId, 0) != 0;
-        Settings.Global.putInt(sContext.getContentResolver(),
-                Settings.Global.DATA_ROAMING + subId, enabled ? 1 : 0);
-        Rlog.d(LOG_TAG, "set data_roaming: " + enabled);
-    }
-
-    //FIXME can this be removed, it is only called in getSMSSubscription
-    static public void setSMSSubscription(int subId) {
-        Settings.Global.putInt(sContext.getContentResolver(),
-                Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION, subId);
-
-        Intent intent = new Intent("com.android.mms.transaction.SEND_MESSAGE");
-        sContext.sendBroadcast(intent);
-
-        // Change occured in SMS preferred sub, update the default
-        // SMS interface Manager object with the new SMS preferred subscription.
-        Rlog.d(LOG_TAG, "setSMSSubscription : " + subId);
-    }
-
     /**
      * Makes a {@link ImsPhone} object.
      * @return the {@code ImsPhone} object or null if the exception occured
diff --git a/src/java/com/android/internal/telephony/ProxyController.java b/src/java/com/android/internal/telephony/ProxyController.java
index 4842349..603bf8c 100644
--- a/src/java/com/android/internal/telephony/ProxyController.java
+++ b/src/java/com/android/internal/telephony/ProxyController.java
@@ -117,7 +117,7 @@
         return sProxyController;
     }
 
-    static public ProxyController getInstance() {
+    public static ProxyController getInstance() {
         return sProxyController;
     }
 
@@ -153,7 +153,10 @@
 
         // Clear to be sure we're in the initial state
         clearTransaction();
-
+        for (int i = 0; i < mProxyPhones.length; i++) {
+            mProxyPhones[i].registerForRadioCapabilityChanged(
+                    mHandler, EVENT_NOTIFICATION_RC_CHANGED, null);
+        }
         logd("Constructor - Exit");
     }
 
@@ -231,6 +234,8 @@
         // is one as this is a programming error.
         synchronized (mSetRadioAccessFamilyStatus) {
             for (int i = 0; i < mProxyPhones.length; i++) {
+                logd("setRadioCapability: mSetRadioAccessFamilyStatus[" + i + "]="
+                        + mSetRadioAccessFamilyStatus[i]);
                 if (mSetRadioAccessFamilyStatus[i] != SET_RC_STATUS_IDLE) {
                     throw new RuntimeException("setRadioCapability: Phone" + i + " is not idle");
                 }
@@ -252,10 +257,11 @@
         mHandler.postDelayed(mSetRadioCapabilityRunnable, SET_RC_TIMEOUT_WAITING_MSEC);
 
         synchronized (mSetRadioAccessFamilyStatus) {
-            logd("setRadioCapability: new request session id:" + mRadioCapabilitySessionId);
+            logd("setRadioCapability: new request session id=" + mRadioCapabilitySessionId);
             mRadioAccessFamilyStatusCounter = rafs.length;
             for (int i = 0; i < rafs.length; i++) {
                 int phoneId = rafs[i].getPhoneId();
+                logd("setRadioCapability: phoneId=" + phoneId + " status=STARTING");
                 mSetRadioAccessFamilyStatus[phoneId] = SET_RC_STATUS_STARTING;
                 mOldRadioAccessFamily[phoneId] = mProxyPhones[phoneId].getRadioAccessFamily();
                 mNewRadioAccessFamily[phoneId] = rafs[i].getRadioAccessFamily();
@@ -278,7 +284,7 @@
     private Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
-            logd("handleMessage msg.what:" + msg.what);
+            logd("handleMessage msg.what=" + msg.what);
             switch (msg.what) {
                 case EVENT_START_RC_RESPONSE:
                     onStartRadioCapabilityResponse(msg);
@@ -315,26 +321,26 @@
                 return;
             }
             mRadioAccessFamilyStatusCounter--;
+            int id = rc.getPhoneId();
             if (((AsyncResult) msg.obj).exception != null) {
                 logd("onStartRadioCapabilityResponse: Error response session=" + rc.getSession());
-                mSetRadioAccessFamilyStatus[rc.getPhoneId()] = SET_RC_STATUS_FAIL;
+                logd("onStartRadioCapabilityResponse: phoneId=" + id + " status=FAIL");
+                mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL;
             } else {
-                mSetRadioAccessFamilyStatus[rc.getPhoneId()] = SET_RC_STATUS_STARTED;
+                logd("onStartRadioCapabilityResponse: phoneId=" + id + " status=STARTED");
+                mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_STARTED;
             }
 
             if (mRadioAccessFamilyStatusCounter == 0) {
-                mHandler.removeCallbacks(mSetRadioCapabilityRunnable);
                 resetRadioAccessFamilyStatusCounter();
                 boolean success = checkAllRadioCapabilitySuccess();
-                logd("onStartRadioCapabilityResponse: success:" + success);
+                logd("onStartRadioCapabilityResponse: success=" + success);
                 if (!success) {
                     issueFinish(RadioCapability.RC_STATUS_FAIL,
                             mRadioCapabilitySessionId);
                 } else {
                     // All logical modem accepted the new radio access family, issue the APPLY
                     for (int i = 0; i < mProxyPhones.length; i++) {
-                        mProxyPhones[i].registerForRadioCapabilityChanged(
-                                        mHandler, EVENT_NOTIFICATION_RC_CHANGED, null);
                         sendRadioCapabilityRequest(
                             i,
                             mRadioCapabilitySessionId,
@@ -343,6 +349,8 @@
                             mLogicalModemIds[i],
                             RadioCapability.RC_STATUS_NONE,
                             EVENT_APPLY_RC_RESPONSE);
+
+                        logd("onStartRadioCapabilityResponse: phoneId=" + i + " status=APPLYING");
                         mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_APPLYING;
                     }
                 }
@@ -365,8 +373,9 @@
         if (((AsyncResult) msg.obj).exception != null) {
             synchronized (mSetRadioAccessFamilyStatus) {
                 logd("onApplyRadioCapabilityResponse: Error response session=" + rc.getSession());
-                mSetRadioAccessFamilyStatus[rc.getPhoneId()] = SET_RC_STATUS_FAIL;
-                mProxyPhones[rc.getPhoneId()].unregisterForRadioCapabilityChanged(mHandler);
+                int id = rc.getPhoneId();
+                logd("onApplyRadioCapabilityResponse: phoneId=" + id + " status=FAIL");
+                mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL;
             }
         } else {
             logd("onApplyRadioCapabilityResponse: Valid start expecting notification rc=" + rc);
@@ -393,17 +402,19 @@
                 return;
             }
 
+            int id = rc.getPhoneId();
             if ((((AsyncResult) msg.obj).exception != null) ||
                     (rc.getStatus() == RadioCapability.RC_STATUS_FAIL)) {
-                mSetRadioAccessFamilyStatus[rc.getPhoneId()] = SET_RC_STATUS_FAIL;
+                logd("onNotificationRadioCapabilityChanged: phoneId=" + id + " status=FAIL");
+                mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL;
             } else {
-                mSetRadioAccessFamilyStatus[rc.getPhoneId()] = SET_RC_STATUS_SUCCESS;
+                logd("onNotificationRadioCapabilityChanged: phoneId=" + id + " status=SUCCESS");
+                mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_SUCCESS;
             }
-            mProxyPhones[rc.getPhoneId()]
-                    .unregisterForRadioCapabilityChanged(mHandler);
 
             mRadioAccessFamilyStatusCounter--;
             if (mRadioAccessFamilyStatusCounter == 0) {
+                logd("onNotificationRadioCapabilityChanged: removing callback from handler");
                 mHandler.removeCallbacks(mSetRadioCapabilityRunnable);
                 resetRadioAccessFamilyStatusCounter();
                 boolean success = checkAllRadioCapabilitySuccess();
@@ -431,7 +442,7 @@
             return;
         }
         synchronized (mSetRadioAccessFamilyStatus) {
-            logd(" onFinishRadioCapabilityResponse mRadioAccessFamilyStatusCounter:"
+            logd(" onFinishRadioCapabilityResponse mRadioAccessFamilyStatusCounter="
                     + mRadioAccessFamilyStatusCounter);
             mRadioAccessFamilyStatusCounter--;
             if (mRadioAccessFamilyStatusCounter == 0) {
@@ -445,7 +456,7 @@
         synchronized(mSetRadioAccessFamilyStatus) {
             for (int i = 0; i < mProxyPhones.length; i++) {
                 if (mSetRadioAccessFamilyStatus[i] != SET_RC_STATUS_FAIL) {
-                    logd("issueFinish: Phone" + i + " sessionId=" + sessionId
+                    logd("issueFinish: phoneId=" + i + " sessionId=" + sessionId
                             + " status=" + status);
                     sendRadioCapabilityRequest(
                         i,
@@ -456,6 +467,7 @@
                         status,
                         EVENT_FINISH_RC_RESPONSE);
                     if (status == RadioCapability.RC_STATUS_FAIL) {
+                        logd("issueFinish: phoneId: " + i + " status: FAIL");
                         // At least one failed, mark them all failed.
                         mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_FAIL;
                     }
@@ -471,12 +483,12 @@
         // Create the intent to broadcast
         Intent intent;
         boolean success = checkAllRadioCapabilitySuccess();
-        logd("onFinishRadioCapabilityResponse: success:" + success);
+        logd("onFinishRadioCapabilityResponse: success=" + success);
         if (success) {
             ArrayList<RadioAccessFamily> phoneRAFList = new ArrayList<RadioAccessFamily>();
             for (int i = 0; i < mProxyPhones.length; i++) {
                 int raf = mProxyPhones[i].getRadioAccessFamily();
-                logd("radioAccessFamily[" + i + "]:" + raf);
+                logd("radioAccessFamily[" + i + "]=" + raf);
                 RadioAccessFamily phoneRC = new RadioAccessFamily(i, raf);
                 phoneRAFList.add(phoneRC);
             }
@@ -496,14 +508,15 @@
 
     // Clear this transaction
     private void clearTransaction() {
-        logd("clearTransaction:");
+        logd("clearTransaction");
         synchronized(mSetRadioAccessFamilyStatus) {
             for (int i = 0; i < mProxyPhones.length; i++) {
+                logd("clearTransaction: phoneId=" + i + " status=IDLE");
                 mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_IDLE;
                 mOldRadioAccessFamily[i] = 0;
                 mNewRadioAccessFamily[i] = 0;
             }
-            
+
             if (mWakeLock.isHeld()) {
                 mWakeLock.release();
             }
@@ -544,7 +557,6 @@
     private class RadioCapabilityRunnable implements Runnable {
         private int mSessionId;
         public  RadioCapabilityRunnable() {
-
         }
 
         public void setTimeoutState(int sessionId) {
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 51de8b4..cadf55a 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -3121,6 +3121,8 @@
                 setCdmaSubscriptionSource(mCdmaSubscription, null);
                 setCellInfoListRate(Integer.MAX_VALUE, null);
                 notifyRegistrantsRilConnectionChanged(((int[])ret)[0]);
+
+                getRadioCapability(null);
                 break;
             }
             case RIL_UNSOL_CELL_INFO_LIST: {
diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java
index d46eefb..b7cd866 100644
--- a/src/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/SMSDispatcher.java
@@ -19,7 +19,7 @@
 import android.app.AlertDialog;
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
-import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -29,19 +29,25 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
+import android.content.ServiceConnection;
 import android.database.ContentObserver;
 import android.database.sqlite.SqliteWrapper;
 import android.net.Uri;
 import android.os.AsyncResult;
 import android.os.Binder;
-import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Message;
+import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.provider.Telephony;
 import android.provider.Telephony.Sms;
 import android.provider.Telephony.Sms.Intents;
+import android.service.carrier.CarrierMessagingService;
+import android.service.carrier.ICarrierMessagingCallback;
+import android.service.carrier.ICarrierMessagingService;
+import android.telephony.CarrierMessagingServiceManager;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
@@ -261,10 +267,6 @@
     /** Sent messages awaiting a delivery status report. */
     protected final ArrayList<SmsTracker> deliveryPendingList = new ArrayList<SmsTracker>();
 
-    /** Outgoing messages being handled by the carrier app. */
-    protected final List<SmsTracker> sendPendingList =
-        Collections.synchronizedList(new ArrayList<SmsTracker>());
-
     /**
      * Handles events coming from the phone stack. Overridden from handler.
      *
@@ -330,6 +332,268 @@
     }
 
     /**
+     * Use the carrier messaging service to send a data or text SMS.
+     */
+    protected abstract class SmsSender extends CarrierMessagingServiceManager {
+        protected final SmsTracker mTracker;
+        // Initialized in sendSmsByCarrierApp
+        protected volatile SmsSenderCallback mSenderCallback;
+
+        protected SmsSender(SmsTracker tracker) {
+            mTracker = tracker;
+        }
+
+        public void sendSmsByCarrierApp(String carrierPackageName,
+                                        SmsSenderCallback senderCallback) {
+            mSenderCallback = senderCallback;
+            if (!bindToCarrierMessagingService(mContext, carrierPackageName)) {
+                Rlog.e(TAG, "bindService() for carrier messaging service failed");
+                mSenderCallback.onSendSmsComplete(
+                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
+                        0 /* messageRef */);
+            } else {
+                Rlog.d(TAG, "bindService() for carrier messaging service succeeded");
+            }
+        }
+    }
+
+    /**
+     * Use the carrier messaging service to send a text SMS.
+     */
+    protected final class TextSmsSender extends SmsSender {
+        public TextSmsSender(SmsTracker tracker) {
+            super(tracker);
+        }
+
+        @Override
+        protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
+            HashMap<String, Object> map = mTracker.mData;
+            String text = (String) map.get("text");
+
+            if (text != null) {
+                try {
+                    carrierMessagingService.sendTextSms(text, getSubId(),
+                            mTracker.mDestAddress, mSenderCallback);
+                } catch (RemoteException e) {
+                    Rlog.e(TAG, "Exception sending the SMS: " + e);
+                    mSenderCallback.onSendSmsComplete(
+                            CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
+                            0 /* messageRef */);
+                }
+            } else {
+                mSenderCallback.onSendSmsComplete(
+                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
+                        0 /* messageRef */);
+            }
+        }
+    }
+
+    /**
+     * Use the carrier messaging service to send a data SMS.
+     */
+    protected final class DataSmsSender extends SmsSender {
+        public DataSmsSender(SmsTracker tracker) {
+            super(tracker);
+        }
+
+        @Override
+        protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
+            HashMap<String, Object> map = mTracker.mData;
+            byte[] data = (byte[]) map.get("data");
+            int destPort = (int) map.get("destPort");
+
+            if (data != null) {
+                try {
+                    carrierMessagingService.sendDataSms(data, getSubId(),
+                            mTracker.mDestAddress, destPort, mSenderCallback);
+                } catch (RemoteException e) {
+                    Rlog.e(TAG, "Exception sending the SMS: " + e);
+                    mSenderCallback.onSendSmsComplete(
+                            CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
+                            0 /* messageRef */);
+                }
+            } else {
+                mSenderCallback.onSendSmsComplete(
+                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
+                        0 /* messageRef */);
+            }
+        }
+    }
+
+    /**
+     * Callback for TextSmsSender and DataSmsSender from the carrier messaging service.
+     * Once the result is ready, the carrier messaging service connection is disposed.
+     */
+    protected final class SmsSenderCallback extends ICarrierMessagingCallback.Stub {
+        private final SmsSender mSmsSender;
+
+        public SmsSenderCallback(SmsSender smsSender) {
+            mSmsSender = smsSender;
+        }
+
+        /**
+         * This method should be called only once.
+         */
+        @Override
+        public void onSendSmsComplete(int result, int messageRef) {
+            mSmsSender.disposeConnection(mContext);
+            processSendSmsResponse(mSmsSender.mTracker, result, messageRef);
+        }
+
+        @Override
+        public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
+            Rlog.e(TAG, "Unexpected onSendMultipartSmsComplete call with result: " + result);
+        }
+
+        @Override
+        public void onFilterComplete(boolean keepMessage) {
+            Rlog.e(TAG, "Unexpected onFilterComplete call with result: " + keepMessage);
+        }
+
+        @Override
+        public void onSendMmsComplete(int result, byte[] sendConfPdu) {
+            Rlog.e(TAG, "Unexpected onSendMmsComplete call with result: " + result);
+        }
+
+        @Override
+        public void onDownloadMmsComplete(int result) {
+            Rlog.e(TAG, "Unexpected onDownloadMmsComplete call with result: " + result);
+        }
+    }
+
+    private void processSendSmsResponse(SmsTracker tracker, int result, int messageRef) {
+        if (tracker == null) {
+            Rlog.e(TAG, "processSendSmsResponse: null tracker");
+            return;
+        }
+
+        SmsResponse smsResponse = new SmsResponse(
+                messageRef, null /* ackPdu */, -1 /* unknown error code */);
+
+        switch (result) {
+        case CarrierMessagingService.SEND_STATUS_OK:
+            Rlog.d(TAG, "Sending SMS by IP succeeded.");
+            sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE,
+                                      new AsyncResult(tracker,
+                                                      smsResponse,
+                                                      null /* exception*/ )));
+            break;
+        case CarrierMessagingService.SEND_STATUS_ERROR:
+            Rlog.d(TAG, "Sending SMS by IP failed.");
+            sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE,
+                    new AsyncResult(tracker, smsResponse,
+                            new CommandException(CommandException.Error.GENERIC_FAILURE))));
+            break;
+        case CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK:
+            Rlog.d(TAG, "Sending SMS by IP failed. Retry on carrier network.");
+            sendSubmitPdu(tracker);
+            break;
+        default:
+            Rlog.d(TAG, "Unknown result " + result + " Retry on carrier network.");
+            sendSubmitPdu(tracker);
+        }
+    }
+
+    /**
+     * Use the carrier messaging service to send a multipart text SMS.
+     */
+    private final class MultipartSmsSender extends CarrierMessagingServiceManager {
+        private final List<String> mParts;
+        public final SmsTracker[] mTrackers;
+        // Initialized in sendSmsByCarrierApp
+        private volatile MultipartSmsSenderCallback mSenderCallback;
+
+        MultipartSmsSender(ArrayList<String> parts, SmsTracker[] trackers) {
+            mParts = parts;
+            mTrackers = trackers;
+        }
+
+        void sendSmsByCarrierApp(String carrierPackageName,
+                                 MultipartSmsSenderCallback senderCallback) {
+            mSenderCallback = senderCallback;
+            if (!bindToCarrierMessagingService(mContext, carrierPackageName)) {
+                Rlog.e(TAG, "bindService() for carrier messaging service failed");
+                mSenderCallback.onSendMultipartSmsComplete(
+                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
+                        null /* smsResponse */);
+            } else {
+                Rlog.d(TAG, "bindService() for carrier messaging service succeeded");
+            }
+        }
+
+        @Override
+        protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
+            try {
+                carrierMessagingService.sendMultipartTextSms(
+                        mParts, getSubId(), mTrackers[0].mDestAddress, mSenderCallback);
+            } catch (RemoteException e) {
+                Rlog.e(TAG, "Exception sending the SMS: " + e);
+                mSenderCallback.onSendMultipartSmsComplete(
+                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
+                        null /* smsResponse */);
+            }
+        }
+    }
+
+    /**
+     * Callback for MultipartSmsSender from the carrier messaging service.
+     * Once the result is ready, the carrier messaging service connection is disposed.
+     */
+    private final class MultipartSmsSenderCallback extends ICarrierMessagingCallback.Stub {
+        private final MultipartSmsSender mSmsSender;
+
+        MultipartSmsSenderCallback(MultipartSmsSender smsSender) {
+            mSmsSender = smsSender;
+        }
+
+        @Override
+        public void onSendSmsComplete(int result, int messageRef) {
+            Rlog.e(TAG, "Unexpected onSendSmsComplete call with result: " + result);
+        }
+
+        /**
+         * This method should be called only once.
+         */
+        @Override
+        public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
+            mSmsSender.disposeConnection(mContext);
+
+            if (mSmsSender.mTrackers == null) {
+                Rlog.e(TAG, "Unexpected onSendMultipartSmsComplete call with null trackers.");
+                return;
+            }
+
+            for (int i = 0; i < mSmsSender.mTrackers.length; i++) {
+                int messageRef = 0;
+                if (messageRefs != null && messageRefs.length > i) {
+                    messageRef = messageRefs[i];
+                }
+                processSendSmsResponse(mSmsSender.mTrackers[i], result, messageRef);
+            }
+        }
+
+        @Override
+        public void onFilterComplete(boolean keepMessage) {
+            Rlog.e(TAG, "Unexpected onFilterComplete call with result: " + keepMessage);
+        }
+
+        @Override
+        public void onSendMmsComplete(int result, byte[] sendConfPdu) {
+            Rlog.e(TAG, "Unexpected onSendMmsComplete call with result: " + result);
+        }
+
+        @Override
+        public void onDownloadMmsComplete(int result) {
+            Rlog.e(TAG, "Unexpected onDownloadMmsComplete call with result: " + result);
+        }
+    }
+
+    /**
+     * Send an SMS PDU. Usually just calls {@link sendRawPdu}.
+     */
+    protected abstract void sendSubmitPdu(SmsTracker tracker);
+
+    /**
      * Called when SMS send completes. Broadcasts a sentIntent on success.
      * On failure, either sets up retries or broadcasts a sentIntent with
      * the failure in the result code.
@@ -520,55 +784,6 @@
             boolean use7bitOnly);
 
     /**
-     * Update the status of a pending (send-by-IP) SMS message and resend by PSTN if necessary.
-     * This outbound message was handled by the carrier app. If the carrier app fails to send
-     * this message, it would be resent by PSTN.
-     *
-     * @param messageRef the reference number of the SMS message.
-     * @param success True if and only if the message was sent successfully. If its value is
-     *  false, this message should be resent via PSTN.
-     */
-    protected abstract void updateSmsSendStatus(int messageRef, boolean success);
-
-    /**
-     * Handler for a {@link GsmSMSDispatcher} or {@link CdmaSMSDispatcher} broadcast.
-     * If SMS sending is successfuly, sends EVENT_SEND_SMS_COMPLETE message. Otherwise,
-     * send the message via the GSM/CDMA network.
-     */
-    protected final class SMSDispatcherReceiver extends BroadcastReceiver {
-
-        private final SmsTracker mTracker;
-
-        public SMSDispatcherReceiver(SmsTracker tracker) {
-            mTracker = tracker;
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(Intents.SMS_SEND_ACTION)) {
-                int rc = getResultCode();
-                if (rc == Activity.RESULT_OK) {
-                    Rlog.d(TAG, "Sending SMS by IP pending.");
-                    Bundle resultExtras = getResultExtras(false);
-                    if (resultExtras != null && resultExtras.containsKey("messageref")) {
-                        mTracker.mMessageRef = resultExtras.getInt("messageref");
-                        Rlog.d(TAG, "messageref = " + mTracker.mMessageRef);
-                    } else {
-                        Rlog.e(TAG, "Can't find messageref in result extras.");
-                    }
-                    sendPendingList.add(mTracker);
-                } else {
-                    Rlog.d(TAG, "Sending SMS by IP failed.");
-                    sendSmsByPstn(mTracker);
-                }
-            } else {
-                Rlog.e(TAG, "unexpected BroadcastReceiver action: " + action);
-            }
-        }
-    }
-
-    /**
      * Send a multi-part text based SMS.
      *  @param destAddr the address to send the message to
      * @param scAddr is the service center address or null to use
@@ -613,6 +828,8 @@
             encodingForParts[i] = details;
         }
 
+        SmsTracker[] trackers = new SmsTracker[msgCount];
+
         // States to track at the message level (for all parts)
         final AtomicInteger unsentPartCount = new AtomicInteger(msgCount);
         final AtomicBoolean anyPartFailed = new AtomicBoolean(false);
@@ -648,23 +865,46 @@
                 deliveryIntent = deliveryIntents.get(i);
             }
 
-            sendNewSubmitPdu(destAddr, scAddr, parts.get(i), smsHeader, encoding,
-                    sentIntent, deliveryIntent, (i == (msgCount - 1)),
-                    unsentPartCount, anyPartFailed, messageUri, fullMessageText);
+            trackers[i] =
+                getNewSubmitPduTracker(destAddr, scAddr, parts.get(i), smsHeader, encoding,
+                        sentIntent, deliveryIntent, (i == (msgCount - 1)),
+                        unsentPartCount, anyPartFailed, messageUri, fullMessageText);
+        }
+
+        if (parts == null || trackers == null || trackers.length == 0
+                || trackers[0] == null) {
+            Rlog.e(TAG, "Cannot send multipart text. parts=" + parts + " trackers=" + trackers);
+            return;
+        }
+
+        String carrierPackage = getCarrierAppPackageName();
+        if (carrierPackage != null) {
+            Rlog.d(TAG, "Found carrier package.");
+            MultipartSmsSender smsSender = new MultipartSmsSender(parts, trackers);
+            smsSender.sendSmsByCarrierApp(carrierPackage, new MultipartSmsSenderCallback(smsSender));
+        } else {
+            Rlog.v(TAG, "No carrier package.");
+            for (SmsTracker tracker : trackers) {
+                if (tracker != null) {
+                    sendSubmitPdu(tracker);
+                } else {
+                    Rlog.e(TAG, "Null tracker.");
+                }
+            }
         }
     }
 
     /**
-     * Create a new SubmitPdu and send it.
+     * Create a new SubmitPdu and return the SMS tracker.
      */
-    protected abstract void sendNewSubmitPdu(String destinationAddress, String scAddress,
+    protected abstract SmsTracker getNewSubmitPduTracker(String destinationAddress, String scAddress,
             String message, SmsHeader smsHeader, int encoding,
             PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart,
             AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
             String fullMessageText);
 
     /**
-     * Send a SMS
+     * Send an SMS
      * @param tracker will contain:
      * -smsc the SMSC to send the message through, or NULL for the
      *  default SMSC
@@ -1488,17 +1728,16 @@
         return sb.toString();
     }
 
-    protected String getCarrierAppPackageName(Intent intent) {
+    protected String getCarrierAppPackageName() {
         UiccCard card = UiccController.getInstance().getUiccCard();
         if (card == null) {
             return null;
         }
 
         List<String> carrierPackages = card.getCarrierPackageNamesForIntent(
-            mContext.getPackageManager(), intent);
+            mContext.getPackageManager(), new Intent(CarrierMessagingService.SERVICE_INTERFACE));
         return (carrierPackages != null && carrierPackages.size() == 1) ?
                 carrierPackages.get(0) : null;
-
     }
 
     protected int getSubId() {
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index 13c6ead..76823bd 100644
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -25,6 +25,7 @@
 import android.os.Registrant;
 import android.os.RegistrantList;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.telephony.CellInfo;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
@@ -103,8 +104,10 @@
      */
     protected boolean mDontPollSignalStrength = false;
 
-    protected RegistrantList mRoamingOnRegistrants = new RegistrantList();
-    protected RegistrantList mRoamingOffRegistrants = new RegistrantList();
+    protected RegistrantList mVoiceRoamingOnRegistrants = new RegistrantList();
+    protected RegistrantList mVoiceRoamingOffRegistrants = new RegistrantList();
+    protected RegistrantList mDataRoamingOnRegistrants = new RegistrantList();
+    protected RegistrantList mDataRoamingOffRegistrants = new RegistrantList();
     protected RegistrantList mAttachedRegistrants = new RegistrantList();
     protected RegistrantList mDetachedRegistrants = new RegistrantList();
     protected RegistrantList mDataRegStateOrRatChangedRegistrants = new RegistrantList();
@@ -334,45 +337,87 @@
     }
 
     /**
-     * Registration point for combined roaming on
+     * Registration point for combined roaming on of mobile voice
      * combined roaming is true when roaming is true and ONS differs SPN
      *
      * @param h handler to notify
      * @param what what code of message when delivered
      * @param obj placed in Message.obj
      */
-    public  void registerForRoamingOn(Handler h, int what, Object obj) {
+    public void registerForVoiceRoamingOn(Handler h, int what, Object obj) {
         Registrant r = new Registrant(h, what, obj);
-        mRoamingOnRegistrants.add(r);
+        mVoiceRoamingOnRegistrants.add(r);
 
-        if (mSS.getRoaming()) {
+        if (mSS.getVoiceRoaming()) {
             r.notifyRegistrant();
         }
     }
 
-    public  void unregisterForRoamingOn(Handler h) {
-        mRoamingOnRegistrants.remove(h);
+    public void unregisterForVoiceRoamingOn(Handler h) {
+        mVoiceRoamingOnRegistrants.remove(h);
     }
 
     /**
-     * Registration point for combined roaming off
+     * Registration point for roaming off of mobile voice
      * combined roaming is true when roaming is true and ONS differs SPN
      *
      * @param h handler to notify
      * @param what what code of message when delivered
      * @param obj placed in Message.obj
      */
-    public  void registerForRoamingOff(Handler h, int what, Object obj) {
+    public void registerForVoiceRoamingOff(Handler h, int what, Object obj) {
         Registrant r = new Registrant(h, what, obj);
-        mRoamingOffRegistrants.add(r);
+        mVoiceRoamingOffRegistrants.add(r);
 
-        if (!mSS.getRoaming()) {
+        if (!mSS.getVoiceRoaming()) {
             r.notifyRegistrant();
         }
     }
 
-    public  void unregisterForRoamingOff(Handler h) {
-        mRoamingOffRegistrants.remove(h);
+    public void unregisterForVoiceRoamingOff(Handler h) {
+        mVoiceRoamingOffRegistrants.remove(h);
+    }
+
+    /**
+     * Registration point for combined roaming on of mobile data
+     * combined roaming is true when roaming is true and ONS differs SPN
+     *
+     * @param h handler to notify
+     * @param what what code of message when delivered
+     * @param obj placed in Message.obj
+     */
+    public void registerForDataRoamingOn(Handler h, int what, Object obj) {
+        Registrant r = new Registrant(h, what, obj);
+        mDataRoamingOnRegistrants.add(r);
+
+        if (mSS.getDataRoaming()) {
+            r.notifyRegistrant();
+        }
+    }
+
+    public void unregisterForDataRoamingOn(Handler h) {
+        mDataRoamingOnRegistrants.remove(h);
+    }
+
+    /**
+     * Registration point for roaming off of mobile data
+     * combined roaming is true when roaming is true and ONS differs SPN
+     *
+     * @param h handler to notify
+     * @param what what code of message when delivered
+     * @param obj placed in Message.obj
+     */
+    public void registerForDataRoamingOff(Handler h, int what, Object obj) {
+        Registrant r = new Registrant(h, what, obj);
+        mDataRoamingOffRegistrants.add(r);
+
+        if (!mSS.getDataRoaming()) {
+            r.notifyRegistrant();
+        }
+    }
+
+    public void unregisterForDataRoamingOff(Handler h) {
+        mDataRoamingOffRegistrants.remove(h);
     }
 
     /**
@@ -887,4 +932,45 @@
             MccTable.updateMccMncConfiguration(context, newOp, true);
         }
     }
+
+    /**
+     * Check ISO country by MCC to see if phone is roaming in same registered country
+     */
+    protected boolean inSameCountry(String operatorNumeric) {
+        if (TextUtils.isEmpty(operatorNumeric) || (operatorNumeric.length() < 5)) {
+            // Not a valid network
+            return false;
+        }
+        final String homeNumeric = getHomeOperatorNumeric();
+        if (TextUtils.isEmpty(homeNumeric) || (homeNumeric.length() < 5)) {
+            // Not a valid SIM MCC
+            return false;
+        }
+        boolean inSameCountry = true;
+        final String networkMCC = operatorNumeric.substring(0, 3);
+        final String homeMCC = homeNumeric.substring(0, 3);
+        final String networkCountry = MccTable.countryCodeForMcc(Integer.parseInt(networkMCC));
+        final String homeCountry = MccTable.countryCodeForMcc(Integer.parseInt(homeMCC));
+        if (networkCountry.isEmpty() || homeCountry.isEmpty()) {
+            // Not a valid country
+            return false;
+        }
+        inSameCountry = homeCountry.equals(networkCountry);
+        if (inSameCountry) {
+            return inSameCountry;
+        }
+        // special same country cases
+        if ("us".equals(homeCountry) && "vi".equals(networkCountry)) {
+            inSameCountry = true;
+        } else if ("vi".equals(homeCountry) && "us".equals(networkCountry)) {
+            inSameCountry = true;
+        }
+        return inSameCountry;
+    }
+
+    protected abstract void setRoamingType(ServiceState currentServiceState);
+
+    protected String getHomeOperatorNumeric() {
+        return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "");
+    }
 }
diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java
index 15dae77..24b9a1b 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -33,6 +33,7 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.telephony.RadioAccessFamily;
 import android.telephony.Rlog;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -42,6 +43,7 @@
 import android.util.Log;
 
 import com.android.internal.telephony.ITelephonyRegistry;
+import com.android.internal.telephony.IccCardConstants.State;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -146,7 +148,7 @@
                     ar = (AsyncResult) msg.obj;
                     synchronized (mLock) {
                         mSuccess = (ar.exception == null);
-                        logd("EVENT_WRITE_MSISDN_DONE, mSuccess = "+mSuccess);
+                        if (DBG) logd("EVENT_WRITE_MSISDN_DONE, mSuccess = "+mSuccess);
                         mLock.notifyAll();
                     }
                     break;
@@ -195,7 +197,7 @@
                 ServiceManager.addService("isub", this);
         }
 
-        logdl("[SubscriptionController] init by Context");
+        if (DBG) logdl("[SubscriptionController] init by Context");
     }
 
     private boolean isSubInfoReady() {
@@ -210,7 +212,7 @@
                 ServiceManager.addService("isub", this);
         }
 
-        logdl("[SubscriptionController] init by Phone");
+        if (DBG) logdl("[SubscriptionController] init by Phone");
     }
 
     /**
@@ -297,10 +299,12 @@
         // FIXME: consider stick this into database too
         String countryIso = getSubscriptionCountryIso(id);
 
-        logd("[getSubInfoRecord] id:" + id + " iccid:" + iccId + " simSlotIndex:" + simSlotIndex
+        if (DBG) {
+            logd("[getSubInfoRecord] id:" + id + " iccid:" + iccId + " simSlotIndex:" + simSlotIndex
                 + " displayName:" + displayName + " nameSource:" + nameSource
                 + " iconTint:" + iconTint + " number:" + number + " dataRoaming:" + dataRoaming
                 + " mcc:" + mcc + " mnc:" + mnc + " countIso:" + countryIso);
+        }
 
         return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
                 nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso);
@@ -329,7 +333,7 @@
      * @return Array list of queried result from database
      */
      private List<SubscriptionInfo> getSubInfo(String selection, Object queryKey) {
-        logd("selection:" + selection + " " + queryKey);
+        if (DBG) logd("selection:" + selection + " " + queryKey);
         String[] selectionArgs = null;
         if (queryKey != null) {
             selectionArgs = new String[] {queryKey.toString()};
@@ -351,7 +355,7 @@
                 }
                 }
             } else {
-                logd("Query fail");
+                if (DBG) logd("Query fail");
             }
         } finally {
             if (cursor != null) {
@@ -400,11 +404,11 @@
         List<SubscriptionInfo> subList = getActiveSubscriptionInfoList();
         for (SubscriptionInfo si : subList) {
             if (si.getSubscriptionId() == subId) {
-                logd("[getActiveSubInfoForSubscriber]+ subId=" + subId + " subInfo=" + si);
+                if (DBG) logd("[getActiveSubInfoForSubscriber]+ subId=" + subId + " subInfo=" + si);
                 return si;
             }
         }
-        logd("[getActiveSubInfoForSubscriber]+ subId=" + subId + " subInfo=null");
+        if (DBG) logd("[getActiveSubInfoForSubscriber]+ subId=" + subId + " subInfo=null");
         return null;
     }
 
@@ -420,11 +424,11 @@
         List<SubscriptionInfo> subList = getActiveSubscriptionInfoList();
         for (SubscriptionInfo si : subList) {
             if (si.getIccId() == iccId) {
-                logd("[getActiveSubInfoUsingIccId]+ iccId=" + iccId + " subInfo=" + si);
+                if (DBG) logd("[getActiveSubInfoUsingIccId]+ iccId=" + iccId + " subInfo=" + si);
                 return si;
             }
         }
-        logd("[getActiveSubInfoUsingIccId]+ iccId=" + iccId + " subInfo=null");
+        if (DBG) logd("[getActiveSubInfoUsingIccId]+ iccId=" + iccId + " subInfo=null");
         return null;
     }
 
@@ -440,12 +444,16 @@
         List<SubscriptionInfo> subList = getActiveSubscriptionInfoList();
         for (SubscriptionInfo si : subList) {
             if (si.getSimSlotIndex() == slotIdx) {
-                logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIdx=" + slotIdx
+                if (DBG) {
+                    logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIdx=" + slotIdx
                         + " subId=" + si);
+                }
                 return si;
             }
         }
-        logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIdx=" + slotIdx + " subId=null");
+        if (DBG) {
+            logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIdx=" + slotIdx + " subId=null");
+        }
         return null;
     }
 
@@ -456,15 +464,15 @@
      */
     @Override
     public List<SubscriptionInfo> getAllSubInfoList() {
-        logd("[getAllSubInfoList]+");
+        if (DBG) logd("[getAllSubInfoList]+");
         enforceSubscriptionPermission();
 
         List<SubscriptionInfo> subList = null;
         subList = getSubInfo(null, null);
         if (subList != null) {
-            logd("[getAllSubInfoList]- " + subList.size() + " infos return");
+            if (DBG) logd("[getAllSubInfoList]- " + subList.size() + " infos return");
         } else {
-            logd("[getAllSubInfoList]- no info return");
+            if (DBG) logd("[getAllSubInfoList]- no info return");
         }
 
         return subList;
@@ -477,12 +485,12 @@
     @Override
     public List<SubscriptionInfo> getActiveSubscriptionInfoList() {
         enforceSubscriptionPermission();
-        logdl("[getActiveSubInfoList]+");
+        if (DBG) logdl("[getActiveSubInfoList]+");
 
         List<SubscriptionInfo> subList = null;
 
         if (!isSubInfoReady()) {
-            logdl("[getActiveSubInfoList] Sub Controller not ready");
+            if (DBG) logdl("[getActiveSubInfoList] Sub Controller not ready");
             return subList;
         }
 
@@ -503,9 +511,9 @@
                 }
             });
 
-            logdl("[getActiveSubInfoList]- " + subList.size() + " infos return");
+            if (DBG) logdl("[getActiveSubInfoList]- " + subList.size() + " infos return");
         } else {
-            logdl("[getActiveSubInfoList]- no info return");
+            if (DBG) logdl("[getActiveSubInfoList]- no info return");
         }
 
         return subList;
@@ -517,13 +525,13 @@
      */
     @Override
     public int getActiveSubInfoCount() {
-        logd("[getActiveSubInfoCount]+");
+        if (DBG) logd("[getActiveSubInfoCount]+");
         List<SubscriptionInfo> records = getActiveSubscriptionInfoList();
         if (records == null) {
-            logd("[getActiveSubInfoCount] records null");
+            if (DBG) logd("[getActiveSubInfoCount] records null");
             return 0;
         }
-        logd("[getActiveSubInfoCount]- count: " + records.size());
+        if (DBG) logd("[getActiveSubInfoCount]- count: " + records.size());
         return records.size();
     }
 
@@ -533,7 +541,7 @@
      */
     @Override
     public int getAllSubInfoCount() {
-        logd("[getAllSubInfoCount]+");
+        if (DBG) logd("[getAllSubInfoCount]+");
         enforceSubscriptionPermission();
 
         Cursor cursor = mContext.getContentResolver().query(SubscriptionManager.CONTENT_URI,
@@ -541,7 +549,7 @@
         try {
             if (cursor != null) {
                 int count = cursor.getCount();
-                logd("[getAllSubInfoCount]- " + count + " SUB(s) in DB");
+                if (DBG) logd("[getAllSubInfoCount]- " + count + " SUB(s) in DB");
                 return count;
             }
         } finally {
@@ -549,7 +557,7 @@
                 cursor.close();
             }
         }
-        logd("[getAllSubInfoCount]- no SUB in DB");
+        if (DBG) logd("[getAllSubInfoCount]- no SUB in DB");
 
         return 0;
     }
@@ -571,24 +579,26 @@
      */
     @Override
     public int addSubInfoRecord(String iccId, int slotId) {
-        logdl("[addSubInfoRecord]+ iccId:" + iccId + " slotId:" + slotId);
+        if (DBG) logdl("[addSubInfoRecord]+ iccId:" + iccId + " slotId:" + slotId);
         enforceSubscriptionPermission();
 
         if (iccId == null) {
-            logdl("[addSubInfoRecord]- null iccId");
+            if (DBG) logdl("[addSubInfoRecord]- null iccId");
             return -1;
         }
 
         int[] subIds = getSubId(slotId);
         if (subIds == null || subIds.length == 0) {
-            logdl("[addSubInfoRecord]- getSubId failed subIds == null || length == 0 subIds="
+            if (DBG) {
+                logdl("[addSubInfoRecord]- getSubId failed subIds == null || length == 0 subIds="
                     + subIds);
+            }
             return -1;
         }
 
         String nameToSet;
         String CarrierName = TelephonyManager.getDefault().getSimOperator(subIds[0]);
-        logdl("[addSubInfoRecord] CarrierName = " + CarrierName);
+        if (DBG) logdl("[addSubInfoRecord] CarrierName = " + CarrierName);
         String simCarrierName =
                 TelephonyManager.getDefault().getSimOperatorName(subIds[0]);
 
@@ -597,8 +607,8 @@
         } else {
             nameToSet = "CARD " + Integer.toString(slotId + 1);
         }
-        logdl("[addSubInfoRecord] sim name = " + nameToSet);
-        logdl("[addSubInfoRecord] carrier name = " + simCarrierName);
+        if (DBG) logdl("[addSubInfoRecord] sim name = " + nameToSet);
+        if (DBG) logdl("[addSubInfoRecord] carrier name = " + simCarrierName);
 
         ContentResolver resolver = mContext.getContentResolver();
         Cursor cursor = resolver.query(SubscriptionManager.CONTENT_URI,
@@ -620,7 +630,7 @@
                         !TextUtils.isEmpty(simCarrierName) ? simCarrierName :
                         mContext.getString(com.android.internal.R.string.unknownName));
                 Uri uri = resolver.insert(SubscriptionManager.CONTENT_URI, value);
-                logdl("[addSubInfoRecord] New record created: " + uri);
+                if (DBG) logdl("[addSubInfoRecord] New record created: " + uri);
             } else {
                 int subId = cursor.getInt(0);
                 int oldSimInfoId = cursor.getInt(1);
@@ -645,7 +655,7 @@
                             "=" + Long.toString(subId), null);
                 }
 
-                logdl("[addSubInfoRecord] Record already exists");
+                if (DBG) logdl("[addSubInfoRecord] Record already exists");
             }
         } finally {
             if (cursor != null) {
@@ -674,9 +684,12 @@
                         mSlotIdxToSubId.put(slotId, subId);
                         int subIdCountMax = getActiveSubInfoCountMax();
                         int defaultSubId = getDefaultSubId();
-                        logdl("[addSubInfoRecord] mSlotIdxToSubId.size=" + mSlotIdxToSubId.size()
+                        if (DBG) {
+                            logdl("[addSubInfoRecord]"
+                                + " mSlotIdxToSubId.size=" + mSlotIdxToSubId.size()
                                 + " slotId=" + slotId + " subId=" + subId
                                 + " defaultSubId=" + defaultSubId + " simCount=" + subIdCountMax);
+                        }
 
                         // Set the default sub if not set or if single sim device
                         if (!SubscriptionManager.isValidSubId(defaultSubId) || subIdCountMax == 1) {
@@ -684,16 +697,20 @@
                         }
                         // If single sim device, set this subscription as the default for everything
                         if (subIdCountMax == 1) {
-                            logdl("[addSubInfoRecord] one sim set defaults to subId=" + subId);
+                            if (DBG) {
+                                logdl("[addSubInfoRecord] one sim set defaults to subId=" + subId);
+                            }
                             setDefaultDataSubId(subId);
                             setDefaultSmsSubId(subId);
                             setDefaultVoiceSubId(subId);
                         }
                     } else {
-                        logdl("[addSubInfoRecord] currentSubId != null"
+                        if (DBG) {
+                            logdl("[addSubInfoRecord] currentSubId != null"
                                 + " && currentSubId is valid, IGNORE");
+                        }
                     }
-                    logdl("[addSubInfoRecord] hashmap(" + slotId + "," + subId + ")");
+                    if (DBG) logdl("[addSubInfoRecord] hashmap(" + slotId + "," + subId + ")");
                 } while (cursor.moveToNext());
             }
         } finally {
@@ -705,7 +722,7 @@
         // Once the records are loaded, notify DcTracker
         updateAllDataConnectionTrackers();
 
-        logdl("[addSubInfoRecord]- info size=" + mSlotIdxToSubId.size());
+        if (DBG) logdl("[addSubInfoRecord]- info size=" + mSlotIdxToSubId.size());
         return 0;
     }
 
@@ -717,13 +734,13 @@
      */
     @Override
     public int setIconTint(int tint, int subId) {
-        logd("[setIconTint]+ tint:" + tint + " subId:" + subId);
+        if (DBG) logd("[setIconTint]+ tint:" + tint + " subId:" + subId);
         enforceSubscriptionPermission();
 
         validateSubId(subId);
         ContentValues value = new ContentValues(1);
         value.put(SubscriptionManager.COLOR, tint);
-        logd("[setIconTint]- tint:" + tint + " set");
+        if (DBG) logd("[setIconTint]- tint:" + tint + " set");
 
         int result = mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, value,
                 SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + Long.toString(subId), null);
@@ -753,8 +770,10 @@
      */
     @Override
     public int setDisplayNameUsingSrc(String displayName, int subId, long nameSource) {
-        logd("[setDisplayName]+  displayName:" + displayName + " subId:" + subId
+        if (DBG) {
+            logd("[setDisplayName]+  displayName:" + displayName + " subId:" + subId
                 + " nameSource:" + nameSource);
+        }
         enforceSubscriptionPermission();
 
         validateSubId(subId);
@@ -767,10 +786,10 @@
         ContentValues value = new ContentValues(1);
         value.put(SubscriptionManager.DISPLAY_NAME, nameToSet);
         if (nameSource >= SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE) {
-            logd("Set nameSource=" + nameSource);
+            if (DBG) logd("Set nameSource=" + nameSource);
             value.put(SubscriptionManager.NAME_SOURCE, nameSource);
         }
-        logd("[setDisplayName]- mDisplayName:" + nameToSet + " set");
+        if (DBG) logd("[setDisplayName]- mDisplayName:" + nameToSet + " set");
 
         int result = mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, value,
                 SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + Long.toString(subId), null);
@@ -787,7 +806,7 @@
      */
     @Override
     public int setDisplayNumber(String number, int subId) {
-        logd("[setDisplayNumber]+ number:" + number + " subId:" + subId);
+        if (DBG) logd("[setDisplayNumber]+ number:" + number + " subId:" + subId);
         enforceSubscriptionPermission();
 
         validateSubId(subId);
@@ -796,12 +815,12 @@
 
         if (number == null || phoneId < 0 ||
                 phoneId >= TelephonyManager.getDefault().getPhoneCount()) {
-            logd("[setDispalyNumber]- fail");
+            if (DBG) logd("[setDispalyNumber]- fail");
             return -1;
         }
         ContentValues value = new ContentValues(1);
         value.put(SubscriptionManager.NUMBER, number);
-        logd("[setDisplayNumber]- number:" + number + " set");
+        if (DBG) logd("[setDisplayNumber]- number:" + number + " set");
 
         Phone phone = sProxyPhones[phoneId];
         String alphaTag = TelephonyManager.getDefault().getLine1AlphaTagForSubscriber(subId);
@@ -823,7 +842,7 @@
             result = mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, value,
                     SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID
                         + "=" + Long.toString(subId), null);
-            logd("[setDisplayNumber]- update result :" + result);
+            if (DBG) logd("[setDisplayNumber]- update result :" + result);
             notifySubscriptionInfoChanged();
         }
 
@@ -838,17 +857,17 @@
      */
     @Override
     public int setDataRoaming(int roaming, int subId) {
-        logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId);
+        if (DBG) logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId);
         enforceSubscriptionPermission();
 
         validateSubId(subId);
         if (roaming < 0) {
-            logd("[setDataRoaming]- fail");
+            if (DBG) logd("[setDataRoaming]- fail");
             return -1;
         }
         ContentValues value = new ContentValues(1);
         value.put(SubscriptionManager.DATA_ROAMING, roaming);
-        logd("[setDataRoaming]- roaming:" + roaming + " set");
+        if (DBG) logd("[setDataRoaming]- roaming:" + roaming + " set");
 
         int result = mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, value,
                 SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + Long.toString(subId), null);
@@ -870,9 +889,9 @@
             mcc = Integer.parseInt(mccMnc.substring(0,3));
             mnc = Integer.parseInt(mccMnc.substring(3));
         } catch (NumberFormatException e) {
-            logd("[setMccMnc] - couldn't parse mcc/mnc: " + mccMnc);
+            loge("[setMccMnc] - couldn't parse mcc/mnc: " + mccMnc);
         }
-        logd("[setMccMnc]+ mcc/mnc:" + mcc + "/" + mnc + " subId:" + subId);
+        if (DBG) logd("[setMccMnc]+ mcc/mnc:" + mcc + "/" + mnc + " subId:" + subId);
         ContentValues value = new ContentValues(2);
         value.put(SubscriptionManager.MCC, mcc);
         value.put(SubscriptionManager.MNC, mnc);
@@ -893,7 +912,7 @@
             subId = getDefaultSubId();
         }
         if (!SubscriptionManager.isValidSubId(subId)) {
-            logd("[getSlotId]- subId invalid");
+            if (DBG) logd("[getSlotId]- subId invalid");
             return SubscriptionManager.INVALID_SIM_SLOT_INDEX;
         }
 
@@ -901,7 +920,7 @@
 
         if (size == 0)
         {
-            logd("[getSlotId]- size == 0, return SIM_NOT_INSERTED instead");
+            if (DBG) logd("[getSlotId]- size == 0, return SIM_NOT_INSERTED instead");
             return SubscriptionManager.SIM_NOT_INSERTED;
         }
 
@@ -916,7 +935,7 @@
             }
         }
 
-        logd("[getSlotId]- return fail");
+        if (DBG) logd("[getSlotId]- return fail");
         return SubscriptionManager.INVALID_SIM_SLOT_INDEX;
     }
 
@@ -936,19 +955,22 @@
         // getDefaultSubId which makes a best guess.
         if (slotIdx == SubscriptionManager.DEFAULT_SIM_SLOT_INDEX) {
             slotIdx = getSlotId(getDefaultSubId());
-            logd("[getSubId] map default slotIdx=" + slotIdx);
+            if (DBG) logd("[getSubId] map default slotIdx=" + slotIdx);
         }
 
         // Check that we have a valid SlotIdx
         if (!SubscriptionManager.isValidSlotId(slotIdx)) {
-            logd("[getSubId]- invalid slotIdx=" + slotIdx);
+            if (DBG) logd("[getSubId]- invalid slotIdx=" + slotIdx);
             return null;
         }
 
         // Check if we've got any SubscriptionInfo records using slotIdToSubId as a surrogate.
         int size = mSlotIdxToSubId.size();
         if (size == 0) {
-            logd("[getSubId]- mSlotIdToSubIdMap.size == 0, return DummySubIds slotIdx=" + slotIdx);
+            if (DBG) {
+                logd("[getSubId]- mSlotIdToSubIdMap.size == 0, return DummySubIds slotIdx="
+                        + slotIdx);
+            }
             return getDummySubIds(slotIdx);
         }
 
@@ -972,7 +994,7 @@
             if (VDBG) logd("[getSubId]- subIdArr=" + subIdArr);
             return subIdArr;
         } else {
-            logd("[getSubId]- numSubIds == 0, return DummySubIds slotIdx=" + slotIdx);
+            if (DBG) logd("[getSubId]- numSubIds == 0, return DummySubIds slotIdx=" + slotIdx);
             return getDummySubIds(slotIdx);
         }
     }
@@ -984,18 +1006,21 @@
 
         if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
             subId = getDefaultSubId();
-            logdl("[getPhoneId] asked for default subId=" + subId);
+            if (DBG) logdl("[getPhoneId] asked for default subId=" + subId);
         }
 
         if (!SubscriptionManager.isValidSubId(subId)) {
-            logdl("[getPhoneId]- invalid subId return=" + SubscriptionManager.INVALID_PHONE_INDEX);
+            if (DBG) {
+                logdl("[getPhoneId]- invalid subId return="
+                        + SubscriptionManager.INVALID_PHONE_INDEX);
+            }
             return SubscriptionManager.INVALID_PHONE_INDEX;
         }
 
         int size = mSlotIdxToSubId.size();
         if (size == 0) {
             phoneId = mDefaultPhoneId;
-            logdl("[getPhoneId]- no sims, returning default phoneId=" + phoneId);
+            if (DBG) logdl("[getPhoneId]- no sims, returning default phoneId=" + phoneId);
             return phoneId;
         }
 
@@ -1011,7 +1036,9 @@
         }
 
         phoneId = mDefaultPhoneId;
-        logdl("[getPhoneId]- subId=" + subId + " not found return default phoneId=" + phoneId);
+        if (DBG) {
+            logdl("[getPhoneId]- subId=" + subId + " not found return default phoneId=" + phoneId);
+        }
         return phoneId;
 
     }
@@ -1027,8 +1054,10 @@
             for (int i = 0; i < numSubs; i++) {
                 dummyValues[i] = SubscriptionManager.DUMMY_SUBSCRIPTION_ID_BASE - slotIdx;
             }
-            logd("getDummySubIds: slotIdx=" + slotIdx
+            if (DBG) {
+                logd("getDummySubIds: slotIdx=" + slotIdx
                     + " return " + numSubs + " DummySubIds with each subId=" + dummyValues[0]);
+            }
             return dummyValues;
         } else {
             return null;
@@ -1041,17 +1070,17 @@
     @Override
     public int clearSubInfo() {
         enforceSubscriptionPermission();
-        logd("[clearSubInfo]+");
+        if (DBG) logd("[clearSubInfo]+");
 
         int size = mSlotIdxToSubId.size();
 
         if (size == 0) {
-            logdl("[clearSubInfo]- no simInfo size=" + size);
+            if (DBG) logdl("[clearSubInfo]- no simInfo size=" + size);
             return 0;
         }
 
         mSlotIdxToSubId.clear();
-        logdl("[clearSubInfo]- clear size=" + size);
+        if (DBG) logdl("[clearSubInfo]- clear size=" + size);
         return size;
     }
 
@@ -1099,7 +1128,7 @@
         if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
             throw new RuntimeException("setDefaultSmsSubId called with DEFAULT_SUB_ID");
         }
-        logdl("[setDefaultSmsSubId] subId=" + subId);
+        if (DBG) logdl("[setDefaultSmsSubId] subId=" + subId);
         Settings.Global.putInt(mContext.getContentResolver(),
                 Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION, subId);
         broadcastDefaultSmsSubIdChanged(subId);
@@ -1107,7 +1136,7 @@
 
     private void broadcastDefaultSmsSubIdChanged(int subId) {
         // Broadcast an Intent for default sms sub change
-        logdl("[broadcastDefaultSmsSubIdChanged] subId=" + subId);
+        if (DBG) logdl("[broadcastDefaultSmsSubIdChanged] subId=" + subId);
         Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED);
         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
         intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
@@ -1128,7 +1157,7 @@
         if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
             throw new RuntimeException("setDefaultVoiceSubId called with DEFAULT_SUB_ID");
         }
-        logdl("[setDefaultVoiceSubId] subId=" + subId);
+        if (DBG) logdl("[setDefaultVoiceSubId] subId=" + subId);
         Settings.Global.putInt(mContext.getContentResolver(),
                 Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, subId);
         broadcastDefaultVoiceSubIdChanged(subId);
@@ -1136,7 +1165,7 @@
 
     private void broadcastDefaultVoiceSubIdChanged(int subId) {
         // Broadcast an Intent for default voice sub change
-        logdl("[broadcastDefaultVoiceSubIdChanged] subId=" + subId);
+        if (DBG) logdl("[broadcastDefaultVoiceSubIdChanged] subId=" + subId);
         Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED);
         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
         intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
@@ -1166,29 +1195,50 @@
         if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
             throw new RuntimeException("setDefaultDataSubId called with DEFAULT_SUB_ID");
         }
-        logdl("[setDefaultDataSubId] subId=" + subId);
+        if (DBG) logdl("[setDefaultDataSubId] subId=" + subId);
+
+        int len = sProxyPhones.length;
+        logdl("[setDefaultDataSubId] num phones=" + len);
+
+        RadioAccessFamily[] rafs = new RadioAccessFamily[len];
+        for (int phoneId = 0; phoneId < len; phoneId++) {
+            PhoneProxy phone = sProxyPhones[phoneId];
+            int raf = phone.getRadioAccessFamily();
+            int id = phone.getSubId();
+            logdl("[setDefaultDataSubId] phoneId=" + phoneId + " subId=" + id + " RAF=" + raf);
+            // TODO(stuartscott): Need to set 3G or 2G depending on user's preference and modem
+            // supported capabilities
+            if (id == subId) {
+                raf |= RadioAccessFamily.RAF_UMTS;
+            } else {
+                raf &= ~RadioAccessFamily.RAF_UMTS;
+            }
+            logdl("[setDefaultDataSubId] newRAF=" + raf);
+            rafs[phoneId] = new RadioAccessFamily(phoneId, raf);
+        }
+        ProxyController.getInstance().setRadioCapability(rafs);
+
+        // FIXME is this still needed?
+        updateAllDataConnectionTrackers();
 
         Settings.Global.putInt(mContext.getContentResolver(),
                 Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION, subId);
         broadcastDefaultDataSubIdChanged(subId);
-
-        // FIXME is this still needed?
-        updateAllDataConnectionTrackers();
     }
 
     private void updateAllDataConnectionTrackers() {
         // Tell Phone Proxies to update data connection tracker
         int len = sProxyPhones.length;
-        logdl("[updateAllDataConnectionTrackers] sProxyPhones.length=" + len);
+        if (DBG) logdl("[updateAllDataConnectionTrackers] sProxyPhones.length=" + len);
         for (int phoneId = 0; phoneId < len; phoneId++) {
-            logdl("[updateAllDataConnectionTrackers] phoneId=" + phoneId);
+            if (DBG) logdl("[updateAllDataConnectionTrackers] phoneId=" + phoneId);
             sProxyPhones[phoneId].updateDataConnectionTracker();
         }
     }
 
     private void broadcastDefaultDataSubIdChanged(int subId) {
         // Broadcast an Intent for default data sub change
-        logdl("[broadcastDefaultDataSubIdChanged] subId=" + subId);
+        if (DBG) logdl("[broadcastDefaultDataSubIdChanged] subId=" + subId);
         Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
         intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
@@ -1204,12 +1254,12 @@
         if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
             throw new RuntimeException("setDefaultSubId called with DEFAULT_SUB_ID");
         }
-        logdl("[setDefaultSubId] subId=" + subId);
+        if (DBG) logdl("[setDefaultSubId] subId=" + subId);
         if (SubscriptionManager.isValidSubId(subId)) {
             int phoneId = getPhoneId(subId);
             if (phoneId >= 0 && (phoneId < TelephonyManager.getDefault().getPhoneCount()
                     || TelephonyManager.getDefault().getSimCount() == 1)) {
-                logdl("[setDefaultSubId] set mDefaultVoiceSubId=" + subId);
+                if (DBG) logdl("[setDefaultSubId] set mDefaultVoiceSubId=" + subId);
                 mDefaultVoiceSubId = subId;
                 // Update MCC MNC device configuration information
                 String defaultMccMnc = TelephonyManager.getDefault().getSimOperator(phoneId);
@@ -1236,42 +1286,42 @@
     @Override
     public void clearDefaultsForInactiveSubIds() {
         final List<SubscriptionInfo> records = getActiveSubscriptionInfoList();
-        logdl("[clearDefaultsForInactiveSubIds] records: " + records);
+        if (DBG) logdl("[clearDefaultsForInactiveSubIds] records: " + records);
         if (shouldDefaultBeCleared(records, getDefaultDataSubId())) {
-            logd("[clearDefaultsForInactiveSubIds] clearing default data sub id");
+            if (DBG) logd("[clearDefaultsForInactiveSubIds] clearing default data sub id");
             setDefaultDataSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
         }
         if (shouldDefaultBeCleared(records, getDefaultSmsSubId())) {
-            logdl("[clearDefaultsForInactiveSubIds] clearing default sms sub id");
+            if (DBG) logdl("[clearDefaultsForInactiveSubIds] clearing default sms sub id");
             setDefaultSmsSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
         }
         if (shouldDefaultBeCleared(records, getDefaultVoiceSubId())) {
-            logdl("[clearDefaultsForInactiveSubIds] clearing default voice sub id");
+            if (DBG) logdl("[clearDefaultsForInactiveSubIds] clearing default voice sub id");
             setDefaultVoiceSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
         }
     }
 
     private boolean shouldDefaultBeCleared(List<SubscriptionInfo> records, int subId) {
-        logdl("[shouldDefaultBeCleared: subId] " + subId);
+        if (DBG) logdl("[shouldDefaultBeCleared: subId] " + subId);
         if (records == null) {
-            logdl("[shouldDefaultBeCleared] return true no records subId=" + subId);
+            if (DBG) logdl("[shouldDefaultBeCleared] return true no records subId=" + subId);
             return true;
         }
         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
             // If the subId parameter is INVALID_SUBSCRIPTION_ID its
             // already cleared so return false.
-            logdl("[shouldDefaultBeCleared] return false only one subId, subId=" + subId);
+            if (DBG) logdl("[shouldDefaultBeCleared] return false only one subId, subId=" + subId);
             return false;
         }
         for (SubscriptionInfo record : records) {
             int id = record.getSubscriptionId();
-            logdl("[shouldDefaultBeCleared] Record.id: " + id);
+            if (DBG) logdl("[shouldDefaultBeCleared] Record.id: " + id);
             if (id == subId) {
                 logdl("[shouldDefaultBeCleared] return false subId is active, subId=" + subId);
                 return false;
             }
         }
-        logdl("[shouldDefaultBeCleared] return true not active subId=" + subId);
+        if (DBG) logdl("[shouldDefaultBeCleared] return true not active subId=" + subId);
         return true;
     }
 
@@ -1290,19 +1340,19 @@
     }
 
     public List<SubscriptionInfo> getSubInfoUsingSlotIdWithCheck(int slotId, boolean needCheck) {
-        logd("[getSubInfoUsingSlotIdWithCheck]+ slotId:" + slotId);
+        if (DBG) logd("[getSubInfoUsingSlotIdWithCheck]+ slotId:" + slotId);
         enforceSubscriptionPermission();
 
         if (slotId == SubscriptionManager.DEFAULT_SIM_SLOT_INDEX) {
             slotId = getSlotId(getDefaultSubId());
         }
         if (!SubscriptionManager.isValidSlotId(slotId)) {
-            logd("[getSubInfoUsingSlotIdWithCheck]- invalid slotId");
+            if (DBG) logd("[getSubInfoUsingSlotIdWithCheck]- invalid slotId");
             return null;
         }
 
         if (needCheck && !isSubInfoReady()) {
-            logd("[getSubInfoUsingSlotIdWithCheck]- not ready");
+            if (DBG) logd("[getSubInfoUsingSlotIdWithCheck]- not ready");
             return null;
         }
 
@@ -1329,13 +1379,13 @@
                 cursor.close();
             }
         }
-        logd("[getSubInfoUsingSlotId]- null info return");
+        if (DBG) logd("[getSubInfoUsingSlotId]- null info return");
 
         return subList;
     }
 
     private void validateSubId(int subId) {
-        logd("validateSubId subId: " + subId);
+        if (DBG) logd("validateSubId subId: " + subId);
         if (!SubscriptionManager.isValidSubId(subId)) {
             throw new RuntimeException("Invalid sub id passed as parameter");
         } else if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
@@ -1353,7 +1403,7 @@
     @Override
     public int[] getActiveSubIdList() {
         Set<Entry<Integer, Integer>> simInfoSet = mSlotIdxToSubId.entrySet();
-        logdl("[getActiveSubIdList] simInfoSet=" + simInfoSet);
+        if (DBG) logdl("[getActiveSubIdList] simInfoSet=" + simInfoSet);
 
         int[] subIdArr = new int[simInfoSet.size()];
         int i = 0;
@@ -1363,10 +1413,43 @@
             i++;
         }
 
-        logdl("[getActiveSubIdList] X subIdArr.length=" + subIdArr.length);
+        if (DBG) logdl("[getActiveSubIdList] X subIdArr.length=" + subIdArr.length);
         return subIdArr;
     }
 
+    /**
+     * Get the SIM state for the subscriber
+     * @return SIM state as the ordinal of {@See IccCardConstants.State}
+     */
+    @Override
+    public int getSimStateForSubscriber(int subId) {
+        State simState;
+        String err;
+        int phoneIdx = getPhoneId(subId);
+        if (phoneIdx < 0) {
+            simState = IccCardConstants.State.UNKNOWN;
+            err = "invalid PhoneIdx";
+        } else {
+            Phone phone = PhoneFactory.getPhone(phoneIdx);
+            if (phone == null) {
+                simState = IccCardConstants.State.UNKNOWN;
+                err = "phone == null";
+            } else {
+                IccCard icc = phone.getIccCard();
+                if (icc == null) {
+                    simState = IccCardConstants.State.UNKNOWN;
+                    err = "icc == null";
+                } else {
+                    simState = icc.getState();
+                    err = "";
+                }
+            }
+        }
+        if (DBG) logd("getSimStateForSubscriber: " + err + " simState=" + simState
+                + " ordinal=" + simState.ordinal());
+        return simState.ordinal();
+    }
+
     private static void printStackTrace(String msg) {
         RuntimeException re = new RuntimeException();
         slogd("StackTrace - " + msg);
diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
index 7135106..f17bef8 100644
--- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
+++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.telephony;
 
+import android.app.ActivityManagerNative;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.ContentResolver;
@@ -27,6 +28,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.preference.PreferenceManager;
 import android.provider.Settings;
 import android.telephony.Rlog;
@@ -119,13 +121,22 @@
                     return;
                 }
                 if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(simStatus)
-                        || IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(simStatus)) {
+                        || IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(simStatus)
+                        || IccCardConstants.INTENT_VALUE_ICC_INTERNAL_LOCKED.equals(simStatus)) {
                     if (mIccId[slotId] != null && mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) {
                         logd("SIM" + (slotId + 1) + " hot plug in");
                         mIccId[slotId] = null;
                         mNeedUpdate = true;
                     }
-                    queryIccId(slotId);
+                    //TODO: Use RetryManager to limit number of retries and do a exponential backoff
+                    if (((PhoneProxy)mPhone[slotId]).getIccFileHandler() != null) {
+                        queryIccId(slotId);
+                    } else {
+                        intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE,
+                                IccCardConstants.INTENT_VALUE_ICC_INTERNAL_LOCKED);
+                        ActivityManagerNative.broadcastStickyIntent(intent,
+                                "android.permission.READ_PHONE_STATE", UserHandle.USER_ALL);
+                    }
                 } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(simStatus)) {
                     queryIccId(slotId);
                     if (mTelephonyMgr == null) {
diff --git a/src/java/com/android/internal/telephony/UiccSmsController.java b/src/java/com/android/internal/telephony/UiccSmsController.java
index c0f3f45..86c0ef6 100755
--- a/src/java/com/android/internal/telephony/UiccSmsController.java
+++ b/src/java/com/android/internal/telephony/UiccSmsController.java
@@ -283,12 +283,6 @@
     }
 
     @Override
-    public void updateSmsSendStatus(int messageRef, boolean success) {
-        getIccSmsInterfaceManager(SubscriptionManager.getDefaultSmsSubId())
-            .updateSmsSendStatus(messageRef, success);
-    }
-
-    @Override
     public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) {
         injectSmsPdu(SubscriptionManager.getDefaultSmsSubId(), pdu, format, receivedIntent);
     }
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/src/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index 58b5020..ff7a75d 100644
--- a/src/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -241,6 +241,8 @@
             mNewSS.setRilDataRadioTechnology(type);
             int dataRegState = regCodeToServiceState(regState);
             mNewSS.setDataRegState(dataRegState);
+            // voice roaming state in done while handling EVENT_POLL_STATE_REGISTRATION_CDMA
+            mNewSS.setDataRoaming(regCodeIsRoaming(regState));
             if (DBG) {
                 log("handlPollStateResultMessage: CdmaLteSST setDataRegState=" + dataRegState
                         + " regState=" + regState
@@ -328,9 +330,13 @@
 
         boolean hasChanged = !mNewSS.equals(mSS);
 
-        boolean hasRoamingOn = !mSS.getRoaming() && mNewSS.getRoaming();
+        boolean hasVoiceRoamingOn = !mSS.getVoiceRoaming() && mNewSS.getVoiceRoaming();
 
-        boolean hasRoamingOff = mSS.getRoaming() && !mNewSS.getRoaming();
+        boolean hasVoiceRoamingOff = mSS.getVoiceRoaming() && !mNewSS.getVoiceRoaming();
+
+        boolean hasDataRoamingOn = !mSS.getDataRoaming() && mNewSS.getDataRoaming();
+
+        boolean hasDataRoamingOff = mSS.getDataRoaming() && !mNewSS.getDataRoaming();
 
         boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc);
 
@@ -361,8 +367,10 @@
                 + " hasVoiceRadioTechnologyChanged= " + hasVoiceRadioTechnologyChanged
                 + " hasDataRadioTechnologyChanged=" + hasDataRadioTechnologyChanged
                 + " hasChanged=" + hasChanged
-                + " hasRoamingOn=" + hasRoamingOn
-                + " hasRoamingOff=" + hasRoamingOff
+                + " hasVoiceRoamingOn=" + hasVoiceRoamingOn
+                + " hasVoiceRoamingOff=" + hasVoiceRoamingOff
+                + " hasDataRoamingOn=" + hasDataRoamingOn
+                + " hasDataRoamingOff=" + hasDataRoamingOff
                 + " hasLocationChanged=" + hasLocationChanged
                 + " has4gHandoff = " + has4gHandoff
                 + " hasMultiApnSupport=" + hasMultiApnSupport
@@ -487,9 +495,11 @@
             }
 
             mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
-                    mSS.getRoaming() ? "true" : "false");
+                    (mSS.getVoiceRoaming() || mSS.getDataRoaming()) ? "true" : "false");
 
             updateSpnDisplay();
+            setRoamingType(mSS);
+            log("Broadcasting ServiceState : " + mSS);
             mPhone.notifyServiceStateChanged(mSS);
         }
 
@@ -506,12 +516,20 @@
             mPhone.notifyDataConnection(null);
         }
 
-        if (hasRoamingOn) {
-            mRoamingOnRegistrants.notifyRegistrants();
+        if (hasVoiceRoamingOn) {
+            mVoiceRoamingOnRegistrants.notifyRegistrants();
         }
 
-        if (hasRoamingOff) {
-            mRoamingOffRegistrants.notifyRegistrants();
+        if (hasVoiceRoamingOff) {
+            mVoiceRoamingOffRegistrants.notifyRegistrants();
+        }
+
+        if (hasDataRoamingOn) {
+            mDataRoamingOnRegistrants.notifyRegistrants();
+        }
+
+        if (hasDataRoamingOff) {
+            mDataRoamingOffRegistrants.notifyRegistrants();
         }
 
         if (hasLocationChanged) {
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index e557ee3..c0e157e 100755
--- a/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -20,7 +20,6 @@
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
-import android.content.BroadcastReceiver;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Message;
@@ -115,7 +114,16 @@
         HashMap map = getSmsTrackerMap(destAddr, scAddr, destPort, data, pdu);
         SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(),
                 null /*messageUri*/, false /*isExpectMore*/, null /*fullMessageText*/);
-        sendSubmitPdu(tracker);
+
+        String carrierPackage = getCarrierAppPackageName();
+        if (carrierPackage != null) {
+            Rlog.d(TAG, "Found carrier package.");
+            DataSmsSender smsSender = new DataSmsSender(tracker);
+            smsSender.sendSmsByCarrierApp(carrierPackage, new SmsSenderCallback(smsSender));
+        } else {
+            Rlog.v(TAG, "No carrier package.");
+            sendSubmitPdu(tracker);
+        }
     }
 
     /** {@inheritDoc} */
@@ -128,7 +136,16 @@
             HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu);
             SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(),
                     messageUri, false /*isExpectMore*/, text);
-            sendSubmitPdu(tracker);
+
+            String carrierPackage = getCarrierAppPackageName();
+            if (carrierPackage != null) {
+                Rlog.d(TAG, "Found carrier package.");
+                TextSmsSender smsSender = new TextSmsSender(tracker);
+                smsSender.sendSmsByCarrierApp(carrierPackage, new SmsSenderCallback(smsSender));
+            } else {
+                Rlog.v(TAG, "No carrier package.");
+                sendSubmitPdu(tracker);
+            }
         } else {
             Rlog.e(TAG, "CdmaSMSDispatcher.sendText(): getSubmitPdu() returned null");
         }
@@ -149,7 +166,7 @@
 
     /** {@inheritDoc} */
     @Override
-    protected void sendNewSubmitPdu(String destinationAddress, String scAddress,
+    protected SmsTracker getNewSubmitPduTracker(String destinationAddress, String scAddress,
             String message, SmsHeader smsHeader, int encoding,
             PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart,
             AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
@@ -173,12 +190,12 @@
 
         HashMap map = getSmsTrackerMap(destinationAddress, scAddress,
                 message, submitPdu);
-        SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent,
+        return getSmsTracker(map, sentIntent, deliveryIntent,
                 getFormat(), unsentPartCount, anyPartFailed, messageUri, smsHeader,
                 false /*isExpextMore*/, fullMessageText);
-        sendSubmitPdu(tracker);
     }
 
+    @Override
     protected void sendSubmitPdu(SmsTracker tracker) {
         if (SystemProperties.getBoolean(TelephonyProperties.PROPERTY_INECM_MODE, false)) {
             if (VDBG) {
@@ -205,37 +222,7 @@
                 + " mMessageRef=" + tracker.mMessageRef
                 + " SS=" + mPhone.getServiceState().getState());
 
-        // Send SMS via the carrier app.
-        BroadcastReceiver resultReceiver = new SMSDispatcherReceiver(tracker);
-
-        // Direct the intent to only the default carrier app.
-        Intent intent = new Intent(Intents.SMS_SEND_ACTION);
-        String carrierPackage = getCarrierAppPackageName(intent);
-        if (carrierPackage != null) {
-            intent.setPackage(getCarrierAppPackageName(intent));
-            intent.putExtra("pdu", pdu);
-            intent.putExtra("format", getFormat());
-            if (tracker.mSmsHeader != null && tracker.mSmsHeader.concatRef != null) {
-                SmsHeader.ConcatRef concatRef = tracker.mSmsHeader.concatRef;
-                intent.putExtra("concat.refNumber", concatRef.refNumber);
-                intent.putExtra("concat.seqNumber", concatRef.seqNumber);
-                intent.putExtra("concat.msgCount", concatRef.msgCount);
-            }
-            intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
-            Rlog.d(TAG, "Sending SMS by carrier app.");
-            mContext.sendOrderedBroadcast(intent, android.Manifest.permission.RECEIVE_SMS,
-                                          AppOpsManager.OP_RECEIVE_SMS, resultReceiver,
-                                          null, Activity.RESULT_CANCELED, null, null);
-        } else {
-            sendSmsByPstn(tracker);
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    protected void updateSmsSendStatus(int messageRef, boolean success) {
-        // This function should be defined in ImsDispatcher.
-        Rlog.e(TAG, "updateSmsSendStatus should never be called from here!");
+        sendSmsByPstn(tracker);
     }
 
     /** {@inheritDoc} */
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/src/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 5968a6a..9003194 100644
--- a/src/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -98,7 +98,6 @@
     private int mNitzUpdateDiff = SystemProperties.getInt("ro.nitz_update_diff",
             NITZ_UPDATE_DIFF_DEFAULT);
 
-    private boolean mCdmaRoaming = false;
     private int mRoamingIndicator;
     private boolean mIsInPrl;
     private int mDefaultRoamingIndicator;
@@ -633,6 +632,7 @@
                 int dataRegState = regCodeToServiceState(regState);
                 mNewSS.setDataRegState(dataRegState);
                 mNewSS.setRilDataRadioTechnology(dataRadioTechnology);
+                mNewSS.setDataRoaming(regCodeIsRoaming(regState));
                 if (DBG) {
                     log("handlPollStateResultMessage: cdma setDataRegState=" + dataRegState
                             + " regState=" + regState
@@ -715,8 +715,9 @@
                 // When registration state is roaming and TSB58
                 // roaming indicator is not in the carrier-specified
                 // list of ERIs for home system, mCdmaRoaming is true.
-                mCdmaRoaming =
+                boolean cdmaRoaming =
                         regCodeIsRoaming(registrationState) && !isRoamIndForHomeSystem(states[10]);
+                mNewSS.setVoiceRoaming(cdmaRoaming);
                 mNewSS.setState (regCodeToServiceState(registrationState));
 
                 mNewSS.setRilVoiceRadioTechnology(radioTechnology);
@@ -836,9 +837,14 @@
 
             // Setting SS Roaming (general)
             if (mIsSubscriptionFromRuim) {
-                mNewSS.setRoaming(isRoamingBetweenOperators(mCdmaRoaming, mNewSS));
-            } else {
-                mNewSS.setRoaming(mCdmaRoaming);
+                mNewSS.setVoiceRoaming(isRoamingBetweenOperators(mNewSS.getVoiceRoaming(), mNewSS));
+            }
+            // For CDMA, voice and data should have the same roaming status
+            final boolean isVoiceInService =
+                    (mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE);
+            final int dataRegType = mNewSS.getRilDataRadioTechnology();
+            if (isVoiceInService && ServiceState.isCdma(dataRegType)) {
+                mNewSS.setDataRoaming(mNewSS.getVoiceRoaming());
             }
 
             // Setting SS CdmaRoamingIndicator and CdmaDefaultRoamingIndicator
@@ -890,7 +896,9 @@
 
             if (DBG) {
                 log("Set CDMA Roaming Indicator to: " + mNewSS.getCdmaRoamingIndicator()
-                    + ". mCdmaRoaming = " + mCdmaRoaming + ", isPrlLoaded = " + isPrlLoaded
+                    + ". voiceRoaming = " + mNewSS.getVoiceRoaming()
+                    + ". dataRoaming = " + mNewSS.getDataRoaming()
+                    + ", isPrlLoaded = " + isPrlLoaded
                     + ". namMatch = " + namMatch + " , mIsInPrl = " + mIsInPrl
                     + ", mRoamingIndicator = " + mRoamingIndicator
                     + ", mDefaultRoamingIndicator= " + mDefaultRoamingIndicator);
@@ -900,6 +908,80 @@
 
     }
 
+    /**
+     * Set both voice and data roaming type,
+     * judging from the roaming indicator
+     * or ISO country of SIM VS network.
+     */
+    protected void setRoamingType(ServiceState currentServiceState) {
+        final boolean isVoiceInService =
+                (currentServiceState.getVoiceRegState() == ServiceState.STATE_IN_SERVICE);
+        if (isVoiceInService) {
+            if (currentServiceState.getVoiceRoaming()) {
+                // some carrier defines international roaming by indicator
+                int[] intRoamingIndicators = mPhone.getContext().getResources().getIntArray(
+                        com.android.internal.R.array.config_cdma_international_roaming_indicators);
+                if ((intRoamingIndicators != null) && (intRoamingIndicators.length > 0)) {
+                    // It's domestic roaming at least now
+                    currentServiceState.setVoiceRoamingType(ServiceState.ROAMING_TYPE_DOMESTIC);
+                    int curRoamingIndicator = currentServiceState.getCdmaRoamingIndicator();
+                    for (int i = 0; i < intRoamingIndicators.length; i++) {
+                        if (curRoamingIndicator == intRoamingIndicators[i]) {
+                            currentServiceState.setVoiceRoamingType(
+                                    ServiceState.ROAMING_TYPE_INTERNATIONAL);
+                            break;
+                        }
+                    }
+                } else {
+                    // check roaming type by MCC
+                    if (inSameCountry(currentServiceState.getVoiceOperatorNumeric())) {
+                        currentServiceState.setVoiceRoamingType(
+                                ServiceState.ROAMING_TYPE_DOMESTIC);
+                    } else {
+                        currentServiceState.setVoiceRoamingType(
+                                ServiceState.ROAMING_TYPE_INTERNATIONAL);
+                    }
+                }
+            } else {
+                currentServiceState.setVoiceRoamingType(ServiceState.ROAMING_TYPE_NOT_ROAMING);
+            }
+        }
+        final boolean isDataInService =
+                (currentServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE);
+        final int dataRegType = currentServiceState.getRilDataRadioTechnology();
+        if (isDataInService) {
+            if (!currentServiceState.getDataRoaming()) {
+                currentServiceState.setDataRoamingType(ServiceState.ROAMING_TYPE_NOT_ROAMING);
+            } else if (ServiceState.isCdma(dataRegType)) {
+                if (isVoiceInService) {
+                    // CDMA data should have the same state as voice
+                    currentServiceState.setDataRoamingType(currentServiceState
+                            .getVoiceRoamingType());
+                } else {
+                    // we can not decide CDMA data roaming type without voice
+                    // set it as same as last time
+                    currentServiceState.setDataRoamingType(ServiceState.ROAMING_TYPE_UNKNOWN);
+                }
+            } else {
+                // take it as 3GPP roaming
+                if (inSameCountry(currentServiceState.getDataOperatorNumeric())) {
+                    currentServiceState.setDataRoamingType(ServiceState.ROAMING_TYPE_DOMESTIC);
+                } else {
+                    currentServiceState.setDataRoamingType(
+                            ServiceState.ROAMING_TYPE_INTERNATIONAL);
+                }
+            }
+        }
+    }
+
+    protected String getHomeOperatorNumeric() {
+        final String cdmaNumeric =
+                SystemProperties.get(CDMAPhone.PROPERTY_CDMA_HOME_OPERATOR_NUMERIC, "");
+        final String simNumeric = SystemProperties.get(
+                TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, cdmaNumeric);
+        return simNumeric;
+    }
+
     protected void setSignalStrengthDefaultValues() {
         mSignalStrength = new SignalStrength( false);
     }
@@ -1023,7 +1105,8 @@
         if (DBG) log("pollStateDone: cdma oldSS=[" + mSS + "] newSS=[" + mNewSS + "]");
 
         if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean(PROP_FORCE_ROAMING, false)) {
-            mNewSS.setRoaming(true);
+            mNewSS.setVoiceRoaming(true);
+            mNewSS.setDataRoaming(true);
         }
 
         useDataRegStateForDataOnlyDevices();
@@ -1055,9 +1138,13 @@
 
         boolean hasChanged = !mNewSS.equals(mSS);
 
-        boolean hasRoamingOn = !mSS.getRoaming() && mNewSS.getRoaming();
+        boolean hasVoiceRoamingOn = !mSS.getVoiceRoaming() && mNewSS.getVoiceRoaming();
 
-        boolean hasRoamingOff = mSS.getRoaming() && !mNewSS.getRoaming();
+        boolean hasVoiceRoamingOff = mSS.getVoiceRoaming() && !mNewSS.getVoiceRoaming();
+
+        boolean hasDataRoamingOn = !mSS.getDataRoaming() && mNewSS.getDataRoaming();
+
+        boolean hasDataRoamingOff = mSS.getDataRoaming() && !mNewSS.getDataRoaming();
 
         boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc);
 
@@ -1156,9 +1243,12 @@
             }
 
             mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
-                    mSS.getRoaming() ? "true" : "false");
+                    (mSS.getVoiceRoaming() || mSS.getDataRoaming()) ? "true" : "false");
 
             updateSpnDisplay();
+            // set roaming type
+            setRoamingType(mSS);
+            log("Broadcasting ServiceState : " + mSS);
             mPhone.notifyServiceStateChanged(mSS);
         }
 
@@ -1175,12 +1265,20 @@
             mPhone.notifyDataConnection(null);
         }
 
-        if (hasRoamingOn) {
-            mRoamingOnRegistrants.notifyRegistrants();
+        if (hasVoiceRoamingOn) {
+            mVoiceRoamingOnRegistrants.notifyRegistrants();
         }
 
-        if (hasRoamingOff) {
-            mRoamingOffRegistrants.notifyRegistrants();
+        if (hasVoiceRoamingOff) {
+            mVoiceRoamingOffRegistrants.notifyRegistrants();
+        }
+
+        if (hasDataRoamingOn) {
+            mDataRoamingOnRegistrants.notifyRegistrants();
+        }
+
+        if (hasDataRoamingOff) {
+            mDataRoamingOffRegistrants.notifyRegistrants();
         }
 
         if (hasLocationChanged) {
@@ -1349,7 +1447,7 @@
      * code is registration state 0-5 from TS 27.007 7.2
      * returns true if registered roam, false otherwise
      */
-    private boolean
+    protected boolean
     regCodeIsRoaming (int code) {
         // 5 is  "in service -- roam"
         return 5 == code;
@@ -1395,8 +1493,8 @@
 
         // NOTE: in case of RUIM we should completely ignore the ERI data file and
         // mOperatorAlphaLong is set from RIL_REQUEST_OPERATOR response 0 (alpha ONS)
-        String onsl = s.getOperatorAlphaLong();
-        String onss = s.getOperatorAlphaShort();
+        String onsl = s.getVoiceOperatorAlphaLong();
+        String onss = s.getVoiceOperatorAlphaShort();
 
         boolean equalsOnsl = onsl != null && spn.equals(onsl);
         boolean equalsOnss = onss != null && spn.equals(onss);
@@ -1892,7 +1990,6 @@
         pw.println(" mCellLoc=" + mCellLoc);
         pw.println(" mNewCellLoc=" + mNewCellLoc);
         pw.println(" mCurrentOtaspMode=" + mCurrentOtaspMode);
-        pw.println(" mCdmaRoaming=" + mCdmaRoaming);
         pw.println(" mRoamingIndicator=" + mRoamingIndicator);
         pw.println(" mIsInPrl=" + mIsInPrl);
         pw.println(" mDefaultRoamingIndicator=" + mDefaultRoamingIndicator);
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index 6991173..5119fdb 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -422,7 +422,7 @@
         int networkType = ss.getDataNetworkType();
         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_MOBILE,
                 networkType, NETWORK_TYPE, TelephonyManager.getNetworkTypeName(networkType));
-        mNetworkInfo.setRoaming(ss.getRoaming());
+        mNetworkInfo.setRoaming(ss.getDataRoaming());
         mNetworkInfo.setIsAvailable(true);
 
         addState(mDefaultState);
@@ -546,7 +546,7 @@
         }
 
         String protocol;
-        if (mPhone.getServiceState().getRoaming()) {
+        if (mPhone.getServiceState().getDataRoaming()) {
             protocol = mApnSetting.roamingProtocol;
         } else {
             protocol = mApnSetting.protocol;
@@ -1045,9 +1045,9 @@
             mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(getHandler(),
                     DataConnection.EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED, null);
 
-            mPhone.getServiceStateTracker().registerForRoamingOn(getHandler(),
+            mPhone.getServiceStateTracker().registerForDataRoamingOn(getHandler(),
                     DataConnection.EVENT_DATA_CONNECTION_ROAM_ON, null);
-            mPhone.getServiceStateTracker().registerForRoamingOff(getHandler(),
+            mPhone.getServiceStateTracker().registerForDataRoamingOff(getHandler(),
                     DataConnection.EVENT_DATA_CONNECTION_ROAM_OFF, null);
 
             // Add ourselves to the list of data connections
@@ -1060,8 +1060,8 @@
             // Unregister for DRS or RAT change.
             mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(getHandler());
 
-            mPhone.getServiceStateTracker().unregisterForRoamingOn(getHandler());
-            mPhone.getServiceStateTracker().unregisterForRoamingOff(getHandler());
+            mPhone.getServiceStateTracker().unregisterForDataRoamingOn(getHandler());
+            mPhone.getServiceStateTracker().unregisterForDataRoamingOff(getHandler());
 
             // Remove ourselves from the DC lists
             mDcController.removeDc(DataConnection.this);
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index afcef5b..8520f57 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -194,9 +194,9 @@
                DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null);
         mPhone.getServiceStateTracker().registerForDataConnectionDetached(this,
                DctConstants.EVENT_DATA_CONNECTION_DETACHED, null);
-        mPhone.getServiceStateTracker().registerForRoamingOn(this,
+        mPhone.getServiceStateTracker().registerForDataRoamingOn(this,
                DctConstants.EVENT_ROAMING_ON, null);
-        mPhone.getServiceStateTracker().registerForRoamingOff(this,
+        mPhone.getServiceStateTracker().registerForDataRoamingOff(this,
                DctConstants.EVENT_ROAMING_OFF, null);
         mPhone.getServiceStateTracker().registerForPsRestrictedEnabled(this,
                 DctConstants.EVENT_PS_RESTRICT_ENABLED, null);
@@ -244,8 +244,8 @@
         mPhone.getCallTracker().unregisterForVoiceCallStarted(this);
         mPhone.getServiceStateTracker().unregisterForDataConnectionAttached(this);
         mPhone.getServiceStateTracker().unregisterForDataConnectionDetached(this);
-        mPhone.getServiceStateTracker().unregisterForRoamingOn(this);
-        mPhone.getServiceStateTracker().unregisterForRoamingOff(this);
+        mPhone.getServiceStateTracker().unregisterForDataRoamingOn(this);
+        mPhone.getServiceStateTracker().unregisterForDataRoamingOff(this);
         mPhone.getServiceStateTracker().unregisterForPsRestrictedEnabled(this);
         mPhone.getServiceStateTracker().unregisterForPsRestrictedDisabled(this);
         //SubscriptionManager.unregisterForDdsSwitch(this);
@@ -719,7 +719,7 @@
                     (mPhone.getState() == PhoneConstants.State.IDLE ||
                      mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) &&
                     internalDataEnabled &&
-                    (!mPhone.getServiceState().getRoaming() || getDataOnRoamingEnabled()) &&
+                    (!mPhone.getServiceState().getDataRoaming() || getDataOnRoamingEnabled()) &&
                     //!mIsPsRestricted &&
                     !psRestricted &&
                     desiredPowerState;
@@ -735,7 +735,7 @@
                 reason += " - Concurrent voice and data not allowed";
             }
             if (!internalDataEnabled) reason += " - mInternalDataEnabled= false";
-            if (mPhone.getServiceState().getRoaming() && !getDataOnRoamingEnabled()) {
+            if (mPhone.getServiceState().getDataRoaming() && !getDataOnRoamingEnabled()) {
                 reason += " - Roaming and data roaming not enabled";
             }
             if (mIsPsRestricted) reason += " - mIsPsRestricted= true";
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTrackerBase.java b/src/java/com/android/internal/telephony/dataconnection/DcTrackerBase.java
index 297d9b4..3796227 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTrackerBase.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTrackerBase.java
@@ -409,7 +409,7 @@
         @Override
         public void onChange(boolean selfChange) {
             // already running on mPhone handler thread
-            if (mPhone.getServiceState().getRoaming()) {
+            if (mPhone.getServiceState().getDataRoaming()) {
                 sendMessage(obtainMessage(DctConstants.EVENT_ROAMING_ON));
             }
         }
@@ -1366,7 +1366,7 @@
                 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
                         Settings.Global.MOBILE_DATA + phoneSubId, enabled ? 1 : 0);
                 if (getDataOnRoamingEnabled() == false &&
-                        mPhone.getServiceState().getRoaming() == true) {
+                        mPhone.getServiceState().getDataRoaming() == true) {
                     if (enabled) {
                         notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON);
                     } else {
@@ -1817,7 +1817,7 @@
             for (ApnSetting apn : mAllApnSettings) {
                 if (apn.modemCognitive) {
                     DataProfile dp = new DataProfile(apn,
-                            mPhone.getServiceState().getRoaming());
+                            mPhone.getServiceState().getDataRoaming());
                     boolean isDup = false;
                     for(DataProfile dpIn : dps) {
                         if (dp.equals(dpIn)) {
diff --git a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
index 21c0865..0ba09ed 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -20,7 +20,6 @@
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
-import android.content.BroadcastReceiver;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.AsyncResult;
@@ -159,7 +158,16 @@
             HashMap map = getSmsTrackerMap(destAddr, scAddr, destPort, data, pdu);
             SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(),
                     null /*messageUri*/, false /*isExpectMore*/, null /*fullMessageText*/);
-            sendRawPdu(tracker);
+
+            String carrierPackage = getCarrierAppPackageName();
+            if (carrierPackage != null) {
+                Rlog.d(TAG, "Found carrier package.");
+                DataSmsSender smsSender = new DataSmsSender(tracker);
+                smsSender.sendSmsByCarrierApp(carrierPackage, new SmsSenderCallback(smsSender));
+            } else {
+                Rlog.v(TAG, "No carrier package.");
+                sendRawPdu(tracker);
+            }
         } else {
             Rlog.e(TAG, "GsmSMSDispatcher.sendData(): getSubmitPdu() returned null");
         }
@@ -175,7 +183,16 @@
             HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu);
             SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(),
                     messageUri, false /*isExpectMore*/, text /*fullMessageText*/);
-            sendRawPdu(tracker);
+
+            String carrierPackage = getCarrierAppPackageName();
+            if (carrierPackage != null) {
+                Rlog.d(TAG, "Found carrier package.");
+                TextSmsSender smsSender = new TextSmsSender(tracker);
+                smsSender.sendSmsByCarrierApp(carrierPackage, new SmsSenderCallback(smsSender));
+            } else {
+                Rlog.v(TAG, "No carrier package.");
+                sendRawPdu(tracker);
+            }
         } else {
             Rlog.e(TAG, "GsmSMSDispatcher.sendText(): getSubmitPdu() returned null");
         }
@@ -196,7 +213,7 @@
 
     /** {@inheritDoc} */
     @Override
-    protected void sendNewSubmitPdu(String destinationAddress, String scAddress,
+    protected SmsTracker getNewSubmitPduTracker(String destinationAddress, String scAddress,
             String message, SmsHeader smsHeader, int encoding,
             PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart,
             AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
@@ -207,15 +224,20 @@
         if (pdu != null) {
             HashMap map =  getSmsTrackerMap(destinationAddress, scAddress,
                     message, pdu);
-            SmsTracker tracker = getSmsTracker(map, sentIntent,
+            return getSmsTracker(map, sentIntent,
                     deliveryIntent, getFormat(), unsentPartCount, anyPartFailed, messageUri,
                     smsHeader, !lastPart, fullMessageText);
-            sendRawPdu(tracker);
         } else {
             Rlog.e(TAG, "GsmSMSDispatcher.sendNewSubmitPdu(): getSubmitPdu() returned null");
+            return null;
         }
     }
 
+    @Override
+    protected void sendSubmitPdu(SmsTracker tracker) {
+        sendRawPdu(tracker);
+    }
+
     /** {@inheritDoc} */
     @Override
     protected void sendSms(SmsTracker tracker) {
@@ -244,30 +266,7 @@
                 + " mMessageRef=" + tracker.mMessageRef
                 + " SS=" + mPhone.getServiceState().getState());
 
-        // Send SMS via the carrier app.
-        BroadcastReceiver resultReceiver = new SMSDispatcherReceiver(tracker);
-
-        Intent intent = new Intent(Intents.SMS_SEND_ACTION);
-        String carrierPackage = getCarrierAppPackageName(intent);
-        if (carrierPackage != null) {
-            intent.setPackage(carrierPackage);
-            intent.putExtra("pdu", pdu);
-            intent.putExtra("smsc", (byte[]) map.get("smsc"));
-            intent.putExtra("format", getFormat());
-            if (tracker.mSmsHeader != null && tracker.mSmsHeader.concatRef != null) {
-                SmsHeader.ConcatRef concatRef = tracker.mSmsHeader.concatRef;
-                intent.putExtra("concat.refNumber", concatRef.refNumber);
-                intent.putExtra("concat.seqNumber", concatRef.seqNumber);
-                intent.putExtra("concat.msgCount", concatRef.msgCount);
-            }
-            intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
-            Rlog.d(TAG, "Sending SMS by carrier app.");
-            mContext.sendOrderedBroadcast(intent, android.Manifest.permission.RECEIVE_SMS,
-                                          AppOpsManager.OP_RECEIVE_SMS, resultReceiver,
-                                          null, Activity.RESULT_CANCELED, null, null);
-        } else {
-            sendSmsByPstn(tracker);
-        }
+        sendSmsByPstn(tracker);
     }
 
     /** {@inheritDoc} */
@@ -317,13 +316,6 @@
         }
     }
 
-    /** {@inheritDoc} */
-    @Override
-    protected void updateSmsSendStatus(int messageRef, boolean success) {
-        // This function should be defined in ImsDispatcher.
-        Rlog.e(TAG, "updateSmsSendStatus should never be called from here!");
-    }
-
     protected UiccCardApplication getUiccCardApplication() {
             Rlog.d(TAG, "GsmSMSDispatcher: subId = " + mPhone.getSubId()
                     + " slotId = " + mPhone.getPhoneId());
diff --git a/src/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/src/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 2e9c7f1..9ffb2b7 100755
--- a/src/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -876,12 +876,56 @@
                 (isSameNamedOperators(mNewSS) || isOperatorConsideredNonRoaming(mNewSS))) {
                 roaming = false;
             }
-            mNewSS.setRoaming(roaming);
+            mNewSS.setVoiceRoaming(roaming);
+            mNewSS.setDataRoaming(roaming);
             mNewSS.setEmergencyOnly(mEmergencyOnly);
             pollStateDone();
         }
     }
 
+    /**
+     * Set both voice and data roaming type,
+     * judging from the ISO country of SIM VS network.
+     */
+    protected void setRoamingType(ServiceState currentServiceState) {
+        final boolean isVoiceInService =
+                (currentServiceState.getVoiceRegState() == ServiceState.STATE_IN_SERVICE);
+        if (isVoiceInService) {
+            if (currentServiceState.getVoiceRoaming()) {
+                // check roaming type by MCC
+                if (inSameCountry(currentServiceState.getVoiceOperatorNumeric())) {
+                    currentServiceState.setVoiceRoamingType(
+                            ServiceState.ROAMING_TYPE_DOMESTIC);
+                } else {
+                    currentServiceState.setVoiceRoamingType(
+                            ServiceState.ROAMING_TYPE_INTERNATIONAL);
+                }
+            } else {
+                currentServiceState.setVoiceRoamingType(ServiceState.ROAMING_TYPE_NOT_ROAMING);
+            }
+        }
+        final boolean isDataInService =
+                (currentServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE);
+        final int dataRegType = currentServiceState.getRilDataRadioTechnology();
+        if (isDataInService) {
+            if (!currentServiceState.getDataRoaming()) {
+                currentServiceState.setDataRoamingType(ServiceState.ROAMING_TYPE_NOT_ROAMING);
+            } else if (ServiceState.isGsm(dataRegType)) {
+                if (isVoiceInService) {
+                    // GSM data should have the same state as voice
+                    currentServiceState.setDataRoamingType(currentServiceState
+                            .getVoiceRoamingType());
+                } else {
+                    // we can not decide GSM data roaming type without voice
+                    currentServiceState.setDataRoamingType(ServiceState.ROAMING_TYPE_UNKNOWN);
+                }
+            } else {
+                // we can not decide 3gpp2 roaming state here
+                currentServiceState.setDataRoamingType(ServiceState.ROAMING_TYPE_UNKNOWN);
+            }
+        }
+    }
+
     private void setSignalStrengthDefaultValues() {
         mSignalStrength = new SignalStrength(true);
     }
@@ -957,7 +1001,8 @@
         }
 
         if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean(PROP_FORCE_ROAMING, false)) {
-            mNewSS.setRoaming(true);
+            mNewSS.setVoiceRoaming(true);
+            mNewSS.setDataRoaming(true);
         }
 
         useDataRegStateForDataOnlyDevices();
@@ -992,9 +1037,13 @@
 
         boolean hasChanged = !mNewSS.equals(mSS);
 
-        boolean hasRoamingOn = !mSS.getRoaming() && mNewSS.getRoaming();
+        boolean hasVoiceRoamingOn = !mSS.getVoiceRoaming() && mNewSS.getVoiceRoaming();
 
-        boolean hasRoamingOff = mSS.getRoaming() && !mNewSS.getRoaming();
+        boolean hasVoiceRoamingOff = mSS.getVoiceRoaming() && !mNewSS.getVoiceRoaming();
+
+        boolean hasDataRoamingOn = !mSS.getDataRoaming() && mNewSS.getDataRoaming();
+
+        boolean hasDataRoamingOff = mSS.getDataRoaming() && !mNewSS.getDataRoaming();
 
         boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc);
 
@@ -1194,8 +1243,10 @@
             }
 
             mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
-                mSS.getRoaming() ? "true" : "false");
+                mSS.getVoiceRoaming() ? "true" : "false");
 
+            setRoamingType(mSS);
+            log("Broadcasting ServiceState : " + mSS);
             mPhone.notifyServiceStateChanged(mSS);
         }
 
@@ -1212,12 +1263,20 @@
             mPhone.notifyDataConnection(null);
         }
 
-        if (hasRoamingOn) {
-            mRoamingOnRegistrants.notifyRegistrants();
+        if (hasVoiceRoamingOn) {
+            mVoiceRoamingOnRegistrants.notifyRegistrants();
         }
 
-        if (hasRoamingOff) {
-            mRoamingOffRegistrants.notifyRegistrants();
+        if (hasVoiceRoamingOff) {
+            mVoiceRoamingOffRegistrants.notifyRegistrants();
+        }
+
+        if (hasDataRoamingOn) {
+            mDataRoamingOnRegistrants.notifyRegistrants();
+        }
+
+        if (hasDataRoamingOff) {
+            mDataRoamingOffRegistrants.notifyRegistrants();
         }
 
         if (hasLocationChanged) {
diff --git a/src/java/com/android/internal/telephony/uicc/IccCardProxy.java b/src/java/com/android/internal/telephony/uicc/IccCardProxy.java
index 3408996..07571c0 100644
--- a/src/java/com/android/internal/telephony/uicc/IccCardProxy.java
+++ b/src/java/com/android/internal/telephony/uicc/IccCardProxy.java
@@ -97,7 +97,6 @@
     private static final int EVENT_SUBSCRIPTION_DEACTIVATED = 502;
     private static final int EVENT_CARRIER_PRIVILIGES_LOADED = 503;
 
-    // FIXME Rename mCardIndex to mSlotId.
     private Integer mCardIndex = null;
 
     private final Object mLock = new Object();
@@ -120,23 +119,17 @@
     private boolean mInitialized = false;
     private State mExternalState = State.UNKNOWN;
 
-    public IccCardProxy(Context context, CommandsInterface ci) {
-        log("Creating");
+    public IccCardProxy(Context context, CommandsInterface ci, int cardIndex) {
+        if (DBG) log("ctor: ci=" + ci + " cardIndex=" + cardIndex);
         mContext = context;
         mCi = ci;
+        mCardIndex = cardIndex;
         mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(context,
                 ci, this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
         mUiccController = UiccController.getInstance();
         mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
         ci.registerForOn(this,EVENT_RADIO_ON, null);
         ci.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_UNAVAILABLE, null);
-        setExternalState(State.NOT_READY);
-    }
-
-    public IccCardProxy(Context context, CommandsInterface ci, int cardIndex) {
-        this(context, ci);
-
-        mCardIndex = cardIndex;
 
         resetProperties();
         setExternalState(State.NOT_READY, false);
@@ -197,6 +190,12 @@
                 newQuietMode = (cdmaSource == Phone.CDMA_SUBSCRIPTION_NV)
                         && (mCurrentAppType == UiccController.APP_FAM_3GPP2)
                         && !isLteOnCdmaMode;
+                if (DBG) {
+                    log("updateQuietMode: cdmaSource=" + cdmaSource
+                            + " mCurrentAppType=" + mCurrentAppType
+                            + " isLteOnCdmaMode=" + isLteOnCdmaMode
+                            + " newQuietMode=" + newQuietMode);
+                }
             }
 
             if (mQuietMode == false && newQuietMode == true) {
@@ -212,6 +211,8 @@
                 }
                 mQuietMode = newQuietMode;
                 setExternalState(mExternalState, true);
+            } else {
+                if (DBG) log("updateQuietMode: no changes don't setExternalState");
             }
             if (DBG) {
                 log("updateQuietMode: QuietMode is " + mQuietMode + " (app_type="
@@ -258,7 +259,7 @@
                     String operator = mIccRecords.getOperatorNumeric();
                     int slotId = mCardIndex;
 
-                    log("operator = " + operator + " slotId = " + slotId);
+                    log("operator=" + operator + " slotId=" + slotId);
 
                     if (operator != null) {
                         log("update icc_operator_numeric=" + operator);
@@ -476,14 +477,16 @@
 
     private void broadcastIccStateChangedIntent(String value, String reason) {
         synchronized (mLock) {
-            if (mCardIndex == null) {
-                loge("broadcastIccStateChangedIntent: Card Index is not set; Return!!");
+            if (mCardIndex == null || !SubscriptionManager.isValidSlotId(mCardIndex)) {
+                loge("broadcastIccStateChangedIntent: mCardIndex=" + mCardIndex
+                        + " is invalid; Return!!");
                 return;
             }
 
             if (mQuietMode) {
-                log("QuietMode: NOT Broadcasting intent ACTION_SIM_STATE_CHANGED " +  value
-                        + " reason " + reason);
+                log("broadcastIccStateChangedIntent: QuietMode"
+                        + " NOT Broadcasting intent ACTION_SIM_STATE_CHANGED "
+                        + " value=" +  value + " reason=" + reason);
                 return;
             }
 
@@ -493,8 +496,8 @@
             intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
             intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
             SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mCardIndex);
-            log("Broadcasting intent ACTION_SIM_STATE_CHANGED " +  value
-                + " reason " + reason + " for mCardIndex : " + mCardIndex);
+            log("broadcastIccStateChangedIntent intent ACTION_SIM_STATE_CHANGED value=" + value
+                + " reason=" + reason + " for mCardIndex=" + mCardIndex);
             ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE,
                     UserHandle.USER_ALL);
         }
@@ -502,15 +505,17 @@
 
     private void setExternalState(State newState, boolean override) {
         synchronized (mLock) {
-            if (mCardIndex == null) {
-                loge("setExternalState: Card Index is not set; Return!!");
+            if (mCardIndex == null || !SubscriptionManager.isValidSlotId(mCardIndex)) {
+                loge("setExternalState: mCardIndex=" + mCardIndex + " is invalid; Return!!");
                 return;
             }
 
             if (!override && newState == mExternalState) {
+                loge("setExternalState: !override and newstate unchanged from " + newState);
                 return;
             }
             mExternalState = newState;
+            loge("setExternalState: set mCardIndex=" + mCardIndex + " mExternalState=" + mExternalState);
             setSystemProperty(PROPERTY_SIM_STATE, mCardIndex, getState().toString());
             broadcastIccStateChangedIntent(getIccStateIntentString(mExternalState),
                     getIccStateReason(mExternalState));
diff --git a/src/java/com/android/internal/telephony/uicc/RuimRecords.java b/src/java/com/android/internal/telephony/uicc/RuimRecords.java
index 85792ba..57355ce 100644
--- a/src/java/com/android/internal/telephony/uicc/RuimRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/RuimRecords.java
@@ -36,6 +36,7 @@
 import android.telephony.Rlog;
 import android.text.TextUtils;
 import android.util.Log;
+import android.content.res.Resources;
 
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.GsmAlphabet;
@@ -853,13 +854,16 @@
                 obtainMessage(EVENT_GET_ICCID_DONE));
         mRecordsToLoad++;
 
-        mFh.loadEFTransparent(EF_PL,
-                obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfPlLoaded()));
-        mRecordsToLoad++;
+        Resources resource = Resources.getSystem();
+        if (resource.getBoolean(com.android.internal.R.bool.config_use_sim_language_file)) {
+            mFh.loadEFTransparent(EF_PL,
+                    obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfPlLoaded()));
+            mRecordsToLoad++;
 
-        mFh.loadEFTransparent(EF_CSIM_LI,
-                obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimLiLoaded()));
-        mRecordsToLoad++;
+            mFh.loadEFTransparent(EF_CSIM_LI,
+                    obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimLiLoaded()));
+            mRecordsToLoad++;
+        }
 
         mFh.loadEFTransparent(EF_CSIM_SPN,
                 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimSpnLoaded()));
diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java
index 7580110..f8fe606 100644
--- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java
@@ -1503,6 +1503,12 @@
     }
 
     private void loadEfLiAndEfPl() {
+        Resources resource = Resources.getSystem();
+        if (!resource.getBoolean(com.android.internal.R.bool.config_use_sim_language_file)) {
+            if (DBG) log ("Not using EF LI/EF PL");
+            return;
+        }
+
         if (mParentApp.getType() == AppType.APPTYPE_USIM) {
             mRecordsRequested = true;
             mFh.loadEFTransparent(EF_LI,