Merge "LegacyState does not send notifyDisplayInfoChanged am: 545dd7778c am: 6acc0754d3 am: b5a0a93648" into rvc-qpr-dev-plus-aosp am: f111895a79

Change-Id: I4db55ff770ad4db3d07a54023e6cd12a7593ac4d
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 6790fa7..466aca3 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -74,6 +74,7 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.UiccAccessRule;
 import android.telephony.UssdResponse;
 import android.telephony.data.ApnSetting;
 import android.text.TextUtils;
@@ -115,6 +116,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.regex.Matcher;
@@ -182,7 +184,7 @@
     private SIMRecords mSimRecords;
 
     // For non-persisted manual network selection
-    private String mManualNetworkSelectionPlmn = "";
+    private String mManualNetworkSelectionPlmn;
 
     //Common
     // Instance Variables
@@ -1889,7 +1891,23 @@
     public void setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1,
             String gid2, String pnn, String spn, String carrierPrivilegeRules, String apn) {
         mCarrierResolver.setTestOverrideApn(apn);
-        mCarrierResolver.setTestOverrideCarrierPriviledgeRule(carrierPrivilegeRules);
+        UiccProfile uiccProfile = mUiccController.getUiccProfileForPhone(getPhoneId());
+        if (uiccProfile != null) {
+            List<UiccAccessRule> testRules;
+            if (carrierPrivilegeRules == null) {
+                testRules = null;
+            } else if (carrierPrivilegeRules.isEmpty()) {
+                testRules = Collections.emptyList();
+            } else {
+                UiccAccessRule accessRule = new UiccAccessRule(
+                        IccUtils.hexStringToBytes(carrierPrivilegeRules), null, 0);
+                testRules = Collections.singletonList(accessRule);
+            }
+            uiccProfile.setTestOverrideCarrierPrivilegeRules(testRules);
+        } else {
+            // TODO: Fix "privilege" typo throughout telephony.
+            mCarrierResolver.setTestOverrideCarrierPriviledgeRule(carrierPrivilegeRules); // NOTYPO
+        }
         IccRecords r = null;
         if (isPhoneTypeGsm()) {
             r = mIccRecords.get();
@@ -1972,7 +1990,7 @@
             mManualNetworkSelectionPlmn = nsm.operatorNumeric;
         } else {
         //on Phone0 in emergency mode (no SIM), or in some races then clear the cache
-            mManualNetworkSelectionPlmn = "";
+            mManualNetworkSelectionPlmn = null;
             Rlog.e(LOG_TAG, "Cannot update network selection due to invalid subId "
                     + subId);
         }
@@ -3078,7 +3096,8 @@
             case EVENT_SET_CARRIER_DATA_ENABLED:
                 ar = (AsyncResult) msg.obj;
                 boolean enabled = (boolean) ar.result;
-                mDataEnabledSettings.setCarrierDataEnabled(enabled);
+                mDataEnabledSettings.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_CARRIER,
+                        enabled);
                 break;
             case EVENT_DEVICE_PROVISIONED_CHANGE:
                 mDataEnabledSettings.updateProvisionedChanged();
diff --git a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
index c99b282..8182994 100644
--- a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
+++ b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
@@ -405,12 +405,12 @@
                     isRetry,
                     pdu);
             mMetrics.writeImsServiceSendSms(mPhone.getPhoneId(), format,
-                    ImsSmsImplBase.SEND_STATUS_OK);
+                    ImsSmsImplBase.SEND_STATUS_OK, tracker.mMessageId);
         } catch (ImsException e) {
             loge("sendSms failed. Falling back to PSTN. Error: " + e.getMessage());
             fallbackToPstn(token, tracker);
             mMetrics.writeImsServiceSendSms(mPhone.getPhoneId(), format,
-                    ImsSmsImplBase.SEND_STATUS_ERROR_FALLBACK);
+                    ImsSmsImplBase.SEND_STATUS_ERROR_FALLBACK, tracker.mMessageId);
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java
index 992a454..ec0ae09 100644
--- a/src/java/com/android/internal/telephony/InboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java
@@ -24,6 +24,7 @@
 import static android.service.carrier.CarrierMessagingService.RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE;
 import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
 
+import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.AppOpsManager;
 import android.app.BroadcastOptions;
@@ -83,6 +84,7 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
 
 /**
@@ -163,7 +165,7 @@
     public static final int EVENT_BROADCAST_SMS = 2;
 
     /** Message from resultReceiver notifying {@link WaitingState} of a completed broadcast. */
-    private static final int EVENT_BROADCAST_COMPLETE = 3;
+    public static final int EVENT_BROADCAST_COMPLETE = 3;
 
     /** Sent on exit from {@link WaitingState} to return to idle after sending all broadcasts. */
     private static final int EVENT_RETURN_TO_IDLE = 4;
@@ -258,6 +260,8 @@
         others in order to update metrics. */
     private boolean mLastSmsWasInjected = false;
 
+    private List<SmsFilter> mSmsFilters;
+
     /**
      * Create a new SMS broadcast helper.
      * @param name the class name for logging
@@ -287,6 +291,8 @@
                 (PowerWhitelistManager) mContext.getSystemService(Context.POWER_WHITELIST_MANAGER);
         mCellBroadcastServiceManager = new CellBroadcastServiceManager(context, phone);
 
+        mSmsFilters = createDefaultSmsFilters();
+
         addState(mDefaultState);
         addState(mStartupState, mDefaultState);
         addState(mIdleState, mDefaultState);
@@ -1091,51 +1097,77 @@
     }
 
     /**
+     * Creates the default filters used to filter SMS messages.
+     *
+     * <p>Currently 3 filters exist: the carrier package, the VisualVoicemailSmsFilter, and the
+     * missed incoming call SMS filter.
+     *
+     * <p>Since the carrier filter is asynchronous, if a message passes through the carrier filter,
+     * the remaining filters will be applied in the callback.
+     */
+    private List<SmsFilter> createDefaultSmsFilters() {
+        List<SmsFilter> smsFilters = new ArrayList<>(3);
+        smsFilters.add(
+                (pdus, destPort, tracker, resultReceiver, userUnlocked, remainingFilters) -> {
+                    CarrierServicesSmsFilterCallback filterCallback =
+                            new CarrierServicesSmsFilterCallback(
+                                    pdus, destPort, tracker, tracker.getFormat(), resultReceiver,
+                                    userUnlocked,
+                                    tracker.isClass0(), tracker.getSubId(), tracker.getMessageId(),
+                                    remainingFilters);
+                    CarrierServicesSmsFilter carrierServicesFilter = new CarrierServicesSmsFilter(
+                            mContext, mPhone, pdus, destPort, tracker.getFormat(),
+                            filterCallback, getName(), mLocalLog);
+                    return carrierServicesFilter.filter();
+                });
+        smsFilters.add(
+                (pdus, destPort, tracker, resultReceiver, userUnlocked, remainingFilters) -> {
+                    if (VisualVoicemailSmsFilter.filter(
+                            mContext, pdus, tracker.getFormat(), destPort, tracker.getSubId())) {
+                        log("Visual voicemail SMS dropped");
+                        dropSms(resultReceiver);
+                        return true;
+                    }
+                    return false;
+                });
+        smsFilters.add(
+                (pdus, destPort, tracker, resultReceiver, userUnlocked, remainingFilters) -> {
+                    MissedIncomingCallSmsFilter missedIncomingCallSmsFilter =
+                            new MissedIncomingCallSmsFilter(mPhone);
+                    if (missedIncomingCallSmsFilter.filter(pdus, tracker.getFormat())) {
+                        log("Missed incoming call SMS received.");
+                        dropSms(resultReceiver);
+                        return true;
+                    }
+                    return false;
+                });
+        return smsFilters;
+    }
+
+    /**
      * Filters the SMS.
      *
-     * <p>currently 3 filters exists: the carrier package, the system package, and the
-     * VisualVoicemailSmsFilter.
-     *
-     * <p>The filtering process is:
-     *
-     * <p>If the carrier package exists, the SMS will be filtered with it first. If the carrier
-     * package did not drop the SMS, then the VisualVoicemailSmsFilter will filter it in the
-     * callback.
-     *
-     * <p>If the carrier package does not exists, we will let the VisualVoicemailSmsFilter filter
-     * it. If the SMS passed the filter, then we will try to find the system package to do the
-     * filtering.
+     * <p>Each filter in {@link #mSmsFilters} is invoked sequentially. If any filter returns true,
+     * this method returns true and subsequent filters are ignored.
      *
      * @return true if a filter is invoked and the SMS processing flow is diverted, false otherwise.
      */
     private boolean filterSms(byte[][] pdus, int destPort,
-        InboundSmsTracker tracker, SmsBroadcastReceiver resultReceiver, boolean userUnlocked) {
-        CarrierServicesSmsFilterCallback filterCallback =
-                new CarrierServicesSmsFilterCallback(
-                        pdus, destPort, tracker.getFormat(), resultReceiver, userUnlocked,
-                        tracker.isClass0(), tracker.getSubId(), tracker.getMessageId());
-        CarrierServicesSmsFilter carrierServicesFilter = new CarrierServicesSmsFilter(
-                mContext, mPhone, pdus, destPort, tracker.getFormat(),
-                filterCallback, getName(), mLocalLog);
-        if (carrierServicesFilter.filter()) {
-            return true;
-        }
+            InboundSmsTracker tracker, SmsBroadcastReceiver resultReceiver, boolean userUnlocked) {
+        return filterSms(pdus, destPort, tracker, resultReceiver, userUnlocked, mSmsFilters);
+    }
 
-        if (VisualVoicemailSmsFilter.filter(
-                mContext, pdus, tracker.getFormat(), destPort, tracker.getSubId())) {
-            log("Visual voicemail SMS dropped");
-            dropSms(resultReceiver);
-            return true;
+    private static boolean filterSms(byte[][] pdus, int destPort,
+            InboundSmsTracker tracker, SmsBroadcastReceiver resultReceiver, boolean userUnlocked,
+            List<SmsFilter> filters) {
+        ListIterator<SmsFilter> iterator = filters.listIterator();
+        while (iterator.hasNext()) {
+            SmsFilter smsFilter = iterator.next();
+            if (smsFilter.filterSms(pdus, destPort, tracker, resultReceiver, userUnlocked,
+                    filters.subList(iterator.nextIndex(), filters.size()))) {
+                return true;
+            }
         }
-
-        MissedIncomingCallSmsFilter missedIncomingCallSmsFilter =
-                new MissedIncomingCallSmsFilter(mPhone);
-        if (missedIncomingCallSmsFilter.filter(pdus, tracker.getFormat())) {
-            log("Missed incoming call SMS received.");
-            dropSms(resultReceiver);
-            return true;
-        }
-
         return false;
     }
 
@@ -1476,7 +1508,8 @@
      * Handler for an {@link InboundSmsTracker} broadcast. Deletes PDUs from the raw table and
      * logs the broadcast duration (as an error if the other receivers were especially slow).
      */
-    private final class SmsBroadcastReceiver extends BroadcastReceiver {
+    @VisibleForTesting
+    public final class SmsBroadcastReceiver extends BroadcastReceiver {
         @UnsupportedAppUsage
         private final String mDeleteWhere;
         @UnsupportedAppUsage
@@ -1561,35 +1594,37 @@
             CarrierServicesSmsFilter.CarrierServicesSmsFilterCallbackInterface {
         private final byte[][] mPdus;
         private final int mDestPort;
+        private final InboundSmsTracker mTracker;
         private final String mSmsFormat;
         private final SmsBroadcastReceiver mSmsBroadcastReceiver;
         private final boolean mUserUnlocked;
         private final boolean mIsClass0;
         private final int mSubId;
         private final long mMessageId;
+        private final List<SmsFilter> mRemainingFilters;
 
-        CarrierServicesSmsFilterCallback(byte[][] pdus, int destPort, String smsFormat,
-                SmsBroadcastReceiver smsBroadcastReceiver,  boolean userUnlocked,
-                boolean isClass0, int subId, long messageId) {
+        CarrierServicesSmsFilterCallback(byte[][] pdus, int destPort, InboundSmsTracker tracker,
+                String smsFormat, SmsBroadcastReceiver smsBroadcastReceiver, boolean userUnlocked,
+                boolean isClass0, int subId, long messageId, List<SmsFilter> remainingFilters) {
             mPdus = pdus;
             mDestPort = destPort;
+            mTracker = tracker;
             mSmsFormat = smsFormat;
             mSmsBroadcastReceiver = smsBroadcastReceiver;
             mUserUnlocked = userUnlocked;
             mIsClass0 = isClass0;
             mSubId = subId;
             mMessageId = messageId;
+            mRemainingFilters = remainingFilters;
         }
 
         @Override
         public void onFilterComplete(int result) {
             logv("onFilterComplete: result is " + result);
             if ((result & CarrierMessagingService.RECEIVE_OPTIONS_DROP) == 0) {
-                if (VisualVoicemailSmsFilter.filter(mContext, mPdus,
-                        mSmsFormat, mDestPort, mSubId)) {
-                    log("Visual voicemail SMS dropped"
-                            + " id: " + mMessageId);
-                    dropSms(mSmsBroadcastReceiver);
+                // Message isn't dropped, so run it through the remaining filters.
+                if (filterSms(mPdus, mDestPort, mTracker, mSmsBroadcastReceiver, mUserUnlocked,
+                        mRemainingFilters)) {
                     return;
                 }
 
@@ -1768,6 +1803,20 @@
     }
 
     /**
+     * Set the SMS filters used by {@link #filterSms} for testing purposes.
+     *
+     * @param smsFilters List of SMS filters, or null to restore the default filters.
+     */
+    @VisibleForTesting
+    public void setSmsFiltersForTesting(@Nullable List<SmsFilter> smsFilters) {
+        if (smsFilters == null) {
+            mSmsFilters = createDefaultSmsFilters();
+        } else {
+            mSmsFilters = smsFilters;
+        }
+    }
+
+    /**
      * Handler for the broadcast sent when the new message notification is clicked. It launches the
      * default SMS app.
      */
@@ -1846,4 +1895,16 @@
             }
         }
     }
+
+    /** A filter for incoming messages allowing the normal processing flow to be skipped. */
+    @VisibleForTesting
+    public interface SmsFilter {
+        /**
+         * Returns true if a filter is invoked and the SMS processing flow should be diverted, false
+         * otherwise.
+         */
+        boolean filterSms(byte[][] pdus, int destPort, InboundSmsTracker tracker,
+                SmsBroadcastReceiver resultReceiver, boolean userUnlocked,
+                List<SmsFilter> remainingFilters);
+    }
 }
diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java
index a90daf9..e8c7dc9 100644
--- a/src/java/com/android/internal/telephony/MultiSimSettingController.java
+++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java
@@ -699,7 +699,8 @@
                     && phone.isUserDataEnabled()
                     && !areSubscriptionsInSameGroup(defaultDataSub, phone.getSubId())) {
                 log("setting data to false on " + phone.getSubId());
-                phone.getDataEnabledSettings().setUserDataEnabled(false);
+                phone.getDataEnabledSettings().setDataEnabled(
+                        TelephonyManager.DATA_ENABLED_REASON_USER, false);
             }
         }
     }
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index 5188ba0..22d372f 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -1980,7 +1980,7 @@
      *  Retrieves manually selected network info.
      */
     public String getManualNetworkSelectionPlmn() {
-        return "";
+        return null;
     }
 
 
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index e7a6d44..f767340 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -1643,13 +1643,30 @@
             try {
                 radioProxy.sendSms(rr.mSerial, msg);
                 mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_GSM,
-                        SmsSession.Event.Format.SMS_FORMAT_3GPP);
+                        SmsSession.Event.Format.SMS_FORMAT_3GPP, getOutgoingSmsMessageId(result));
             } catch (RemoteException | RuntimeException e) {
                 handleRadioProxyExceptionForRR(rr, "sendSMS", e);
             }
         }
     }
 
+    /**
+     * Extract the outgoing sms messageId from the tracker, if there is one. This is specifically
+     * for SMS related APIs.
+     * @param result the result Message
+     * @return messageId unique identifier or 0 if there is no message id
+     */
+    public static long getOutgoingSmsMessageId(Message result) {
+        if (result == null || !(result.obj instanceof SMSDispatcher.SmsTracker)) {
+            return 0L;
+        }
+        long messageId = ((SMSDispatcher.SmsTracker) result.obj).mMessageId;
+        if (RILJ_LOGV) {
+            Rlog.d(RILJ_LOG_TAG, "getOutgoingSmsMessageId messageId: " + messageId);
+        }
+        return messageId;
+    }
+
     @Override
     public void sendSMSExpectMore(String smscPdu, String pdu, Message result) {
         IRadio radioProxy = getRadioProxy(result);
@@ -1665,7 +1682,7 @@
             try {
                 radioProxy.sendSMSExpectMore(rr.mSerial, msg);
                 mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_GSM,
-                        SmsSession.Event.Format.SMS_FORMAT_3GPP);
+                        SmsSession.Event.Format.SMS_FORMAT_3GPP, getOutgoingSmsMessageId(result));
             } catch (RemoteException | RuntimeException e) {
                 handleRadioProxyExceptionForRR(rr, "sendSMSExpectMore", e);
             }
@@ -3521,7 +3538,8 @@
                 try {
                     radioProxy15.sendCdmaSmsExpectMore(rr.mSerial, msg);
                     mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_CDMA,
-                            SmsSession.Event.Format.SMS_FORMAT_3GPP2);
+                            SmsSession.Event.Format.SMS_FORMAT_3GPP2,
+                            getOutgoingSmsMessageId(result));
                 } catch (RemoteException | RuntimeException e) {
                     handleRadioProxyExceptionForRR(rr, "sendCdmaSMSExpectMore", e);
                 }
@@ -3547,7 +3565,7 @@
             try {
                 radioProxy.sendCdmaSms(rr.mSerial, msg);
                 mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_CDMA,
-                        SmsSession.Event.Format.SMS_FORMAT_3GPP2);
+                        SmsSession.Event.Format.SMS_FORMAT_3GPP2, getOutgoingSmsMessageId(result));
             } catch (RemoteException | RuntimeException e) {
                 handleRadioProxyExceptionForRR(rr, "sendCdmaSms", e);
             }
@@ -4072,7 +4090,7 @@
             try {
                 radioProxy.sendImsSms(rr.mSerial, msg);
                 mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_IMS,
-                        SmsSession.Event.Format.SMS_FORMAT_3GPP);
+                        SmsSession.Event.Format.SMS_FORMAT_3GPP, getOutgoingSmsMessageId(result));
             } catch (RemoteException | RuntimeException e) {
                 handleRadioProxyExceptionForRR(rr, "sendImsGsmSms", e);
             }
@@ -4101,7 +4119,7 @@
             try {
                 radioProxy.sendImsSms(rr.mSerial, msg);
                 mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_IMS,
-                        SmsSession.Event.Format.SMS_FORMAT_3GPP2);
+                        SmsSession.Event.Format.SMS_FORMAT_3GPP2, getOutgoingSmsMessageId(result));
             } catch (RemoteException | RuntimeException e) {
                 handleRadioProxyExceptionForRR(rr, "sendImsCdmaSms", e);
             }
@@ -5599,9 +5617,9 @@
     }
 
     private void processResponseCleanUp(RILRequest rr, RadioResponseInfo responseInfo, Object ret) {
-        mMetrics.writeOnRilSolicitedResponse(mPhoneId, rr.mSerial, responseInfo.error,
-                rr.mRequest, ret);
         if (rr != null) {
+            mMetrics.writeOnRilSolicitedResponse(mPhoneId, rr.mSerial, responseInfo.error,
+                    rr.mRequest, ret);
             if (responseInfo.type == RadioResponseType.SOLICITED) {
                 decrementWakeLock(rr);
             }
diff --git a/src/java/com/android/internal/telephony/RadioResponse.java b/src/java/com/android/internal/telephony/RadioResponse.java
index 0afbd13..ffebae4 100644
--- a/src/java/com/android/internal/telephony/RadioResponse.java
+++ b/src/java/com/android/internal/telephony/RadioResponse.java
@@ -2157,7 +2157,8 @@
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
-            SmsResponse ret = new SmsResponse(sms.messageRef, sms.ackPDU, sms.errorCode);
+            long messageId = RIL.getOutgoingSmsMessageId(rr.mResult);
+            SmsResponse ret = new SmsResponse(sms.messageRef, sms.ackPDU, sms.errorCode, messageId);
             if (responseInfo.error == RadioError.NONE) {
                 sendMessageResponse(rr.mResult, ret);
             }
diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java
index c7f8c1b..30162b2 100644
--- a/src/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/SMSDispatcher.java
@@ -514,7 +514,8 @@
             return;
         }
 
-        SmsResponse smsResponse = new SmsResponse(messageRef, null /* ackPdu */, NO_ERROR_CODE);
+        SmsResponse smsResponse = new SmsResponse(messageRef, null /* ackPdu */, NO_ERROR_CODE,
+                tracker.mMessageId);
 
         switch (result) {
             case CarrierMessagingService.SEND_STATUS_OK:
diff --git a/src/java/com/android/internal/telephony/SmsResponse.java b/src/java/com/android/internal/telephony/SmsResponse.java
index e2209be..5e9aab2 100644
--- a/src/java/com/android/internal/telephony/SmsResponse.java
+++ b/src/java/com/android/internal/telephony/SmsResponse.java
@@ -39,18 +39,26 @@
     @UnsupportedAppUsage
     public int mErrorCode;
 
+    public long mMessageId;
+
     @UnsupportedAppUsage
     public SmsResponse(int messageRef, String ackPdu, int errorCode) {
+        this(messageRef, ackPdu, errorCode, /* messageId= */ 0L);
+    }
+
+    public SmsResponse(int messageRef, String ackPdu, int errorCode, long messageId) {
         mMessageRef = messageRef;
         mAckPdu = ackPdu;
         mErrorCode = errorCode;
+        mMessageId = messageId;
     }
 
     @Override
     public String toString() {
         String ret = "{ mMessageRef = " + mMessageRef
                         + ", mErrorCode = " + mErrorCode
-                        + ", mAckPdu = " + mAckPdu
+                + ", mAckPdu = " + mAckPdu
+                + ", mMessageId = " + mMessageId
                         + "}";
         return ret;
     }
diff --git a/src/java/com/android/internal/telephony/SmsUsageMonitor.java b/src/java/com/android/internal/telephony/SmsUsageMonitor.java
index 8f583d9..5bf2792 100644
--- a/src/java/com/android/internal/telephony/SmsUsageMonitor.java
+++ b/src/java/com/android/internal/telephony/SmsUsageMonitor.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.telephony;
 
+import android.app.role.RoleManager;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -51,6 +52,7 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.regex.Pattern;
@@ -125,6 +127,8 @@
     /** Last modified time for pattern file */
     private long mPatternFileLastModified = 0;
 
+    private RoleManager mRoleManager;
+
     /** Directory for per-app SMS permission XML file. */
     private static final String SMS_POLICY_FILE_DIRECTORY = "/data/misc/sms";
 
@@ -248,6 +252,7 @@
     public SmsUsageMonitor(Context context) {
         mContext = context;
         ContentResolver resolver = context.getContentResolver();
+        mRoleManager = (RoleManager) mContext.getSystemService(Context.ROLE_SERVICE);
 
         mMaxAllowed = Settings.Global.getInt(resolver,
                 Settings.Global.SMS_OUTGOING_CHECK_MAX_COUNT,
@@ -345,7 +350,7 @@
     /**
      * Check to see if an application is allowed to send new SMS messages, and confirm with
      * user if the send limit was reached or if a non-system app is potentially sending to a
-     * premium SMS short code or number.
+     * premium SMS short code or number. If the app is the default SMS app, there's no send limit.
      *
      * @param appName the package name of the app requesting to send an SMS
      * @param smsWaiting the number of new messages desired to send
@@ -363,7 +368,12 @@
                 mSmsStamp.put(appName, sentList);
             }
 
-            return isUnderLimit(sentList, smsWaiting);
+            List<String> defaultApp = mRoleManager.getRoleHolders(RoleManager.ROLE_SMS);
+            if (defaultApp.contains(appName)) {
+                return true;
+            } else {
+                return isUnderLimit(sentList, smsWaiting);
+            }
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
index dc842d2..036d61c 100644
--- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
+++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
@@ -576,10 +576,6 @@
             }
         }
 
-        // Update set of enabled carrier apps now that the privilege rules may have changed.
-        CarrierAppUtils.disableCarrierAppsUntilPrivileged(sContext.getOpPackageName(),
-                TelephonyManager.getDefault(), mCurrentlyActiveUserId, sContext);
-
         /**
          * The sim loading sequence will be
          *  1. ACTION_SUBINFO_CONTENT_CHANGE happens through updateSubscriptionInfoByIccId() above.
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java b/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java
index 10c9db6..fc4619c 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java
@@ -69,7 +69,8 @@
                     REASON_PROVISIONED_CHANGED,
                     REASON_PROVISIONING_DATA_ENABLED_CHANGED,
                     REASON_OVERRIDE_RULE_CHANGED,
-                    REASON_OVERRIDE_CONDITION_CHANGED
+                    REASON_OVERRIDE_CONDITION_CHANGED,
+                    REASON_THERMAL_DATA_ENABLED
             })
     public @interface DataEnabledChangedReason {}
 
@@ -91,6 +92,8 @@
 
     public static final int REASON_OVERRIDE_CONDITION_CHANGED = 8;
 
+    public static final int REASON_THERMAL_DATA_ENABLED = 9;
+
     /**
      * responds to the setInternalDataEnabled call - used internally to turn off data.
      * For example during emergency calls
@@ -108,6 +111,15 @@
      */
     private boolean mCarrierDataEnabled = true;
 
+    /**
+     * Flag indicating data allowed by Thermal service or not.
+     */
+    private boolean mThermalDataEnabled = true;
+
+    /**
+     * Flag indicating whether data is allowed or not for the device. It can be disabled by
+     * user, carrier, policy or thermal
+     */
     private boolean mIsDataEnabled = false;
 
     private final Phone mPhone;
@@ -172,6 +184,7 @@
                 + ", mPolicyDataEnabled=" + mPolicyDataEnabled
                 + ", mCarrierDataEnabled=" + mCarrierDataEnabled
                 + ", mIsDataEnabled=" + mIsDataEnabled
+                + ", mThermalDataEnabled=" + mThermalDataEnabled
                 + ", " + mDataEnabledOverride
                 + "]";
     }
@@ -204,7 +217,7 @@
         return mInternalDataEnabled;
     }
 
-    public synchronized void setUserDataEnabled(boolean enabled) {
+    private synchronized void setUserDataEnabled(boolean enabled) {
         // By default the change should propagate to the group.
         setUserDataEnabled(enabled, true);
     }
@@ -233,6 +246,32 @@
         }
     }
 
+    /**
+     * Policy control of data connection with reason
+     * @param reason the reason the data enable change is taking place
+     * @param enabled True if enabling the data, otherwise disabling.
+     */
+    public synchronized void setDataEnabled(@TelephonyManager.DataEnabledReason int reason,
+            boolean enabled) {
+        switch (reason) {
+            case TelephonyManager.DATA_ENABLED_REASON_USER:
+                setUserDataEnabled(enabled);
+                break;
+            case TelephonyManager.DATA_ENABLED_REASON_CARRIER:
+                setCarrierDataEnabled(enabled);
+                break;
+            case TelephonyManager.DATA_ENABLED_REASON_POLICY:
+                setPolicyDataEnabled(enabled);
+                break;
+            case TelephonyManager.DATA_ENABLED_REASON_THERMAL:
+                setThermalDataEnabled(enabled);
+                break;
+            default:
+                log("Invalid data enable reason " + reason);
+                break;
+        }
+    }
+
     public synchronized boolean isUserDataEnabled() {
         // User data should always be true for opportunistic subscription.
         if (isStandAloneOpportunistic(mPhone.getSubId(), mPhone.getContext())) return true;
@@ -300,7 +339,7 @@
         return mDataEnabledOverride.isDataAllowedInVoiceCall();
     }
 
-    public synchronized void setPolicyDataEnabled(boolean enabled) {
+    private synchronized void setPolicyDataEnabled(boolean enabled) {
         if (mPolicyDataEnabled != enabled) {
             localLog("PolicyDataEnabled", enabled);
             mPolicyDataEnabled = enabled;
@@ -312,7 +351,7 @@
         return mPolicyDataEnabled;
     }
 
-    public synchronized void setCarrierDataEnabled(boolean enabled) {
+    private synchronized void setCarrierDataEnabled(boolean enabled) {
         if (mCarrierDataEnabled != enabled) {
             localLog("CarrierDataEnabled", enabled);
             mCarrierDataEnabled = enabled;
@@ -324,6 +363,18 @@
         return mCarrierDataEnabled;
     }
 
+    private synchronized void setThermalDataEnabled(boolean enabled) {
+        if (mThermalDataEnabled != enabled) {
+            localLog("ThermalDataEnabled", enabled);
+            mThermalDataEnabled = enabled;
+            updateDataEnabledAndNotify(REASON_THERMAL_DATA_ENABLED);
+        }
+    }
+
+    public synchronized boolean isThermalDataEnabled() {
+        return mThermalDataEnabled;
+    }
+
     public synchronized void updateProvisionedChanged() {
         updateDataEnabledAndNotify(REASON_PROVISIONED_CHANGED);
     }
@@ -336,6 +387,27 @@
         return mIsDataEnabled;
     }
 
+    /**
+     * Check if data is enabled for a specific reason {@@TelephonyManager.DataEnabledReason}
+     *
+     * @return {@code true} if the overall data is enabled; {@code false} if not.
+     */
+    public synchronized boolean isDataEnabledWithReason(
+            @TelephonyManager.DataEnabledReason int reason) {
+        switch (reason) {
+            case TelephonyManager.DATA_ENABLED_REASON_USER:
+                return isUserDataEnabled();
+            case TelephonyManager.DATA_ENABLED_REASON_CARRIER:
+                return isCarrierDataEnabled();
+            case TelephonyManager.DATA_ENABLED_REASON_POLICY:
+                return isPolicyDataEnabled();
+            case TelephonyManager.DATA_ENABLED_REASON_THERMAL:
+                return isThermalDataEnabled();
+            default:
+                return false;
+        }
+    }
+
     private synchronized void updateDataEnabledAndNotify(int reason) {
         boolean prevDataEnabled = mIsDataEnabled;
 
@@ -352,7 +424,7 @@
         } else {
             mIsDataEnabled = mInternalDataEnabled && (isUserDataEnabled() || mDataEnabledOverride
                     .shouldOverrideDataEnabledSettings(mPhone, ApnSetting.TYPE_ALL))
-                    && mPolicyDataEnabled && mCarrierDataEnabled;
+                    && mPolicyDataEnabled && mCarrierDataEnabled && mThermalDataEnabled;
         }
     }
 
@@ -469,7 +541,7 @@
                     .shouldOverrideDataEnabledSettings(mPhone, apnType);
 
             return (mInternalDataEnabled && mPolicyDataEnabled && mCarrierDataEnabled
-                    && (userDataEnabled || isDataEnabledOverridden));
+                    && mThermalDataEnabled && (userDataEnabled || isDataEnabledOverridden));
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
index 246d2e0..bf81bd5 100644
--- a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
+++ b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
@@ -1820,8 +1820,10 @@
         } else {
 
             int errorCode = SmsResponse.NO_ERROR_CODE;
+            long messageId = 0L;
             if (response != null) {
                 errorCode = response.mErrorCode;
+                messageId = response.mMessageId;
             }
 
             smsSession.addEvent(new SmsSessionEventBuilder(
@@ -1829,6 +1831,7 @@
                     .setErrorCode(errorCode)
                     .setRilErrno(rilError + 1)
                     .setRilRequestId(rilSerial)
+                    .setMessageId(messageId)
             );
 
             smsSession.decreaseExpectedResponse();
@@ -1856,7 +1859,7 @@
                     SmsSession.Event.Type.SMS_SEND_RESULT)
                     .setImsServiceErrno(resultCode)
                     .setErrorCode(errorReason)
-                    .setMessageId((messageId))
+                    .setMessageId(messageId)
             );
 
             smsSession.decreaseExpectedResponse();
@@ -2237,14 +2240,17 @@
      * @param rilSerial RIL request serial number
      * @param tech SMS RAT
      * @param format SMS format. Either 3GPP or 3GPP2.
+     * @param messageId Unique id for this message.
      */
-    public synchronized void writeRilSendSms(int phoneId, int rilSerial, int tech, int format) {
+    public synchronized void writeRilSendSms(int phoneId, int rilSerial, int tech, int format,
+            long messageId) {
         InProgressSmsSession smsSession = startNewSmsSessionIfNeeded(phoneId);
 
         smsSession.addEvent(new SmsSessionEventBuilder(SmsSession.Event.Type.SMS_SEND)
                 .setTech(tech)
                 .setRilRequestId(rilSerial)
                 .setFormat(format)
+                .setMessageId(messageId)
         );
 
         smsSession.increaseExpectedResponse();
@@ -2259,14 +2265,16 @@
      *         {@link SmsMessage#FORMAT_3GPP2}.
      * @param resultCode The result of sending the new SMS to the vendor layer to be sent to the
      *         carrier network.
+     * @param messageId Unique id for this message.
      */
     public synchronized void writeImsServiceSendSms(int phoneId, String format,
-            @ImsSmsImplBase.SendStatusResult int resultCode) {
+            @ImsSmsImplBase.SendStatusResult int resultCode, long messageId) {
         InProgressSmsSession smsSession = startNewSmsSessionIfNeeded(phoneId);
         smsSession.addEvent(new SmsSessionEventBuilder(SmsSession.Event.Type.SMS_SEND)
                 .setTech(SmsSession.Event.Tech.SMS_IMS)
                 .setImsServiceErrno(resultCode)
                 .setFormat(convertSmsFormat(format))
+                .setMessageId(messageId)
         );
 
         smsSession.increaseExpectedResponse();
diff --git a/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java b/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java
index e1bc0b7..c1a6960 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java
@@ -32,6 +32,7 @@
 import android.text.TextUtils;
 import android.util.LocalLog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.CommandException;
 import com.android.telephony.Rlog;
 
@@ -228,6 +229,14 @@
         openChannel(mAIDInUse);
     }
 
+    @VisibleForTesting
+    public UiccCarrierPrivilegeRules(List<UiccAccessRule> rules) {
+        mAccessRules = rules;
+        mState = new AtomicInteger(STATE_LOADED);
+        mRules = "";
+        mStatusMessage.log("Loaded from test rules.");
+    }
+
     /**
      * Returns true if the carrier privilege rules have finished loading.
      */
diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
index a0276c7..cac849e 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.telephony.uicc;
 
+import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.app.usage.UsageStatsManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -48,6 +50,7 @@
 import android.util.ArraySet;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.CarrierAppUtils;
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.IccCardConstants;
@@ -106,6 +109,7 @@
     private final UiccCard mUiccCard; //parent
     private CatService mCatService;
     private UiccCarrierPrivilegeRules mCarrierPrivilegeRules;
+    private UiccCarrierPrivilegeRules mTestOverrideCarrierPrivilegeRules;
     private boolean mDisposed = false;
 
     private RegistrantList mCarrierPrivilegeRegistrants = new RegistrantList();
@@ -128,6 +132,7 @@
     private static final int EVENT_SIM_IO_DONE = 12;
     private static final int EVENT_CARRIER_PRIVILEGES_LOADED = 13;
     private static final int EVENT_CARRIER_CONFIG_CHANGED = 14;
+    private static final int EVENT_CARRIER_PRIVILEGES_TEST_OVERRIDE_SET = 15;
     // NOTE: any new EVENT_* values must be added to eventToString.
 
     private TelephonyManager mTelephonyManager;
@@ -245,6 +250,16 @@
                     ((Message) ar.userObj).sendToTarget();
                     break;
 
+                case EVENT_CARRIER_PRIVILEGES_TEST_OVERRIDE_SET:
+                    if (msg.obj == null) {
+                        mTestOverrideCarrierPrivilegeRules = null;
+                    } else {
+                        mTestOverrideCarrierPrivilegeRules =
+                                new UiccCarrierPrivilegeRules((List<UiccAccessRule>) msg.obj);
+                    }
+                    refresh();
+                    break;
+
                 default:
                     loge("handleMessage: Unhandled message with number: " + msg.what);
                     break;
@@ -1250,6 +1265,11 @@
     }
 
     private void onCarrierPrivilegesLoadedMessage() {
+        // Update set of enabled carrier apps now that the privilege rules may have changed.
+        ActivityManager am = mContext.getSystemService(ActivityManager.class);
+        CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(),
+                mTelephonyManager, am.getCurrentUser(), mContext);
+
         UsageStatsManager usm = (UsageStatsManager) mContext.getSystemService(
                 Context.USAGE_STATS_SERVICE);
         if (usm != null) {
@@ -1317,11 +1337,12 @@
         if (certPackageMap.isEmpty()) {
             return Collections.emptySet();
         }
-        if (mCarrierPrivilegeRules == null) {
+        UiccCarrierPrivilegeRules rules = getCarrierPrivilegeRules();
+        if (rules == null) {
             return Collections.emptySet();
         }
         Set<String> uninstalledCarrierPackages = new ArraySet<>();
-        List<UiccAccessRule> accessRules = mCarrierPrivilegeRules.getAccessRules();
+        List<UiccAccessRule> accessRules = rules.getAccessRules();
         for (UiccAccessRule accessRule : accessRules) {
             String certHexString = accessRule.getCertificateHexString().toUpperCase();
             String pkgName = certPackageMap.get(certHexString);
@@ -1661,6 +1682,9 @@
     /** Returns a reference to the current {@link UiccCarrierPrivilegeRules}. */
     private UiccCarrierPrivilegeRules getCarrierPrivilegeRules() {
         synchronized (mLock) {
+            if (mTestOverrideCarrierPrivilegeRules != null) {
+                return mTestOverrideCarrierPrivilegeRules;
+            }
             return mCarrierPrivilegeRules;
         }
     }
@@ -1728,11 +1752,14 @@
             case EVENT_ICC_RECORD_EVENTS: return "ICC_RECORD_EVENTS";
             case EVENT_OPEN_LOGICAL_CHANNEL_DONE: return "OPEN_LOGICAL_CHANNEL_DONE";
             case EVENT_CLOSE_LOGICAL_CHANNEL_DONE: return "CLOSE_LOGICAL_CHANNEL_DONE";
-            case EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE: return "TRANSMIT_APDU_LOGICAL_CHANNEL_DONE";
+            case EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE:
+                return "TRANSMIT_APDU_LOGICAL_CHANNEL_DONE";
             case EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE: return "TRANSMIT_APDU_BASIC_CHANNEL_DONE";
             case EVENT_SIM_IO_DONE: return "SIM_IO_DONE";
             case EVENT_CARRIER_PRIVILEGES_LOADED: return "CARRIER_PRIVILEGES_LOADED";
             case EVENT_CARRIER_CONFIG_CHANGED: return "CARRIER_CONFIG_CHANGED";
+            case EVENT_CARRIER_PRIVILEGES_TEST_OVERRIDE_SET:
+                return "CARRIER_PRIVILEGES_TEST_OVERRIDE_SET";
             default: return "UNKNOWN(" + event + ")";
         }
     }
@@ -1760,6 +1787,19 @@
     }
 
     /**
+     * Set a test set of carrier privilege rules which will override the actual rules on the SIM.
+     *
+     * <p>May be null, in which case the rules on the SIM will be used and any previous overrides
+     * will be cleared.
+     *
+     * @see TelephonyManager#setCarrierTestOverride
+     */
+    public void setTestOverrideCarrierPrivilegeRules(@Nullable List<UiccAccessRule> rules) {
+        mHandler.sendMessage(
+                mHandler.obtainMessage(EVENT_CARRIER_PRIVILEGES_TEST_OVERRIDE_SET, rules));
+    }
+
+    /**
      * Dump
      */
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -1812,6 +1852,11 @@
             pw.println(" mCarrierPrivilegeRules: " + mCarrierPrivilegeRules);
             mCarrierPrivilegeRules.dump(fd, pw, args);
         }
+        if (mTestOverrideCarrierPrivilegeRules != null) {
+            pw.println(" mTestOverrideCarrierPrivilegeRules: "
+                    + mTestOverrideCarrierPrivilegeRules);
+            mTestOverrideCarrierPrivilegeRules.dump(fd, pw, args);
+        }
         pw.println(" mCarrierPrivilegeRegistrants: size=" + mCarrierPrivilegeRegistrants.size());
         for (int i = 0; i < mCarrierPrivilegeRegistrants.size(); i++) {
             pw.println("  mCarrierPrivilegeRegistrants[" + i + "]="
diff --git a/src/java/com/android/internal/telephony/vendor/VendorMultiSimSettingController.java b/src/java/com/android/internal/telephony/vendor/VendorMultiSimSettingController.java
index 026b6f5..117b0ea 100644
--- a/src/java/com/android/internal/telephony/vendor/VendorMultiSimSettingController.java
+++ b/src/java/com/android/internal/telephony/vendor/VendorMultiSimSettingController.java
@@ -18,17 +18,17 @@
 
 import android.content.Context;
 import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
 import android.telephony.SubscriptionInfo;
+import android.telephony.TelephonyManager;
 import android.util.Log;
+
 import com.android.internal.telephony.GlobalSettingsHelper;
 import com.android.internal.telephony.MultiSimSettingController;
-import com.android.internal.telephony.SubscriptionController;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.SubscriptionController;
 
 import java.util.List;
-import java.util.stream.Collectors;
 
 /*
  * Extending VendorMultiSimSettingController to override default
@@ -90,7 +90,8 @@
                 // For active subscription, call setUserDataEnabled through DataEnabledSettings.
                 Phone phone = PhoneFactory.getPhone(mSubController.getPhoneId(currentSubId));
                 if (phone != null) {
-                    phone.getDataEnabledSettings().setUserDataEnabled(enable);
+                    phone.getDataEnabledSettings().setDataEnabled(
+                            TelephonyManager.DATA_ENABLED_REASON_USER, enable);
                 }
             } else {
                 // For inactive subscription, directly write into global settings.
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
index 106a2a8..a0e786f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
@@ -290,6 +290,8 @@
                 return Context.POWER_WHITELIST_MANAGER;
             } else if (serviceClass == SystemConfigManager.class) {
                 return Context.SYSTEM_CONFIG_SERVICE;
+            } else if (serviceClass == ActivityManager.class) {
+                return Context.ACTIVITY_SERVICE;
             }
             return super.getSystemServiceName(serviceClass);
         }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java
index af72c70..04e2eee 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java
@@ -313,7 +313,8 @@
         mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1);
         mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2);
         processAllMessages();
-        verify(mDataEnabledSettingsMock2).setUserDataEnabled(false);
+        verify(mDataEnabledSettingsMock2).setDataEnabled(
+                TelephonyManager.DATA_ENABLED_REASON_USER, false);
 
         // Enable on non-default sub should trigger setDefaultDataSubId.
         mMultiSimSettingControllerUT.notifyUserDataEnabled(2, true);
@@ -324,7 +325,8 @@
         doReturn(2).when(mSubControllerMock).getDefaultDataSubId();
         mMultiSimSettingControllerUT.notifyDefaultDataSubChanged();
         processAllMessages();
-        verify(mDataEnabledSettingsMock1).setUserDataEnabled(false);
+        verify(mDataEnabledSettingsMock1).setDataEnabled(
+                TelephonyManager.DATA_ENABLED_REASON_USER, false);
 
         doReturn(1).when(mSubControllerMock).getDefaultDataSubId();
         doReturn(1).when(mSubControllerMock).getDefaultSmsSubId();
@@ -391,7 +393,8 @@
         doReturn(1).when(mSubControllerMock).getDefaultDataSubId();
         mMultiSimSettingControllerUT.notifyDefaultDataSubChanged();
         processAllMessages();
-        verify(mDataEnabledSettingsMock2).setUserDataEnabled(false);
+        verify(mDataEnabledSettingsMock2).setDataEnabled(
+                TelephonyManager.DATA_ENABLED_REASON_USER, false);
         mMultiSimSettingControllerUT.notifyUserDataEnabled(2, false);
         processAllMessages();
         assertFalse(GlobalSettingsHelper.getBoolean(
@@ -439,7 +442,8 @@
         mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2);
         processAllMessages();
         verify(mSubControllerMock).setDefaultDataSubId(2);
-        verify(mDataEnabledSettingsMock1, never()).setUserDataEnabled(anyBoolean());
+        verify(mDataEnabledSettingsMock1, never()).setDataEnabled(
+                anyInt(), anyBoolean());
         // No user selection needed, no intent should be sent.
         verify(mContext, never()).sendBroadcast(any());
 
@@ -456,8 +460,10 @@
         mMultiSimSettingControllerUT.notifyUserDataEnabled(2, true);
         processAllMessages();
         verify(mSubControllerMock, never()).setDefaultDataSubId(anyInt());
-        verify(mDataEnabledSettingsMock1, never()).setUserDataEnabled(anyBoolean());
-        verify(mDataEnabledSettingsMock2, never()).setUserDataEnabled(anyBoolean());
+        verify(mDataEnabledSettingsMock1, never()).setDataEnabled(
+                eq(TelephonyManager.DATA_ENABLED_REASON_USER), anyBoolean());
+        verify(mDataEnabledSettingsMock2, never()).setDataEnabled(
+                TelephonyManager.DATA_ENABLED_REASON_USER, false);
     }
 
     @Test
@@ -551,13 +557,16 @@
         // loaded on both subscriptions.
         mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded();
         processAllMessages();
-        verify(mDataEnabledSettingsMock2, never()).setUserDataEnabled(false);
+        verify(mDataEnabledSettingsMock2, never()).setDataEnabled(
+                TelephonyManager.DATA_ENABLED_REASON_USER, false);
         mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1);
         processAllMessages();
-        verify(mDataEnabledSettingsMock2, never()).setUserDataEnabled(false);
+        verify(mDataEnabledSettingsMock2, never()).setDataEnabled(
+                TelephonyManager.DATA_ENABLED_REASON_USER, false);
         mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2);
         processAllMessages();
-        verify(mDataEnabledSettingsMock2).setUserDataEnabled(false);
+        verify(mDataEnabledSettingsMock2).setDataEnabled(
+                TelephonyManager.DATA_ENABLED_REASON_USER, false);
 
         // Switch from sub 2 to sub 3 in phone[1].
         clearInvocations(mSubControllerMock);
@@ -639,7 +648,8 @@
                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
         processAllMessages();
         // Nothing should happen as carrier config is not ready for sub 2.
-        verify(mDataEnabledSettingsMock2, never()).setUserDataEnabled(false);
+        verify(mDataEnabledSettingsMock2, never()).setDataEnabled(
+                TelephonyManager.DATA_ENABLED_REASON_USER, false);
 
         // Still notify carrier config without specifying subId2, but this time subController
         // and CarrierConfigManager have subId 2 active and ready.
@@ -651,6 +661,7 @@
                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
         processAllMessages();
         // This time user data should be disabled on phone1.
-        verify(mDataEnabledSettingsMock2).setUserDataEnabled(false);
+        verify(mDataEnabledSettingsMock2).setDataEnabled(
+                TelephonyManager.DATA_ENABLED_REASON_USER, false);
     }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataEnabledSettingsTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataEnabledSettingsTest.java
index 52c9573..b3fe158 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataEnabledSettingsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataEnabledSettingsTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.verify;
 
 import android.os.HandlerThread;
+import android.telephony.TelephonyManager;
 import android.telephony.data.ApnSetting;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -104,7 +105,7 @@
     @Test
     @SmallTest
     public void testSetAlwaysAllowMmsData() throws Exception {
-        mDataEnabledSettingsUT.setUserDataEnabled(false);
+        mDataEnabledSettingsUT.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, false);
         assertTrue(mDataEnabledSettingsUT.setAlwaysAllowMmsData(true));
         ArgumentCaptor<String> stringCaptor = ArgumentCaptor.forClass(String.class);
         verify(mSubscriptionController).setDataEnabledOverrideRules(anyInt(),
@@ -120,7 +121,23 @@
         assertEquals("", stringCaptor.getValue());
         assertFalse(mDataEnabledSettingsUT.isDataEnabled(ApnSetting.TYPE_MMS));
 
-        mDataEnabledSettingsUT.setUserDataEnabled(true);
+        mDataEnabledSettingsUT.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, true);
         assertTrue(mDataEnabledSettingsUT.isDataEnabled(ApnSetting.TYPE_MMS));
     }
+
+    @Test
+    @SmallTest
+    public void testSetThermalDataEnabled() throws Exception {
+        mDataEnabledSettingsUT.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_THERMAL,
+                false);
+        assertFalse(mDataEnabledSettingsUT.isDataEnabledWithReason(
+                TelephonyManager.DATA_ENABLED_REASON_THERMAL));
+        assertFalse(mDataEnabledSettingsUT.isDataEnabled());
+
+        mDataEnabledSettingsUT.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_THERMAL,
+                true);
+        assertTrue(mDataEnabledSettingsUT.isDataEnabledWithReason(
+                TelephonyManager.DATA_ENABLED_REASON_THERMAL));
+        assertTrue(mDataEnabledSettingsUT.isDataEnabled());
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
index 411738a..39b78db 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Matchers.nullable;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doReturn;
@@ -34,6 +35,7 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.content.BroadcastReceiver;
 import android.content.ContentValues;
@@ -75,9 +77,13 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.stubbing.Answer;
+import org.mockito.verification.VerificationMode;
 
 import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 @RunWith(AndroidTestingRunner.class)
@@ -102,6 +108,11 @@
     private ContentValues mInboundSmsTrackerCVSub1;
     @Mock
     private CdmaInboundSmsHandler mCdmaInboundSmsHandler;
+    @Mock
+    private InboundSmsHandler.SmsFilter mSmsFilter;
+    @Mock
+    private InboundSmsHandler.SmsFilter mSmsFilter2;
+    private List<InboundSmsHandler.SmsFilter> mSmsFilters;
 
     private GsmInboundSmsHandler mGsmInboundSmsHandler;
 
@@ -235,6 +246,10 @@
 
         mGsmInboundSmsHandler = GsmInboundSmsHandler.makeInboundSmsHandler(mContext,
                 mSmsStorageMonitor, mPhone);
+        mSmsFilters = new ArrayList<>();
+        mSmsFilters.add(mSmsFilter);
+        mSmsFilters.add(mSmsFilter2);
+        mGsmInboundSmsHandler.setSmsFiltersForTesting(mSmsFilters);
         monitorTestableLooper(new TestableLooper(mGsmInboundSmsHandler.getHandler().getLooper()));
         processAllMessages();
     }
@@ -341,6 +356,8 @@
 
         verify(mContext, times(2)).sendBroadcast(any(Intent.class));
         assertEquals("IdleState", getCurrentState().getName());
+
+        verifySmsFiltersInvoked(times(1));
     }
 
     @Test
@@ -355,6 +372,67 @@
 
         verify(mContext, never()).sendBroadcast(any(Intent.class));
         assertEquals("IdleState", getCurrentState().getName());
+
+        // verify no filter was invoked.
+        // TODO(b/136262737): Adjust test once blocked SMSes are passed through filters too.
+        verifySmsFiltersInvoked(never());
+    }
+
+    @Test
+    @MediumTest
+    public void testNewSms_filterInvoked_noBroadcastsSent() {
+        // Configure the first filter to drop the SMS.
+        when(mSmsFilter.filterSms(any(byte[][].class), anyInt(),
+                any(InboundSmsTracker.class), any(InboundSmsHandler.SmsBroadcastReceiver.class),
+                anyBoolean(), Mockito.<List<InboundSmsHandler.SmsFilter>>any()))
+                .thenAnswer((Answer<Boolean>) invocation -> {
+                    mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_BROADCAST_COMPLETE);
+                    return true;
+                });
+
+        transitionFromStartupToIdle();
+
+        sendNewSms();
+
+        verify(mContext, never()).sendBroadcast(any(Intent.class));
+        assertEquals("IdleState", getCurrentState().getName());
+
+        // verify second filter was never invoked.
+        verify(mSmsFilter2, never()).filterSms(any(byte[][].class), anyInt(),
+                any(InboundSmsTracker.class), any(InboundSmsHandler.SmsBroadcastReceiver.class),
+                anyBoolean(), Mockito.<List<InboundSmsHandler.SmsFilter>>any());
+    }
+
+    @Test
+    @MediumTest
+    public void testNewSms_filterChaining_noBroadcastsSent() {
+        // Have the first filter indicate it matched without completing the flow.
+        when(mSmsFilter.filterSms(any(byte[][].class), anyInt(),
+                any(InboundSmsTracker.class), any(InboundSmsHandler.SmsBroadcastReceiver.class),
+                anyBoolean(), Mockito.<List<InboundSmsHandler.SmsFilter>>any())).thenReturn(true);
+
+        transitionFromStartupToIdle();
+
+        sendNewSms();
+
+        verify(mContext, never()).sendBroadcast(any(Intent.class));
+        // Now waiting for the first filter to complete.
+        assertEquals("WaitingState", getCurrentState().getName());
+
+        // Verify the first filter was invoked with the right set of remaining filters.
+        verify(mSmsFilter).filterSms(any(byte[][].class), anyInt(),
+                any(InboundSmsTracker.class), any(InboundSmsHandler.SmsBroadcastReceiver.class),
+                anyBoolean(), eq(Collections.singletonList(mSmsFilter2)));
+
+        // Verify second filter was never invoked.
+        verify(mSmsFilter2, never()).filterSms(any(byte[][].class), anyInt(),
+                any(InboundSmsTracker.class), any(InboundSmsHandler.SmsBroadcastReceiver.class),
+                anyBoolean(), Mockito.<List<InboundSmsHandler.SmsFilter>>any());
+
+        // Clean up by completing the broadcast, as an asynchronous filter must do.
+        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_BROADCAST_COMPLETE);
+        processAllMessages();
+        assertEquals("IdleState", getCurrentState().getName());
     }
 
     private void verifyDataSmsIntentBroadcasts(int numPastBroadcasts) {
@@ -401,6 +479,7 @@
         processAllMessages();
 
         verifySmsIntentBroadcasts(0, true /* allowBgActivityStarts */);
+        verifySmsFiltersInvoked(times(1));
     }
 
     @Test
@@ -438,6 +517,8 @@
         processAllMessages();
 
         verifyDataSmsIntentBroadcasts(1);
+
+        verifySmsFiltersInvoked(times(2));
     }
 
     @FlakyTest
@@ -459,6 +540,8 @@
 
         verify(mContext, times(2)).sendBroadcast(any(Intent.class));
         assertEquals("IdleState", getCurrentState().getName());
+
+        verifySmsFiltersInvoked(times(1));
     }
 
     private void prepareMultiPartSms(boolean is3gpp2WapPush) {
@@ -538,6 +621,7 @@
 
         // verify no broadcast sent.
         verify(mContext, times(0)).sendBroadcast(any(Intent.class));
+        verifySmsFiltersInvoked(never());
 
         // additional copy of part 1 of non-3gpp2wap
         prepareMultiPartSms(false);
@@ -554,6 +638,8 @@
         // verify there are three segments in the db and only one of them is not marked as deleted.
         assertEquals(3, mContentProvider.getNumRows());
         assertEquals(1, mContentProvider.query(sRawUri, null, "deleted=0", null, null).getCount());
+
+        verifySmsFiltersInvoked(times(1));
     }
 
     @FlakyTest
@@ -587,6 +673,7 @@
 
         // verify broadcast intents
         verifySmsIntentBroadcasts(0);
+        verifySmsFiltersInvoked(times(1));
 
         // if an additional copy of one of the segments above is received, it should not be kept in
         // the db and should not be combined with any subsequent messages received from the same
@@ -602,6 +689,7 @@
 
         // verify no additional broadcasts sent
         verify(mContext, times(2)).sendBroadcast(any(Intent.class));
+        verifySmsFiltersInvoked(times(1));
 
         // part 1 of new sms recieved from same sender with same parameters, just different
         // timestamps, should not be combined with the additional part 2 received above
@@ -619,6 +707,7 @@
 
         // verify no additional broadcasts sent
         verify(mContext, times(2)).sendBroadcast(any(Intent.class));
+        verifySmsFiltersInvoked(times(1));
 
         assertEquals("IdleState", getCurrentState().getName());
     }
@@ -681,6 +770,7 @@
         assertEquals(mMessageBodyPart2, c.getString(c.getColumnIndex("message_body")));
         // State machine should go back to idle
         assertEquals("IdleState", getCurrentState().getName());
+        verifySmsFiltersInvoked(never());
     }
 
     @Test
@@ -736,6 +826,7 @@
         verify(mContext, never()).sendBroadcast(any(Intent.class));
         // State machine should go back to idle
         assertEquals("IdleState", getCurrentState().getName());
+        verifySmsFiltersInvoked(never());
     }
 
     @Test
@@ -770,6 +861,8 @@
 
         verify(mContext, never()).sendBroadcast(any(Intent.class));
         assertEquals("IdleState", getCurrentState().getName());
+        // TODO(b/136262737): Adjust test once blocked SMSes are passed through filters too.
+        verifySmsFiltersInvoked(never());
     }
 
     @Test
@@ -820,6 +913,55 @@
 
         verify(mContext, never()).sendBroadcast(any(Intent.class));
         assertEquals("IdleState", getCurrentState().getName());
+        // TODO(b/136262737): Adjust test once blocked SMSes are passed through filters too.
+        verifySmsFiltersInvoked(never());
+    }
+
+    @Test
+    @MediumTest
+    public void testMultipartSms_filterInvoked_noBroadcastsSent() {
+        // Configure the first filter to drop the SMS.
+        when(mSmsFilter.filterSms(any(byte[][].class), anyInt(),
+                any(InboundSmsTracker.class), any(InboundSmsHandler.SmsBroadcastReceiver.class),
+                anyBoolean(), Mockito.<List<InboundSmsHandler.SmsFilter>>any()))
+                .thenAnswer((Answer<Boolean>) invocation -> {
+                    mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_BROADCAST_COMPLETE);
+                    return true;
+                });
+
+        transitionFromStartupToIdle();
+
+        // prepare SMS part 1 and part 2
+        prepareMultiPartSms(false);
+
+        mSmsHeader.concatRef = new SmsHeader.ConcatRef();
+        doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader();
+
+        doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory)
+                .makeInboundSmsTracker(any(Context.class), nullable(byte[].class), anyLong(),
+                        anyInt(), anyBoolean(),
+                        nullable(String.class), nullable(String.class), anyInt(), anyInt(),
+                        anyInt(), anyBoolean(), nullable(String.class), anyBoolean(), anyInt());
+        sendNewSms();
+
+        // State machine should go back to idle and wait for second part
+        assertEquals("IdleState", getCurrentState().getName());
+
+        doReturn(mInboundSmsTrackerPart2).when(mTelephonyComponentFactory)
+                .makeInboundSmsTracker(any(Context.class), nullable(byte[].class), anyLong(),
+                        anyInt(), anyBoolean(),
+                        nullable(String.class), nullable(String.class), anyInt(), anyInt(),
+                        anyInt(), anyBoolean(), nullable(String.class), anyBoolean(), anyInt());
+        sendNewSms();
+
+        // verify no broadcasts sent
+        verify(mContext, never()).sendBroadcast(any(Intent.class));
+        assertEquals("IdleState", getCurrentState().getName());
+
+        // verify second filter was never invoked.
+        verify(mSmsFilter2, never()).filterSms(any(byte[][].class), anyInt(),
+                any(InboundSmsTracker.class), any(InboundSmsHandler.SmsBroadcastReceiver.class),
+                anyBoolean(), Mockito.<List<InboundSmsHandler.SmsFilter>>any());
     }
 
     @Test
@@ -859,6 +1001,7 @@
         processAllMessages();
 
         verifyDataSmsIntentBroadcasts(1);
+        verifySmsFiltersInvoked(times(1));
     }
 
     @Test
@@ -879,6 +1022,7 @@
 
         // user is unlocked; intent should be broadcast right away
         verifyDataSmsIntentBroadcasts(0);
+        verifySmsFiltersInvoked(times(1));
     }
 
     @Test
@@ -917,7 +1061,7 @@
 
         verify(mContext, times(1)).sendBroadcast(any(Intent.class));
         assertEquals("IdleState", getCurrentState().getName());
-
+        verifySmsFiltersInvoked(never());
     }
 
     @FlakyTest
@@ -944,6 +1088,7 @@
         processAllMessages();
 
         verifySmsIntentBroadcasts(0);
+        verifySmsFiltersInvoked(times(1));
     }
 
     @Test
@@ -962,5 +1107,15 @@
 
         verifySmsIntentBroadcasts(0, mSubId0, true);
         verifySmsIntentBroadcasts(2, mSubId1, false);
+        verifySmsFiltersInvoked(times(2));
+    }
+
+    private void verifySmsFiltersInvoked(VerificationMode verificationMode) {
+        verify(mSmsFilter, verificationMode).filterSms(any(byte[][].class), anyInt(),
+                any(InboundSmsTracker.class), any(InboundSmsHandler.SmsBroadcastReceiver.class),
+                anyBoolean(), Mockito.<List<InboundSmsHandler.SmsFilter>>any());
+        verify(mSmsFilter2, verificationMode).filterSms(any(byte[][].class), anyInt(),
+                any(InboundSmsTracker.class), any(InboundSmsHandler.SmsBroadcastReceiver.class),
+                anyBoolean(), Mockito.<List<InboundSmsHandler.SmsFilter>>any());
     }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java
index c1d0bce..6c1cfad 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java
@@ -560,14 +560,17 @@
     @Test
     @SmallTest
     public void testWriteRilSendSms() throws Exception {
-        mMetrics.writeRilSendSms(mPhone.getPhoneId(), 1, 2, 1);
-        mMetrics.writeRilSendSms(mPhone.getPhoneId(), 4, 5, 2);
+        long fakeMessageId1 = 123123L;
+        long fakeMessageId2 = -987L;
 
-        SmsResponse response = new SmsResponse(0, null, 123);
+        mMetrics.writeRilSendSms(mPhone.getPhoneId(), 1, 2, 1, fakeMessageId1);
+        mMetrics.writeRilSendSms(mPhone.getPhoneId(), 4, 5, 2, fakeMessageId2);
+
+        SmsResponse response = new SmsResponse(0, null, 123, fakeMessageId1);
 
         mMetrics.writeOnRilSolicitedResponse(mPhone.getPhoneId(), 1, 0, RIL_REQUEST_SEND_SMS,
                 response);
-        response = new SmsResponse(0, null, 456);
+        response = new SmsResponse(0, null, 456, fakeMessageId2);
         mMetrics.writeOnRilSolicitedResponse(mPhone.getPhoneId(), 4, 0, RIL_REQUEST_SEND_SMS,
                 response);
         TelephonyLog log = buildProto();
@@ -583,21 +586,25 @@
         assertEquals(1, events[0].rilRequestId);
         assertEquals(2, events[0].tech);
         assertEquals(1, events[0].format);
+        assertEquals(fakeMessageId1, events[0].messageId);
 
         assertEquals(SmsSession.Event.Type.SMS_SEND, events[1].type);
         assertEquals(4, events[1].rilRequestId);
         assertEquals(5, events[1].tech);
         assertEquals(2, events[1].format);
+        assertEquals(fakeMessageId2, events[1].messageId);
 
         assertEquals(SmsSession.Event.Type.SMS_SEND_RESULT, events[2].type);
         assertEquals(1, events[2].rilRequestId);
         assertEquals(1, events[2].error);
         assertEquals(123, events[2].errorCode);
+        assertEquals(fakeMessageId1, events[2].messageId);
 
         assertEquals(SmsSession.Event.Type.SMS_SEND_RESULT, events[3].type);
         assertEquals(4, events[3].rilRequestId);
         assertEquals(1, events[3].error);
         assertEquals(456, events[3].errorCode);
+        assertEquals(fakeMessageId2, events[3].messageId);
     }
 
     // Test write phone state