Merge "IMS: Propagate media profile changed message"
diff --git a/Android.bp b/Android.bp
index 9f5459b..80070b7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -47,6 +47,7 @@
     ],
     static_libs: [
         "telephony-protos",
+        "ecc-protos-lite",
         "android.hardware.radio-V1.0-java",
         "android.hardware.radio-V1.1-java",
         "android.hardware.radio-V1.2-java",
diff --git a/proto/src/telephony.proto b/proto/src/telephony.proto
index 1e7db0d..31d8ea8 100644
--- a/proto/src/telephony.proto
+++ b/proto/src/telephony.proto
@@ -47,6 +47,9 @@
 
   // Modem power stats
   optional ModemPowerStats modem_power_stats = 8;
+
+  // Hardware revision (EVT, DVT, PVT etc.)
+  optional string hardware_revision = 9;
 }
 
 // The time information
@@ -575,11 +578,11 @@
   IMS_E_UNKNOWN = 0;
   // The operation has succeeded
   IMS_E_SUCCESS = 1;
-  // Sending an SMS over IMS has failed. Do not retry over IMS again or fallback to CS.
+  // Sending SMS over IMS failed. Do not retry over IMS again or fallback to CS.
   IMS_E_SMS_SEND_STATUS_ERROR = 2;
-  // Sending an SMS over IMS has failed. Retry over IMS again.
+  // Sending SMS over IMS failed. Retry over IMS again.
   IMS_E_SMS_SEND_STATUS_ERROR_RETRY = 3;
-  // Sending an SMS over IMS has failed. Fallback to sending the SMS over CS.
+  // Sending SMS over IMS failed. Fallback to sending the SMS over CS.
   IMS_E_SMS_SEND_STATUS_ERROR_FALLBACK = 4;
 }
 
@@ -1082,6 +1085,9 @@
 
       // System time overwritten by NITZ (Network time)
       NITZ_TIME = 21;
+
+      // Change of audio codec
+      AUDIO_CODEC = 22;
     }
 
     enum RilRequest {
@@ -1174,6 +1180,53 @@
       CALL_DISCONNECTING = 9;
     }
 
+    // Audio codecs
+    enum AudioCodec {
+
+      // Unknown codec
+      AUDIO_CODEC_UNKNOWN = 0;
+
+      AUDIO_CODEC_AMR = 1;
+
+      AUDIO_CODEC_AMR_WB = 2;
+
+      AUDIO_CODEC_QCELP13K = 3;
+
+      AUDIO_CODEC_EVRC = 4;
+
+      AUDIO_CODEC_EVRC_B = 5;
+
+      AUDIO_CODEC_EVRC_WB = 6;
+
+      AUDIO_CODEC_EVRC_NW = 7;
+
+      AUDIO_CODEC_GSM_EFR = 8;
+
+      AUDIO_CODEC_GSM_FR = 9;
+
+      AUDIO_CODEC_GSM_HR = 10;
+
+      AUDIO_CODEC_G711U = 11;
+
+      AUDIO_CODEC_G723 = 12;
+
+      AUDIO_CODEC_G711A = 13;
+
+      AUDIO_CODEC_G722 = 14;
+
+      AUDIO_CODEC_G711AB = 15;
+
+      AUDIO_CODEC_G729 = 16;
+
+      AUDIO_CODEC_EVS_NB = 17;
+
+      AUDIO_CODEC_EVS_WB = 18;
+
+      AUDIO_CODEC_EVS_SWB = 19;
+
+      AUDIO_CODEC_EVS_FB = 20;
+    }
+
     // The information about a voice call
     message RilCall {
 
@@ -1281,6 +1334,9 @@
 
     // NITZ time in milliseconds
     optional int64 nitz_timestamp_millis = 21;
+
+    // Audio codec at the beginning of the session or when changed
+    optional AudioCodec audio_codec = 22;
   }
 
   // Time when call has started, in minutes since epoch,
@@ -1333,16 +1389,6 @@
 
       // CB message received
       CB_SMS_RECEIVED = 9;
-
-      // Send an SMS message over ImsService
-      SMS_SEND_IMS_SERVICE = 10;
-
-      // Receive an SMS message result over ImsService
-      SMS_SEND_RESULT_IMS_SERVICE = 11;
-
-      // Receive an SMS message over ImsService
-      SMS_RECEIVED_IMS_SERVICE = 12;
-
     }
 
     // Formats used to encode SMS messages
@@ -1380,6 +1426,12 @@
 
       // Service category of CB message
       optional int32 service_category = 4;
+
+      // Message's serial number
+      optional int32 serial_number = 5;
+
+      // The delivered time (UTC) of the message
+      optional int64 delivered_timestamp_millis = 6;
     }
 
     enum CBMessageType {
@@ -1442,8 +1494,9 @@
 
     // See 3GPP 27.005, 3.2.5 for GSM/UMTS,
     // 3GPP2 N.S0005 (IS-41C) Table 171 for CDMA,
-    // or ImsService for IMS specific error codes (using ImsService specific Event.Type)
-    // -1 if unknown or not applicable
+    // Will map to a SmsManager.RESULT_* code if ims_error is populated
+    // SmsManager can be accessed from
+    // frameworks/base/telephony/java/android/telephony/SmsManager.java
     optional int32 error_code = 10;
 
     // RIL error code
@@ -1456,7 +1509,7 @@
     optional CBMessage cell_broadcast_message = 13;
 
     // ImsService error code.
-    optional ImsServiceErrno imsError = 14;
+    optional ImsServiceErrno ims_error = 14;
   }
 
   // Time when session has started, in minutes since epoch,
@@ -1503,4 +1556,20 @@
 
   // Amount of time modem is in tx (ms)
   repeated int64 tx_time_ms = 9;
+
+  // Number of bytes sent (tx)
+  optional int64 num_bytes_tx = 10;
+
+  // Number of packets received (rx)
+  optional int64 num_packets_rx = 11;
+
+  // Number of bytes received (rx)
+  optional int64 num_bytes_rx = 12;
+
+  // Amount of time phone spends in various Radio Access Technologies (ms)
+  repeated int64 time_in_rat_ms = 13;
+
+  // Amount of time phone spends in various cellular
+  // rx signal strength levels (ms)
+  repeated int64 time_in_rx_signal_strength_level_ms = 14;
 }
diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java
index d5e7e0c..2695951 100644
--- a/src/java/com/android/internal/telephony/BaseCommands.java
+++ b/src/java/com/android/internal/telephony/BaseCommands.java
@@ -78,6 +78,7 @@
     protected RegistrantList mNattKeepaliveStatusRegistrants = new RegistrantList();
     protected RegistrantList mPhysicalChannelConfigurationRegistrants = new RegistrantList();
     protected RegistrantList mLceInfoRegistrants = new RegistrantList();
+    protected RegistrantList mEmergencyNumberListRegistrants = new RegistrantList();
 
     protected Registrant mGsmSmsRegistrant;
     protected Registrant mCdmaSmsRegistrant;
@@ -783,6 +784,17 @@
         mSubscriptionStatusRegistrants.remove(h);
     }
 
+    @Override
+    public void registerForEmergencyNumberList(Handler h, int what, Object obj) {
+        Registrant r = new Registrant(h, what, obj);
+        mEmergencyNumberListRegistrants.add(r);
+    }
+
+    @Override
+    public void unregisterForEmergencyNumberList(Handler h) {
+        mEmergencyNumberListRegistrants.remove(h);
+    }
+
     //***** Protected Methods
     /**
      * Store new RadioState and send notification based on the changes
diff --git a/src/java/com/android/internal/telephony/CallFailCause.java b/src/java/com/android/internal/telephony/CallFailCause.java
index acc1432..6e4e01c 100644
--- a/src/java/com/android/internal/telephony/CallFailCause.java
+++ b/src/java/com/android/internal/telephony/CallFailCause.java
@@ -149,6 +149,9 @@
     int DIAL_MODIFIED_TO_SS   = 245;
     int DIAL_MODIFIED_TO_DIAL = 246;
 
+    //Access class blocked - TS 31.121 5.2.1
+    int ACCESS_CLASS_BLOCKED = 260;
+
     //Emergency Redial
     int EMERGENCY_TEMP_FAILURE = 325;
     int EMERGENCY_PERM_FAILURE = 326;
diff --git a/src/java/com/android/internal/telephony/CarrierActionAgent.java b/src/java/com/android/internal/telephony/CarrierActionAgent.java
index 4582404..40fe386 100644
--- a/src/java/com/android/internal/telephony/CarrierActionAgent.java
+++ b/src/java/com/android/internal/telephony/CarrierActionAgent.java
@@ -118,6 +118,10 @@
                 log("SET_METERED_APNS_ENABLED: " + mCarrierActionOnMeteredApnEnabled);
                 mMeteredApnEnabledLog.log("SET_METERED_APNS_ENABLED: "
                         + mCarrierActionOnMeteredApnEnabled);
+                int otaspState = (mCarrierActionOnMeteredApnEnabled)
+                        ? mPhone.getServiceStateTracker().getOtasp()
+                        : TelephonyManager.OTASP_SIM_UNPROVISIONED;
+                mPhone.notifyOtaspChanged(otaspState);
                 mMeteredApnEnableRegistrants.notifyRegistrants(
                         new AsyncResult(null, mCarrierActionOnMeteredApnEnabled, null));
                 break;
diff --git a/src/java/com/android/internal/telephony/CarrierResolver.java b/src/java/com/android/internal/telephony/CarrierResolver.java
index 0c7950f..20d7be8 100644
--- a/src/java/com/android/internal/telephony/CarrierResolver.java
+++ b/src/java/com/android/internal/telephony/CarrierResolver.java
@@ -375,7 +375,6 @@
                     .ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED);
             intent.putExtra(TelephonyManager.EXTRA_CARRIER_ID, mCarrierId);
             intent.putExtra(TelephonyManager.EXTRA_CARRIER_NAME, mCarrierName);
-            intent.putExtra(TelephonyManager.EXTRA_MNO_CARRIER_ID, mMnoCarrierId);
             intent.putExtra(TelephonyManager.EXTRA_SUBSCRIPTION_ID, mPhone.getSubId());
             mContext.sendBroadcast(intent);
 
@@ -383,10 +382,12 @@
             ContentValues cv = new ContentValues();
             cv.put(CarrierId.CARRIER_ID, mCarrierId);
             cv.put(CarrierId.CARRIER_NAME, mCarrierName);
-            cv.put(CarrierId.MNO_CARRIER_ID, mMnoCarrierId);
             mContext.getContentResolver().update(
-                    Uri.withAppendedPath(CarrierId.CONTENT_URI,
-                            Integer.toString(mPhone.getSubId())), cv, null, null);
+                    Telephony.CarrierId.getUriForSubscriptionId(mPhone.getSubId()), cv, null, null);
+            if (SubscriptionManager.isValidSubscriptionId(mPhone.getSubId())) {
+                // only persist carrier id to simInfo db when subId is valid.
+                SubscriptionController.getInstance().setCarrierId(mCarrierId, mPhone.getSubId());
+            }
         }
 
         update = false;
diff --git a/src/java/com/android/internal/telephony/CellBroadcastHandler.java b/src/java/com/android/internal/telephony/CellBroadcastHandler.java
index 2261340..4c4148d 100644
--- a/src/java/com/android/internal/telephony/CellBroadcastHandler.java
+++ b/src/java/com/android/internal/telephony/CellBroadcastHandler.java
@@ -94,7 +94,8 @@
         TelephonyMetrics metrics = TelephonyMetrics.getInstance();
         metrics.writeNewCBSms(mPhone.getPhoneId(), message.getMessageFormat(),
                 message.getMessagePriority(), message.isCmasMessage(), message.isEtwsMessage(),
-                message.getServiceCategory());
+                message.getServiceCategory(), message.getSerialNumber(),
+                System.currentTimeMillis());
 
         String msg;
         Intent intent;
diff --git a/src/java/com/android/internal/telephony/CellularNetworkService.java b/src/java/com/android/internal/telephony/CellularNetworkService.java
index fa84b20..ee10023 100644
--- a/src/java/com/android/internal/telephony/CellularNetworkService.java
+++ b/src/java/com/android/internal/telephony/CellularNetworkService.java
@@ -16,7 +16,6 @@
 
 package com.android.internal.telephony;
 
-import android.annotation.CallSuper;
 import android.hardware.radio.V1_0.CellInfoType;
 import android.hardware.radio.V1_0.RegState;
 import android.os.AsyncResult;
@@ -24,6 +23,7 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.CellIdentity;
 import android.telephony.CellIdentityCdma;
@@ -31,6 +31,7 @@
 import android.telephony.CellIdentityLte;
 import android.telephony.CellIdentityTdscdma;
 import android.telephony.CellIdentityWcdma;
+import android.telephony.LteVopsSupportInfo;
 import android.telephony.NetworkRegistrationState;
 import android.telephony.NetworkService;
 import android.telephony.NetworkServiceCallback;
@@ -272,11 +273,13 @@
                 int[] availableServices = getAvailableServices(regState, domain, emergencyOnly);
                 CellIdentity cellIdentity =
                         convertHalCellIdentityToCellIdentity(dataRegState.cellIdentity);
-
+                LteVopsSupportInfo lteVopsSupportInfo =
+                        new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE,
+                        LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE);
                 return new NetworkRegistrationState(domain, transportType, regState,
                         accessNetworkTechnology, reasonForDenial, emergencyOnly, availableServices,
                         cellIdentity, maxDataCalls, false /* isDcNrRestricted */,
-                        false /* isNrAvailable */);
+                        false /* isNrAvailable */, false /* isEnDcAvailable */, lteVopsSupportInfo);
 
             } else if (result instanceof android.hardware.radio.V1_2.DataRegStateResult) {
                 android.hardware.radio.V1_2.DataRegStateResult dataRegState =
@@ -289,15 +292,61 @@
                 int[] availableServices = getAvailableServices(regState, domain, emergencyOnly);
                 CellIdentity cellIdentity =
                         convertHalCellIdentityToCellIdentity(dataRegState.cellIdentity);
-
+                LteVopsSupportInfo lteVopsSupportInfo =
+                        new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE,
+                        LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE);
                 return new NetworkRegistrationState(domain, transportType, regState,
                         accessNetworkTechnology, reasonForDenial, emergencyOnly, availableServices,
                         cellIdentity, maxDataCalls, false /* isDcNrRestricted */,
-                        false /* isNrAvailable */);
+                        false /* isNrAvailable */, false /* isEnDcAvailable */, lteVopsSupportInfo);
+            } else if (result instanceof android.hardware.radio.V1_4.DataRegStateResult) {
+                android.hardware.radio.V1_4.DataRegStateResult dataRegState =
+                        (android.hardware.radio.V1_4.DataRegStateResult) result;
+                int regState = getRegStateFromHalRegState(dataRegState.base.regState);
+                int accessNetworkTechnology =
+                        getAccessNetworkTechnologyFromRat(dataRegState.base.rat);
+                LteVopsSupportInfo lteVopsSupportInfo = null;
+                int reasonForDenial = dataRegState.base.reasonDataDenied;
+                boolean emergencyOnly = isEmergencyOnly(dataRegState.base.regState);
+                int maxDataCalls = dataRegState.base.maxDataCalls;
+                int[] availableServices = getAvailableServices(regState, domain, emergencyOnly);
+                CellIdentity cellIdentity =
+                        convertHalCellIdentityToCellIdentity(dataRegState.base.cellIdentity);
+                android.hardware.radio.V1_4.NrIndicators nrIndicators = dataRegState.nrIndicators;
+                if (AccessNetworkType.EUTRAN == accessNetworkTechnology) {
+                    android.hardware.radio.V1_4.LteVopsInfo vopsSupport =
+                            dataRegState.vopsInfo.lteVopsInfo();
+                    lteVopsSupportInfo = convertHalLteVopsSupportInfo(vopsSupport.isVopsSupported,
+                        vopsSupport.isEmcBearerSupported);
+                } else {
+                    lteVopsSupportInfo =
+                        new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE,
+                        LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE);
+                }
+
+                return new NetworkRegistrationState(domain, transportType, regState,
+                        accessNetworkTechnology, reasonForDenial, emergencyOnly, availableServices,
+                        cellIdentity, maxDataCalls, nrIndicators.isDcNrRestricted,
+                        nrIndicators.isNrAvailable, nrIndicators.isEndcAvailable,
+                        lteVopsSupportInfo);
             }
             return null;
         }
 
+        private LteVopsSupportInfo convertHalLteVopsSupportInfo(
+                boolean vopsSupport, boolean emcBearerSupport) {
+            int vops = LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED;
+            int emergency = LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED;
+
+            if (vopsSupport) {
+                vops = LteVopsSupportInfo.LTE_STATUS_SUPPORTED;
+            }
+            if (emcBearerSupport) {
+                emergency = LteVopsSupportInfo.LTE_STATUS_SUPPORTED;
+            }
+            return new LteVopsSupportInfo(vops, emergency);
+        }
+
         private CellIdentity convertHalCellIdentityToCellIdentity(
                 android.hardware.radio.V1_0.CellIdentity cellIdentity) {
             if (cellIdentity == null) {
@@ -310,9 +359,7 @@
                     if (cellIdentity.cellIdentityGsm.size() == 1) {
                         android.hardware.radio.V1_0.CellIdentityGsm cellIdentityGsm =
                                 cellIdentity.cellIdentityGsm.get(0);
-                        result = new CellIdentityGsm(cellIdentityGsm.lac, cellIdentityGsm.cid,
-                                cellIdentityGsm.arfcn, cellIdentityGsm.bsic, cellIdentityGsm.mcc,
-                                cellIdentityGsm.mnc, null, null);
+                        result = new CellIdentityGsm(cellIdentityGsm);
                     }
                     break;
                 }
@@ -320,9 +367,7 @@
                     if (cellIdentity.cellIdentityWcdma.size() == 1) {
                         android.hardware.radio.V1_0.CellIdentityWcdma cellIdentityWcdma =
                                 cellIdentity.cellIdentityWcdma.get(0);
-                        result = new CellIdentityWcdma(cellIdentityWcdma.lac, cellIdentityWcdma.cid,
-                                cellIdentityWcdma.psc, cellIdentityWcdma.uarfcn,
-                                cellIdentityWcdma.mcc, cellIdentityWcdma.mnc, null, null);
+                        result = new CellIdentityWcdma(cellIdentityWcdma);
                     }
                     break;
                 }
@@ -330,10 +375,7 @@
                     if (cellIdentity.cellIdentityTdscdma.size() == 1) {
                         android.hardware.radio.V1_0.CellIdentityTdscdma cellIdentityTdscdma =
                                 cellIdentity.cellIdentityTdscdma.get(0);
-                        result = new  CellIdentityTdscdma(cellIdentityTdscdma.mcc,
-                                cellIdentityTdscdma.mnc, cellIdentityTdscdma.lac,
-                                cellIdentityTdscdma.cid, cellIdentityTdscdma.cpid,
-                                Integer.MAX_VALUE, null, null);
+                        result = new  CellIdentityTdscdma(cellIdentityTdscdma);
                     }
                     break;
                 }
@@ -341,10 +383,7 @@
                     if (cellIdentity.cellIdentityLte.size() == 1) {
                         android.hardware.radio.V1_0.CellIdentityLte cellIdentityLte =
                                 cellIdentity.cellIdentityLte.get(0);
-
-                        result = new CellIdentityLte(cellIdentityLte.ci, cellIdentityLte.pci,
-                                cellIdentityLte.tac, cellIdentityLte.earfcn, Integer.MAX_VALUE,
-                                cellIdentityLte.mcc, cellIdentityLte.mnc, null, null);
+                        result = new CellIdentityLte(cellIdentityLte);
                     }
                     break;
                 }
@@ -352,10 +391,7 @@
                     if (cellIdentity.cellIdentityCdma.size() == 1) {
                         android.hardware.radio.V1_0.CellIdentityCdma cellIdentityCdma =
                                 cellIdentity.cellIdentityCdma.get(0);
-
-                        result = new CellIdentityCdma(cellIdentityCdma.networkId,
-                                cellIdentityCdma.systemId, cellIdentityCdma.baseStationId,
-                                cellIdentityCdma.longitude, cellIdentityCdma.latitude);
+                        result = new CellIdentityCdma(cellIdentityCdma);
                     }
                     break;
                 }
@@ -379,16 +415,7 @@
                     if (cellIdentity.cellIdentityGsm.size() == 1) {
                         android.hardware.radio.V1_2.CellIdentityGsm cellIdentityGsm =
                                 cellIdentity.cellIdentityGsm.get(0);
-
-                        result = new CellIdentityGsm(
-                                cellIdentityGsm.base.lac,
-                                cellIdentityGsm.base.cid,
-                                cellIdentityGsm.base.arfcn,
-                                cellIdentityGsm.base.bsic,
-                                cellIdentityGsm.base.mcc,
-                                cellIdentityGsm.base.mnc,
-                                cellIdentityGsm.operatorNames.alphaLong,
-                                cellIdentityGsm.operatorNames.alphaShort);
+                        result = new CellIdentityGsm(cellIdentityGsm);
                     }
                     break;
                 }
@@ -396,16 +423,7 @@
                     if (cellIdentity.cellIdentityWcdma.size() == 1) {
                         android.hardware.radio.V1_2.CellIdentityWcdma cellIdentityWcdma =
                                 cellIdentity.cellIdentityWcdma.get(0);
-
-                        result = new CellIdentityWcdma(
-                                cellIdentityWcdma.base.lac,
-                                cellIdentityWcdma.base.cid,
-                                cellIdentityWcdma.base.psc,
-                                cellIdentityWcdma.base.uarfcn,
-                                cellIdentityWcdma.base.mcc,
-                                cellIdentityWcdma.base.mnc,
-                                cellIdentityWcdma.operatorNames.alphaLong,
-                                cellIdentityWcdma.operatorNames.alphaShort);
+                        result = new CellIdentityWcdma(cellIdentityWcdma);
                     }
                     break;
                 }
@@ -413,16 +431,7 @@
                     if (cellIdentity.cellIdentityTdscdma.size() == 1) {
                         android.hardware.radio.V1_2.CellIdentityTdscdma cellIdentityTdscdma =
                                 cellIdentity.cellIdentityTdscdma.get(0);
-
-                        result = new  CellIdentityTdscdma(
-                                cellIdentityTdscdma.base.mcc,
-                                cellIdentityTdscdma.base.mnc,
-                                cellIdentityTdscdma.base.lac,
-                                cellIdentityTdscdma.base.cid,
-                                cellIdentityTdscdma.base.cpid,
-                                cellIdentityTdscdma.uarfcn,
-                                cellIdentityTdscdma.operatorNames.alphaLong,
-                                cellIdentityTdscdma.operatorNames.alphaShort);
+                        result = new  CellIdentityTdscdma(cellIdentityTdscdma);
                     }
                     break;
                 }
@@ -430,17 +439,7 @@
                     if (cellIdentity.cellIdentityLte.size() == 1) {
                         android.hardware.radio.V1_2.CellIdentityLte cellIdentityLte =
                                 cellIdentity.cellIdentityLte.get(0);
-
-                        result = new CellIdentityLte(
-                                cellIdentityLte.base.ci,
-                                cellIdentityLte.base.pci,
-                                cellIdentityLte.base.tac,
-                                cellIdentityLte.base.earfcn,
-                                cellIdentityLte.bandwidth,
-                                cellIdentityLte.base.mcc,
-                                cellIdentityLte.base.mnc,
-                                cellIdentityLte.operatorNames.alphaLong,
-                                cellIdentityLte.operatorNames.alphaShort);
+                        result = new CellIdentityLte(cellIdentityLte);
                     }
                     break;
                 }
@@ -448,15 +447,7 @@
                     if (cellIdentity.cellIdentityCdma.size() == 1) {
                         android.hardware.radio.V1_2.CellIdentityCdma cellIdentityCdma =
                                 cellIdentity.cellIdentityCdma.get(0);
-
-                        result = new CellIdentityCdma(
-                                cellIdentityCdma.base.networkId,
-                                cellIdentityCdma.base.systemId,
-                                cellIdentityCdma.base.baseStationId,
-                                cellIdentityCdma.base.longitude,
-                                cellIdentityCdma.base.latitude,
-                                cellIdentityCdma.operatorNames.alphaLong,
-                                cellIdentityCdma.operatorNames.alphaShort);
+                        result = new CellIdentityCdma(cellIdentityCdma);
                     }
                     break;
                 }
@@ -488,10 +479,8 @@
             }
         }
 
-        @CallSuper
-        protected void onDestroy() {
-            super.onDestroy();
-
+        @Override
+        public void close() {
             mCallbackMap.clear();
             mHandlerThread.quit();
             mPhone.mCi.unregisterForNetworkStateChanged(mHandler);
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index 8b39e8b..f060520 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -825,7 +825,8 @@
      * CLIR_SUPPRESSION == on "CLIR suppression" (allow CLI presentation)
      * CLIR_INVOCATION  == on "CLIR invocation" (restrict CLI presentation)
      */
-    void dial (String address, int clirMode, Message result);
+    void dial(String address, boolean isEmergencyCall, int emergencyServiceCategories,
+               int clirMode, Message result);
 
     /**
      *  returned message
@@ -838,7 +839,8 @@
      * CLIR_SUPPRESSION == on "CLIR suppression" (allow CLI presentation)
      * CLIR_INVOCATION  == on "CLIR invocation" (restrict CLI presentation)
      */
-    void dial(String address, int clirMode, UUSInfo uusInfo, Message result);
+    void dial(String address, boolean isEmergencyCall, int emergencyServiceCategories,
+              int clirMode, UUSInfo uusInfo, Message result);
 
     /**
      *  returned message
@@ -2221,6 +2223,22 @@
     void unregisterForNattKeepaliveStatus(Handler h);
 
     /**
+     * Register for unsolicited Emergency Number List Indications
+     *
+     * @param h Handler for notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    void registerForEmergencyNumberList(Handler h, int what, Object obj);
+
+    /**
+     * Deregister for unsolicited Emergency Number List Indications
+     *
+     * @param h Handler for notification message.
+     */
+    void unregisterForEmergencyNumberList(Handler h);
+
+    /**
      * Start sending NATT Keepalive packets on a specified data connection
      *
      * @param contextId cid that identifies the data connection for this keepalive
diff --git a/src/java/com/android/internal/telephony/Connection.java b/src/java/com/android/internal/telephony/Connection.java
index 05a0081..a48be1f 100755
--- a/src/java/com/android/internal/telephony/Connection.java
+++ b/src/java/com/android/internal/telephony/Connection.java
@@ -23,6 +23,8 @@
 import android.telephony.DisconnectCause;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
+import android.telephony.emergency.EmergencyNumber;
+import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -226,6 +228,29 @@
     private boolean mAnsweringDisconnectsActiveCall;
     private boolean mAllowAddCallDuringVideoCall;
 
+    private boolean mIsEmergencyCall;
+
+    /**
+     * The emergency service categories, only valid if {@link #isEmergencyCall()} returns
+     * {@code true}
+     *
+     * If valid, the value is the bitwise-OR combination of the following constants:
+     * <ol>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_POLICE} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_AMBULANCE} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_MIEC} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_AIEC} </li>
+     * </ol>
+     *
+     * Reference: 3gpp 23.167, Section 6 - Functional description;
+     *            3gpp 22.101, Section 10 - Emergency Calls.
+     */
+    private int mEmergencyServiceCategories;
+
     /**
      * When {@code true}, the network has indicated that this is an emergency call.
      */
@@ -433,6 +458,76 @@
     }
 
     /**
+     * Checks if the connection is for an emergency call.
+     *
+     * @return {@code true} if the call is an emergency call
+     *         or {@code false} otherwise.
+     */
+    public boolean isEmergencyCall() {
+        return mIsEmergencyCall;
+    }
+
+    /**
+     * Sets whether this call is an emergency call or not.
+     *
+     * @param isEmergencyCall {@code true} if the call is an emergency call,
+     *                        or {@code false} otherwise.
+     */
+    public void setEmergencyCall(boolean isEmergencyCall) {
+        mIsEmergencyCall = isEmergencyCall;
+    }
+
+
+    /**
+     * Set the emergency service categories. The set value is valid only if
+     * {@link #getEmergencyServiceCategories()} returns {@code true}
+     *
+     * @return the emergency service categories,
+     *
+     * If valid, the value is the bitwise-OR combination of the following constants:
+     * <ol>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_POLICE} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_AMBULANCE} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_MIEC} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_AIEC} </li>
+     * </ol>
+     *
+     * Reference: 3gpp 23.167, Section 6 - Functional description;
+     *            3gpp 22.101, Section 10 - Emergency Calls.
+     */
+    public @EmergencyServiceCategories int getEmergencyServiceCategories() {
+        return mEmergencyServiceCategories;
+    }
+
+    /**
+     * Set the emergency service categories. The set value is valid only if
+     * {@link #getEmergencyServiceCategories()} returns {@code true}
+     *
+     * If valid, the value is the bitwise-OR combination of the following constants:
+     * <ol>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_POLICE} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_AMBULANCE} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_MIEC} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_AIEC} </li>
+     * </ol>
+     *
+     * Reference: 3gpp 23.167, Section 6 - Functional description;
+     *            3gpp 22.101, Section 10 - Emergency Calls.
+     */
+    public void setEmergencyServiceCategories(
+            @EmergencyServiceCategories int emergencyServiceCategories) {
+        mEmergencyServiceCategories = emergencyServiceCategories;
+    }
+
+    /**
      * If this Connection is connected, then it is associated with
      * a Call.
      *
diff --git a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index 94948cc..e85db77 100644
--- a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -23,6 +23,7 @@
 import android.os.ServiceManager;
 import android.telephony.CellInfo;
 import android.telephony.CellLocation;
+import android.telephony.DataFailCause;
 import android.telephony.PhoneCapability;
 import android.telephony.PhysicalChannelConfig;
 import android.telephony.PreciseCallState;
@@ -30,6 +31,7 @@
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
 
 import java.util.List;
 
@@ -152,13 +154,13 @@
     }
 
     @Override
-    public void notifyDataConnection(Phone sender, String reason, String apnType,
-            PhoneConstants.DataState state) {
-        doNotifyDataConnection(sender, reason, apnType, state);
+    public void notifyDataConnection(Phone sender, String apnType,
+                                     PhoneConstants.DataState state) {
+        doNotifyDataConnection(sender, apnType, state);
     }
 
-    private void doNotifyDataConnection(Phone sender, String reason, String apnType,
-            PhoneConstants.DataState state) {
+    private void doNotifyDataConnection(Phone sender, String apnType,
+                                        PhoneConstants.DataState state) {
         int subId = sender.getSubId();
         long dds = SubscriptionManager.getDefaultDataSubscriptionId();
         if (DBG) log("subId = " + subId + ", DDS = " + dds);
@@ -182,7 +184,7 @@
             if (mRegistry != null) {
                 mRegistry.notifyDataConnectionForSubscriber(subId,
                     PhoneConstantConversions.convertDataState(state),
-                        sender.isDataAllowed(), reason,
+                        sender.isDataAllowed(ApnSetting.getApnTypesBitmaskFromString(apnType)),
                         sender.getActiveApnHost(apnType),
                         apnType,
                         linkProperties,
@@ -196,11 +198,11 @@
     }
 
     @Override
-    public void notifyDataConnectionFailed(Phone sender, String reason, String apnType) {
+    public void notifyDataConnectionFailed(Phone sender, String apnType) {
         int subId = sender.getSubId();
         try {
             if (mRegistry != null) {
-                mRegistry.notifyDataConnectionFailedForSubscriber(subId, reason, apnType);
+                mRegistry.notifyDataConnectionFailedForSubscriber(subId, apnType);
             }
         } catch (RemoteException ex) {
             // system process is dead
@@ -284,11 +286,11 @@
         }
     }
 
-    public void notifyPreciseDataConnectionFailed(Phone sender, String reason, String apnType,
-            String apn, String failCause) {
+    public void notifyPreciseDataConnectionFailed(Phone sender, String apnType,
+            String apn, @DataFailCause.FailCause int failCause) {
         // FIXME: subId?
         try {
-            mRegistry.notifyPreciseDataConnectionFailed(reason, apnType, apn, failCause);
+            mRegistry.notifyPreciseDataConnectionFailed(apnType, apn, failCause);
         } catch (RemoteException ex) {
             // system process is dead
         }
@@ -360,6 +362,17 @@
         }
     }
 
+    @Override
+    public void notifyEmergencyNumberList() {
+        try {
+            if (mRegistry != null) {
+                mRegistry.notifyEmergencyNumberList();
+            }
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
     /**
      * Convert the {@link Phone.DataActivityState} enum into the TelephonyManager.DATA_* constants
      * for the public API.
diff --git a/src/java/com/android/internal/telephony/DeviceStateMonitor.java b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
index 3a96630..358f15f 100644
--- a/src/java/com/android/internal/telephony/DeviceStateMonitor.java
+++ b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
@@ -27,6 +27,9 @@
 import android.hardware.display.DisplayManager;
 import android.hardware.radio.V1_2.IndicationFilter;
 import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
 import android.os.BatteryManager;
 import android.os.Handler;
 import android.os.Message;
@@ -39,11 +42,14 @@
 import android.util.SparseIntArray;
 import android.view.Display;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
 
 /**
  * The device state monitor monitors the device state such as charging state, power saving sate,
@@ -58,21 +64,65 @@
     protected static final boolean DBG = false;      /* STOPSHIP if true */
     protected static final String TAG = DeviceStateMonitor.class.getSimpleName();
 
-    private static final int EVENT_RIL_CONNECTED                = 0;
-    private static final int EVENT_UPDATE_MODE_CHANGED          = 1;
-    private static final int EVENT_SCREEN_STATE_CHANGED         = 2;
-    private static final int EVENT_POWER_SAVE_MODE_CHANGED      = 3;
-    private static final int EVENT_CHARGING_STATE_CHANGED       = 4;
-    private static final int EVENT_TETHERING_STATE_CHANGED      = 5;
-    private static final int EVENT_RADIO_AVAILABLE              = 6;
+    static final int EVENT_RIL_CONNECTED                = 0;
+    static final int EVENT_UPDATE_MODE_CHANGED          = 1;
+    @VisibleForTesting
+    static final int EVENT_SCREEN_STATE_CHANGED         = 2;
+    static final int EVENT_POWER_SAVE_MODE_CHANGED      = 3;
+    @VisibleForTesting
+    static final int EVENT_CHARGING_STATE_CHANGED       = 4;
+    static final int EVENT_TETHERING_STATE_CHANGED      = 5;
+    static final int EVENT_RADIO_AVAILABLE              = 6;
+    @VisibleForTesting
+    static final int EVENT_WIFI_CONNECTION_CHANGED      = 7;
 
     // TODO(b/74006656) load hysteresis values from a property when DeviceStateMonitor starts
     private static final int HYSTERESIS_KBPS = 50;
 
+    private static final int WIFI_UNAVAILABLE = 0;
+    private static final int WIFI_AVAILABLE = 1;
+
     private final Phone mPhone;
 
     private final LocalLog mLocalLog = new LocalLog(100);
 
+    private final NetworkRequest mWifiNetworkRequest =
+            new NetworkRequest.Builder()
+            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+            .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+            .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+            .build();
+
+    private final ConnectivityManager.NetworkCallback mNetworkCallback =
+            new ConnectivityManager.NetworkCallback() {
+        Set<Network> mWifiNetworks = new HashSet<>();
+
+        @Override
+        public void onAvailable(Network network) {
+            synchronized (mWifiNetworks) {
+                if (mWifiNetworks.size() == 0) {
+                    // We just connected to Wifi, so send an update.
+                    obtainMessage(EVENT_WIFI_CONNECTION_CHANGED, WIFI_AVAILABLE, 0).sendToTarget();
+                    log("Wifi (default) connected", true);
+                }
+                mWifiNetworks.add(network);
+            }
+        }
+
+        @Override
+        public void onLost(Network network) {
+            synchronized (mWifiNetworks) {
+                mWifiNetworks.remove(network);
+                if (mWifiNetworks.size() == 0) {
+                    // We just disconnected from the last connected wifi, so send an update.
+                    obtainMessage(
+                            EVENT_WIFI_CONNECTION_CHANGED, WIFI_UNAVAILABLE, 0).sendToTarget();
+                    log("Wifi (default) disconnected", true);
+                }
+            }
+        }
+    };
+
     /**
      * Flag for wifi/usb/bluetooth tethering turned on or not
      */
@@ -105,6 +155,22 @@
      */
     private boolean mIsLowDataExpected;
 
+    /**
+     * Wifi is connected. True means both that cellular is likely to be asleep when the screen is
+     * on and that in most cases the device location is relatively close to the WiFi AP. This means
+     * that fewer location updates should be provided by cellular.
+     */
+    private boolean mIsWifiConnected;
+
+    @VisibleForTesting
+    static final int CELL_INFO_INTERVAL_SHORT_MS = 2000;
+    @VisibleForTesting
+    static final int CELL_INFO_INTERVAL_LONG_MS = 10000;
+
+    /** The minimum required wait time between cell info requests to the modem */
+    private int mCellInfoMinInterval = CELL_INFO_INTERVAL_SHORT_MS;
+
+
     private SparseIntArray mUpdateModes = new SparseIntArray();
 
     /**
@@ -202,6 +268,10 @@
 
         mPhone.mCi.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);
         mPhone.mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
+
+        ConnectivityManager cm = (ConnectivityManager) phone.getContext().getSystemService(
+                Context.CONNECTIVITY_SERVICE);
+        cm.registerNetworkCallback(mWifiNetworkRequest, mNetworkCallback);
     }
 
     /**
@@ -212,6 +282,27 @@
     }
 
     /**
+     * @return The minimum period between CellInfo requests to the modem
+     */
+    @VisibleForTesting
+    public int computeCellInfoMinInterval() {
+        // The screen is on and we're either on cellular or charging. Screen on + Charging is
+        // a likely vehicular scenario, even if there is a nomadic AP.
+        if (mIsScreenOn && !mIsWifiConnected) {
+            // Screen on without WiFi - We are in a high power likely mobile situation.
+            return CELL_INFO_INTERVAL_SHORT_MS;
+        } else if (mIsScreenOn && mIsCharging) {
+            // Screen is on and we're charging, so we favor accuracy over power.
+            return CELL_INFO_INTERVAL_SHORT_MS;
+        } else {
+            // If the screen is off, apps should not need cellular location at rapid intervals.
+            // If the screen is on but we are on wifi and not charging then cellular location
+            // accuracy is not crucial, so favor modem power saving over high accuracy.
+            return CELL_INFO_INTERVAL_LONG_MS;
+        }
+    }
+
+    /**
      * @return True if signal strength update should be turned off.
      */
     private boolean shouldTurnOffSignalStrength() {
@@ -358,6 +449,9 @@
             case EVENT_TETHERING_STATE_CHANGED:
                 onUpdateDeviceState(msg.what, msg.arg1 != 0);
                 break;
+            case EVENT_WIFI_CONNECTION_CHANGED:
+                onUpdateDeviceState(msg.what, msg.arg1 != WIFI_UNAVAILABLE);
+                break;
             default:
                 throw new IllegalStateException("Unexpected message arrives. msg = " + msg.what);
         }
@@ -389,10 +483,22 @@
                 mIsPowerSaveOn = state;
                 sendDeviceState(POWER_SAVE_MODE, mIsPowerSaveOn);
                 break;
+            case EVENT_WIFI_CONNECTION_CHANGED:
+                if (mIsWifiConnected == state) return;
+                mIsWifiConnected = state;
+
+                break;
             default:
                 return;
         }
 
+        final int newCellInfoMinInterval = computeCellInfoMinInterval();
+        if (mCellInfoMinInterval != newCellInfoMinInterval) {
+            mCellInfoMinInterval = newCellInfoMinInterval;
+            setCellInfoMinInterval(mCellInfoMinInterval);
+            log("CellInfo Min Interval Updated to " + newCellInfoMinInterval, true);
+        }
+
         if (mIsLowDataExpected != isLowDataExpected()) {
             mIsLowDataExpected = !mIsLowDataExpected;
             sendDeviceState(LOW_DATA_EXPECTED, mIsLowDataExpected);
@@ -437,6 +543,7 @@
         setUnsolResponseFilter(mUnsolicitedResponseFilter, true);
         setSignalStrengthReportingCriteria();
         setLinkCapacityReportingCriteria();
+        setCellInfoMinInterval(mCellInfoMinInterval);
     }
 
     /**
@@ -501,6 +608,10 @@
                 LINK_CAPACITY_UPLINK_THRESHOLDS, AccessNetworkType.CDMA2000);
     }
 
+    private void setCellInfoMinInterval(int rate) {
+        mPhone.setCellInfoMinInterval(rate);
+    }
+
     /**
      * @return True if the device is currently in power save mode.
      * See {@link android.os.BatteryManager#isPowerSaveMode BatteryManager.isPowerSaveMode()}.
@@ -579,6 +690,7 @@
         ipw.println("mIsPowerSaveOn=" + mIsPowerSaveOn);
         ipw.println("mIsLowDataExpected=" + mIsLowDataExpected);
         ipw.println("mUnsolicitedResponseFilter=" + mUnsolicitedResponseFilter);
+        ipw.println("mIsWifiConnected=" + mIsWifiConnected);
         ipw.println("Local logs:");
         ipw.increaseIndent();
         mLocalLog.dump(fd, ipw, args);
diff --git a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
index ee24974..4b37351 100755
--- a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
@@ -173,7 +173,7 @@
             // Prior to phone switch to GSM, if CDMA has any emergency call
             // data will be in disabled state, after switching to GSM enable data.
             if (mIsInEmergencyCall) {
-                mPhone.mDcTracker.setInternalDataEnabled(true);
+                mPhone.getDataEnabledSettings().setInternalDataEnabled(true);
             }
         } else {
             mConnections = new GsmCdmaConnection[MAX_CONNECTIONS_CDMA];
@@ -330,7 +330,9 @@
             // Always unmute when initiating a new call
             setMute(false);
 
-            mCi.dial(mPendingMO.getAddress(), clirMode, uusInfo, obtainCompleteMessage());
+            mCi.dial(mPendingMO.getAddress(), mPendingMO.isEmergencyCall(),
+                    mPendingMO.getEmergencyServiceCategories(), clirMode, uusInfo,
+                    obtainCompleteMessage());
         }
 
         if (mNumberConverted) {
@@ -372,7 +374,7 @@
     //CDMA
     public void setIsInEmergencyCall() {
         mIsInEmergencyCall = true;
-        mPhone.mDcTracker.setInternalDataEnabled(false);
+        mPhone.getDataEnabledSettings().setInternalDataEnabled(false);
         mPhone.notifyEmergencyCallRegistrants(true);
         mPhone.sendEmergencyCallStateChange(true);
     }
@@ -445,7 +447,9 @@
 
             // In Ecm mode, if another emergency call is dialed, Ecm mode will not exit.
             if(!isPhoneInEcmMode || (isPhoneInEcmMode && isEmergencyCall)) {
-                mCi.dial(mPendingMO.getAddress(), clirMode, obtainCompleteMessage());
+                mCi.dial(mPendingMO.getAddress(), mPendingMO.isEmergencyCall(),
+                        mPendingMO.getEmergencyServiceCategories(), clirMode,
+                        obtainCompleteMessage());
             } else {
                 mPhone.exitEmergencyCallbackMode();
                 mPhone.setOnEcbModeExitResponse(this,EVENT_EXIT_ECM_RESPONSE_CDMA, null);
@@ -1529,7 +1533,9 @@
                 if (!isPhoneTypeGsm()) {
                     // no matter the result, we still do the same here
                     if (mPendingCallInEcm) {
-                        mCi.dial(mPendingMO.getAddress(), mPendingCallClirMode, obtainCompleteMessage());
+                        mCi.dial(mPendingMO.getAddress(), mPendingMO.isEmergencyCall(),
+                                mPendingMO.getEmergencyServiceCategories(), mPendingCallClirMode,
+                                obtainCompleteMessage());
                         mPendingCallInEcm = false;
                     }
                     mPhone.unsetOnEcbModeExitResponse(this);
@@ -1628,7 +1634,7 @@
             }
             if (!inEcm) {
                 // Re-initiate data connection
-                mPhone.mDcTracker.setInternalDataEnabled(true);
+                mPhone.getDataEnabledSettings().setInternalDataEnabled(true);
                 mPhone.notifyEmergencyCallRegistrants(false);
             }
             mPhone.sendEmergencyCallStateChange(false);
diff --git a/src/java/com/android/internal/telephony/GsmCdmaConnection.java b/src/java/com/android/internal/telephony/GsmCdmaConnection.java
index 32587ec..64fd2f7 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaConnection.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaConnection.java
@@ -29,13 +29,21 @@
 import android.telephony.PhoneNumberUtils;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
+import android.telephony.emergency.EmergencyNumber;
+import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories;
 import android.text.TextUtils;
 
 import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
+import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
 import com.android.internal.telephony.uicc.UiccCardApplication;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 /**
  * {@hide}
  */
@@ -72,11 +80,14 @@
 
     private PowerManager.WakeLock mPartialWakeLock;
 
-    private boolean mIsEmergencyCall = false;
-
     // The cached delay to be used between DTMF tones fetched from carrier config.
     private int mDtmfToneDelay = 0;
 
+    // Store the current audio codec
+    private int mAudioCodec = DriverCall.AUDIO_QUALITY_UNSPECIFIED;
+
+    private TelephonyMetrics mMetrics = TelephonyMetrics.getInstance();
+
     //***** Event Constants
     static final int EVENT_DTMF_DONE = 1;
     static final int EVENT_PAUSE_DONE = 2;
@@ -129,7 +140,9 @@
         mHandler = new MyHandler(mOwner.getLooper());
 
         mAddress = dc.number;
-        mIsEmergencyCall = PhoneNumberUtils.isLocalEmergencyNumber(phone.getContext(), mAddress);
+        setEmergencyCall(TelephonyManager.getDefault().isCurrentEmergencyNumber(mAddress));
+        setEmergencyServiceCategories(fetchEmergencyServiceCategories());
+
         mIsIncoming = dc.isMT;
         mCreateTime = System.currentTimeMillis();
         mCnapName = dc.name;
@@ -170,7 +183,9 @@
         }
 
         mAddress = PhoneNumberUtils.extractNetworkPortionAlt(dialString);
-        mIsEmergencyCall = isEmergencyCall;
+        setEmergencyCall(isEmergencyCall);
+        setEmergencyServiceCategories(fetchEmergencyServiceCategories());
+
         mPostDialString = PhoneNumberUtils.extractPostDialPortion(dialString);
 
         mIndex = -1;
@@ -522,6 +537,7 @@
             case CallFailCause.USER_ALERTING_NO_ANSWER:
                 return DisconnectCause.TIMED_OUT;
 
+            case CallFailCause.ACCESS_CLASS_BLOCKED:
             case CallFailCause.ERROR_UNSPECIFIED:
             case CallFailCause.NORMAL_CLEARING:
             default:
@@ -533,7 +549,7 @@
                 if (serviceState == ServiceState.STATE_POWER_OFF) {
                     return DisconnectCause.POWER_OFF;
                 }
-                if (!mIsEmergencyCall) {
+                if (!isEmergencyCall()) {
                     // Only send OUT_OF_SERVICE if it is not an emergency call. We can still
                     // technically be in STATE_OUT_OF_SERVICE or STATE_EMERGENCY_ONLY during
                     // an emergency call and when it ends, we do not want to mistakenly generate
@@ -556,7 +572,8 @@
                     }
                 }
                 if (isPhoneTypeGsm()) {
-                    if (causeCode == CallFailCause.ERROR_UNSPECIFIED) {
+                    if (causeCode == CallFailCause.ERROR_UNSPECIFIED ||
+                                   causeCode == CallFailCause.ACCESS_CLASS_BLOCKED ) {
                         if (phone.mSST.mRestrictedState.isCsRestricted()) {
                             return DisconnectCause.CS_RESTRICTED;
                         } else if (phone.mSST.mRestrictedState.isCsEmergencyRestricted()) {
@@ -661,6 +678,12 @@
             changed = true;
         }
 
+        // Metrics for audio codec
+        if (dc.audioQuality != mAudioCodec) {
+            mAudioCodec = dc.audioQuality;
+            mMetrics.writeAudioCodecGsmCdma(mOwner.getPhone().getPhoneId(), dc.audioQuality);
+        }
+
         // A null cnapName should be the same as ""
         if (TextUtils.isEmpty(dc.name)) {
             if (!TextUtils.isEmpty(mCnapName)) {
@@ -1108,6 +1131,31 @@
         }
     }
 
+    private @EmergencyServiceCategories int fetchEmergencyServiceCategories() {
+        Map<Integer, List<EmergencyNumber>> emergencyNumberListInternal = new HashMap<>();
+        for (Phone phone: PhoneFactory.getPhones()) {
+            if (phone.getEmergencyNumberTracker() != null
+                    && phone.getEmergencyNumberTracker().getEmergencyNumberList() != null) {
+                emergencyNumberListInternal.put(
+                        phone.getSubId(),
+                        phone.getEmergencyNumberTracker().getEmergencyNumberList());
+            }
+        }
+        if (emergencyNumberListInternal != null) {
+            for (List<EmergencyNumber> emergencyNumberList
+                    : emergencyNumberListInternal.values()) {
+                if (emergencyNumberList != null) {
+                    for (EmergencyNumber num : emergencyNumberList) {
+                        if (num.getNumber().equals(mAddress)) {
+                            return num.getEmergencyServiceCategoryBitmask();
+                        }
+                    }
+                }
+            }
+        }
+        return EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED;
+    }
+
     private boolean isPhoneTypeGsm() {
         return mOwner.getPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_GSM;
     }
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 29d4b35..d4cbbaa 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -55,6 +55,7 @@
 import android.provider.Settings;
 import android.provider.Telephony;
 import android.telecom.VideoProfile;
+import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.CarrierConfigManager;
 import android.telephony.CellLocation;
 import android.telephony.ImsiEncryptionInfo;
@@ -66,6 +67,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.UssdResponse;
+import android.telephony.data.ApnSetting;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
@@ -75,7 +77,10 @@
 import com.android.internal.telephony.cdma.CdmaMmiCode;
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
 import com.android.internal.telephony.cdma.EriManager;
+import com.android.internal.telephony.dataconnection.DataEnabledSettings;
+import com.android.internal.telephony.dataconnection.DcTracker;
 import com.android.internal.telephony.dataconnection.TransportManager;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.gsm.GsmMmiCode;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
 import com.android.internal.telephony.test.SimulatedRadioControl;
@@ -167,6 +172,7 @@
     private IsimUiccRecords mIsimUiccRecords;
     public GsmCdmaCallTracker mCT;
     public ServiceStateTracker mSST;
+    public EmergencyNumberTracker mEmergencyNumberTracker;
     private ArrayList <MmiCode> mPendingMMIs = new ArrayList<MmiCode>();
     private IccPhoneBookInterfaceManager mIccPhoneBookIntManager;
     // Used for identify the carrier of current subscription
@@ -203,6 +209,8 @@
     private CarrierKeyDownloadManager mCDM;
     private CarrierInfoManager mCIM;
 
+    private final SettingsObserver mSettingsObserver;
+
     // Constructors
 
     public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId,
@@ -222,18 +230,46 @@
         initRatSpecific(precisePhoneType);
         // CarrierSignalAgent uses CarrierActionAgent in construction so it needs to be created
         // after CarrierActionAgent.
-        mCarrierActionAgent = mTelephonyComponentFactory.makeCarrierActionAgent(this);
-        mCarrierSignalAgent = mTelephonyComponentFactory.makeCarrierSignalAgent(this);
-        mTransportManager = mTelephonyComponentFactory.makeTransportManager(this);
-        mSST = mTelephonyComponentFactory.makeServiceStateTracker(this, this.mCi);
+        mCarrierActionAgent = mTelephonyComponentFactory.inject(CarrierActionAgent.class.getName())
+                .makeCarrierActionAgent(this);
+        mCarrierSignalAgent = mTelephonyComponentFactory.inject(CarrierSignalAgent.class.getName())
+                .makeCarrierSignalAgent(this);
+        mTransportManager = mTelephonyComponentFactory.inject(TransportManager.class.getName())
+                .makeTransportManager(this);
+        mSST = mTelephonyComponentFactory.inject(ServiceStateTracker.class.getName())
+                .makeServiceStateTracker(this, this.mCi);
+        mEmergencyNumberTracker = mTelephonyComponentFactory
+                .inject(EmergencyNumberTracker.class.getName()).makeEmergencyNumberTracker(
+                this, this.mCi);
+        mDataEnabledSettings = mTelephonyComponentFactory
+                .inject(DataEnabledSettings.class.getName()).makeDataEnabledSettings(this);
+
         // DcTracker uses SST so needs to be created after it is instantiated
-        mDcTracker = mTelephonyComponentFactory.makeDcTracker(this);
-        mCarrierResolver = mTelephonyComponentFactory.makeCarrierResolver(this);
+        for (int transport : mTransportManager.getAvailableTransports()) {
+            mDcTrackers.put(transport, mTelephonyComponentFactory.inject(DcTracker.class.getName())
+                    .makeDcTracker(this, transport));
+        }
+
+        mCarrierResolver = mTelephonyComponentFactory.inject(CarrierResolver.class.getName())
+                .makeCarrierResolver(this);
+
+        getCarrierActionAgent().registerForCarrierAction(
+                CarrierActionAgent.CARRIER_ACTION_SET_METERED_APNS_ENABLED, this,
+                EVENT_SET_CARRIER_DATA_ENABLED, null, false);
 
         mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
-        mDeviceStateMonitor = mTelephonyComponentFactory.makeDeviceStateMonitor(this);
+        mDeviceStateMonitor = mTelephonyComponentFactory.inject(DeviceStateMonitor.class.getName())
+                .makeDeviceStateMonitor(this);
 
         mSST.registerForVoiceRegStateOrRatChanged(this, EVENT_VRS_OR_RAT_CHANGED, null);
+
+        mSettingsObserver = new SettingsObserver(context, this);
+        mSettingsObserver.observe(
+                Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
+                EVENT_DEVICE_PROVISIONED_CHANGE);
+        mSettingsObserver.observe(
+                Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED),
+                EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE);
         logd("GsmCdmaPhone: constructor: sub = " + mPhoneId);
     }
 
@@ -252,12 +288,17 @@
             mSimulatedRadioControl = (SimulatedRadioControl) ci;
         }
 
-        mCT = mTelephonyComponentFactory.makeGsmCdmaCallTracker(this);
-        mIccPhoneBookIntManager = mTelephonyComponentFactory.makeIccPhoneBookInterfaceManager(this);
+        mCT = mTelephonyComponentFactory.inject(GsmCdmaCallTracker.class.getName())
+                .makeGsmCdmaCallTracker(this);
+        mIccPhoneBookIntManager = mTelephonyComponentFactory
+                .inject(IccPhoneBookInterfaceManager.class.getName())
+                .makeIccPhoneBookInterfaceManager(this);
         PowerManager pm
                 = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
-        mIccSmsInterfaceManager = mTelephonyComponentFactory.makeIccSmsInterfaceManager(this);
+        mIccSmsInterfaceManager = mTelephonyComponentFactory
+                .inject(IccSmsInterfaceManager.class.getName())
+                .makeIccSmsInterfaceManager(this);
 
         mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
         mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
@@ -270,10 +311,11 @@
         mCi.setOnSs(this, EVENT_SS, null);
 
         //CDMA
-        mCdmaSSM = mTelephonyComponentFactory.getCdmaSubscriptionSourceManagerInstance(mContext,
+        mCdmaSSM = mTelephonyComponentFactory.inject(CdmaSubscriptionSourceManager.class.getName())
+                .getCdmaSubscriptionSourceManagerInstance(mContext,
                 mCi, this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
-        mEriManager = mTelephonyComponentFactory.makeEriManager(this, mContext,
-                EriManager.ERI_FROM_XML);
+        mEriManager = mTelephonyComponentFactory.inject(EriManager.class.getName())
+                .makeEriManager(this, mContext, EriManager.ERI_FROM_XML);
         mCi.setEmergencyCallbackMode(this, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null);
         mCi.registerForExitEmergencyCallbackMode(this, EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE,
                 null);
@@ -363,6 +405,7 @@
         if (TextUtils.isEmpty(operatorNumeric)) {
             logd("setIsoCountryProperty: clear 'gsm.sim.operator.iso-country'");
             tm.setSimCountryIsoForPhone(mPhoneId, "");
+            SubscriptionController.getInstance().setCountryIso("", getSubId());
         } else {
             String iso = "";
             try {
@@ -373,6 +416,7 @@
 
             logd("setIsoCountryProperty: set 'gsm.sim.operator.iso-country' to iso=" + iso);
             tm.setSimCountryIsoForPhone(mPhoneId, iso);
+            SubscriptionController.getInstance().setCountryIso(iso, getSubId());
         }
     }
 
@@ -468,6 +512,11 @@
     }
 
     @Override
+    public EmergencyNumberTracker getEmergencyNumberTracker() {
+        return mEmergencyNumberTracker;
+    }
+
+    @Override
     public CallTracker getCallTracker() {
         return mCT;
     }
@@ -523,21 +572,25 @@
 
             ret = PhoneConstants.DataState.DISCONNECTED;
         } else { /* mSST.gprsState == ServiceState.STATE_IN_SERVICE */
-            switch (mDcTracker.getState(apnType)) {
-                case CONNECTED:
-                case DISCONNECTING:
-                    if ( mCT.mState != PhoneConstants.State.IDLE
-                            && !mSST.isConcurrentVoiceAndDataAllowed()) {
-                        ret = PhoneConstants.DataState.SUSPENDED;
-                    } else {
-                        ret = PhoneConstants.DataState.CONNECTED;
-                    }
-                    break;
-                case CONNECTING:
-                    ret = PhoneConstants.DataState.CONNECTING;
-                    break;
-                default:
-                    ret = PhoneConstants.DataState.DISCONNECTED;
+            int currentTransport = mTransportManager.getCurrentTransport(
+                    ApnSetting.getApnTypesBitmaskFromString(apnType));
+            if (getDcTracker(currentTransport) != null) {
+                switch (getDcTracker(currentTransport).getState(apnType)) {
+                    case CONNECTED:
+                    case DISCONNECTING:
+                        if (mCT.mState != PhoneConstants.State.IDLE
+                                && !mSST.isConcurrentVoiceAndDataAllowed()) {
+                            ret = PhoneConstants.DataState.SUSPENDED;
+                        } else {
+                            ret = PhoneConstants.DataState.CONNECTED;
+                        }
+                        break;
+                    case CONNECTING:
+                        ret = PhoneConstants.DataState.CONNECTING;
+                        break;
+                    default:
+                        ret = PhoneConstants.DataState.DISCONNECTED;
+                }
             }
         }
 
@@ -549,8 +602,9 @@
     public DataActivityState getDataActivityState() {
         DataActivityState ret = DataActivityState.NONE;
 
-        if (mSST.getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE) {
-            switch (mDcTracker.getActivity()) {
+        if (mSST.getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE
+                && getDcTracker(TransportType.WWAN) != null) {
+            switch (getDcTracker(TransportType.WWAN).getActivity()) {
                 case DATAIN:
                     ret = DataActivityState.DATAIN;
                 break;
@@ -1427,7 +1481,7 @@
             }
         }
 
-        if (!isPhoneTypeGsm() && TextUtils.isEmpty(number)) {
+        if (TextUtils.isEmpty(number)) {
             // Read platform settings for dynamic voicemail number
             CarrierConfigManager configManager = (CarrierConfigManager)
                     getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
@@ -1435,8 +1489,6 @@
             if (b != null && b.getBoolean(
                     CarrierConfigManager.KEY_CONFIG_TELEPHONY_USE_OWN_NUMBER_FOR_VOICEMAIL_BOOL)) {
                 number = getLine1Number();
-            } else {
-                number = "*86";
             }
         }
 
@@ -1856,9 +1908,7 @@
             int serviceClass) {
         if (isPhoneTypeGsm()) {
             Phone imsPhone = mImsPhone;
-            if ((imsPhone != null)
-                    && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
-                    || imsPhone.isUtEnabled())) {
+            if ((imsPhone != null) && imsPhone.isUtEnabled()) {
                 imsPhone.getCallBarring(facility, password, onComplete, serviceClass);
                 return;
             }
@@ -1873,9 +1923,7 @@
             Message onComplete, int serviceClass) {
         if (isPhoneTypeGsm()) {
             Phone imsPhone = mImsPhone;
-            if ((imsPhone != null)
-                    && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
-                    || imsPhone.isUtEnabled())) {
+            if ((imsPhone != null) && imsPhone.isUtEnabled()) {
                 imsPhone.setCallBarring(facility, lockState, password, onComplete, serviceClass);
                 return;
             }
@@ -2036,12 +2084,17 @@
 
     @Override
     public boolean getDataRoamingEnabled() {
-        return mDcTracker.getDataRoamingEnabled();
+        if (getDcTracker(TransportType.WWAN) != null) {
+            return getDcTracker(TransportType.WWAN).getDataRoamingEnabled();
+        }
+        return false;
     }
 
     @Override
     public void setDataRoamingEnabled(boolean enable) {
-        mDcTracker.setDataRoamingEnabledByUser(enable);
+        if (getDcTracker(TransportType.WWAN) != null) {
+            getDcTracker(TransportType.WWAN).setDataRoamingEnabledByUser(enable);
+        }
     }
 
     @Override
@@ -2084,19 +2137,18 @@
         mCT.unregisterForCallWaiting(h);
     }
 
+    /**
+     * Whether data is enabled by user. Unlike isDataEnabled, this only
+     * checks user setting stored in {@link android.provider.Settings.Global#MOBILE_DATA}
+     * if not provisioning, or isProvisioningDataEnabled if provisioning.
+     */
     @Override
     public boolean isUserDataEnabled() {
-        return mDcTracker.isUserDataEnabled();
-    }
-
-    @Override
-    public boolean isDataEnabled() {
-        return mDcTracker.isDataEnabled();
-    }
-
-    @Override
-    public void setUserDataEnabled(boolean enable) {
-        mDcTracker.setUserDataEnabled(enable);
+        if (mDataEnabledSettings.isProvisioning()) {
+            return mDataEnabledSettings.isProvisioningDataEnabled();
+        } else {
+            return mDataEnabledSettings.isUserDataEnabled();
+        }
     }
 
     /**
@@ -2624,6 +2676,17 @@
                 onVoiceRegStateOrRatChanged(vrsRatPair.first, vrsRatPair.second);
                 break;
 
+            case EVENT_SET_CARRIER_DATA_ENABLED:
+                ar = (AsyncResult) msg.obj;
+                boolean enabled = (boolean) ar.result;
+                mDataEnabledSettings.setCarrierDataEnabled(enabled);
+                break;
+            case EVENT_DEVICE_PROVISIONED_CHANGE:
+                mDataEnabledSettings.updateProvisionedChanged();
+                break;
+            case EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE:
+                mDataEnabledSettings.updateProvisioningDataEnabled();
+                break;
             default:
                 super.handleMessage(msg);
         }
@@ -3065,7 +3128,7 @@
             // send an Intent
             sendEmergencyCallbackModeChange();
             // Re-initiate data connection
-            mDcTracker.setInternalDataEnabled(true);
+            mDataEnabledSettings.setInternalDataEnabled(true);
             notifyEmergencyCallRegistrants(false);
         }
     }
diff --git a/src/java/com/android/internal/telephony/IccCard.java b/src/java/com/android/internal/telephony/IccCard.java
index 7bab408..75f3377 100644
--- a/src/java/com/android/internal/telephony/IccCard.java
+++ b/src/java/com/android/internal/telephony/IccCard.java
@@ -275,6 +275,14 @@
         return false;
     }
 
+    /**
+     * @return whether the card is an empty profile, meaning there's no UiccCardApplication,
+     * and that we don't need to wait for LOADED state.
+     */
+    public boolean isEmptyProfile() {
+        return false;
+    }
+
     private void sendMessageWithCardAbsentException(Message onComplete) {
         AsyncResult ret = AsyncResult.forMessage(onComplete);
         ret.exception = new RuntimeException("No valid IccCard");
diff --git a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
index 70db301..2033d4a 100644
--- a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
+++ b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
@@ -179,7 +179,7 @@
                 int mappedResult;
                 switch (result) {
                     case Intents.RESULT_SMS_HANDLED:
-                        mappedResult = ImsSmsImplBase.STATUS_REPORT_STATUS_OK;
+                        mappedResult = ImsSmsImplBase.DELIVER_STATUS_OK;
                         break;
                     case Intents.RESULT_SMS_OUT_OF_MEMORY:
                         mappedResult = ImsSmsImplBase.DELIVER_STATUS_ERROR_NO_MEMORY;
@@ -199,11 +199,13 @@
                         Rlog.w(TAG, "SMS Received with a PDU that could not be parsed.");
                         getImsManager().acknowledgeSms(token, 0, mappedResult);
                     }
+                    mMetrics.writeImsServiceNewSms(mPhone.getPhoneId(), format, mappedResult);
                 } catch (ImsException e) {
                     Rlog.e(TAG, "Failed to acknowledgeSms(). Error: " + e.getMessage());
+                    mMetrics.writeImsServiceNewSms(mPhone.getPhoneId(), format,
+                            ImsSmsImplBase.DELIVER_STATUS_ERROR_GENERIC);
                 }
             }, true);
-            mMetrics.writeImsServiceNewSms(mPhone.getPhoneId(), format);
         }
     };
 
@@ -366,10 +368,13 @@
                     smsc != null ? new String(smsc) : null,
                     isRetry,
                     pdu);
-            mMetrics.writeImsServiceSendSms(mPhone.getPhoneId(), format);
+            mMetrics.writeImsServiceSendSms(mPhone.getPhoneId(), format,
+                    ImsSmsImplBase.SEND_STATUS_OK);
         } catch (ImsException e) {
             Rlog.e(TAG, "sendSms failed. Falling back to PSTN. Error: " + e.getMessage());
             fallbackToPstn(token, tracker);
+            mMetrics.writeImsServiceSendSms(mPhone.getPhoneId(), format,
+                    ImsSmsImplBase.SEND_STATUS_ERROR_FALLBACK);
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java
index a115dba..5124748 100644
--- a/src/java/com/android/internal/telephony/InboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java
@@ -259,7 +259,8 @@
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
         mWakeLock.acquire();    // wake lock released after we enter idle state
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        mDeviceIdleController = TelephonyComponentFactory.getInstance().getIDeviceIdleController();
+        mDeviceIdleController = TelephonyComponentFactory.getInstance()
+                .inject(IDeviceIdleController.class.getName()).getIDeviceIdleController();
 
         addState(mDefaultState);
         addState(mStartupState, mDefaultState);
@@ -719,8 +720,9 @@
                 destPort = smsHeader.portAddrs.destPort;
                 if (DBG) log("destination port: " + destPort);
             }
-
-            tracker = TelephonyComponentFactory.getInstance().makeInboundSmsTracker(sms.getPdu(),
+            tracker = TelephonyComponentFactory.getInstance()
+                    .inject(InboundSmsTracker.class.getName())
+                    .makeInboundSmsTracker(sms.getPdu(),
                     sms.getTimestampMillis(), destPort, is3gpp2(), false,
                     sms.getOriginatingAddress(), sms.getDisplayOriginatingAddress(),
                     sms.getMessageBody());
@@ -729,8 +731,9 @@
             SmsHeader.ConcatRef concatRef = smsHeader.concatRef;
             SmsHeader.PortAddrs portAddrs = smsHeader.portAddrs;
             int destPort = (portAddrs != null ? portAddrs.destPort : -1);
-
-            tracker = TelephonyComponentFactory.getInstance().makeInboundSmsTracker(sms.getPdu(),
+            tracker = TelephonyComponentFactory.getInstance()
+                    .inject(InboundSmsTracker.class.getName())
+                    .makeInboundSmsTracker(sms.getPdu(),
                     sms.getTimestampMillis(), destPort, is3gpp2(), sms.getOriginatingAddress(),
                     sms.getDisplayOriginatingAddress(), concatRef.refNumber, concatRef.seqNumber,
                     concatRef.msgCount, false, sms.getMessageBody());
diff --git a/src/java/com/android/internal/telephony/LocaleTracker.java b/src/java/com/android/internal/telephony/LocaleTracker.java
index d582762..9236839 100755
--- a/src/java/com/android/internal/telephony/LocaleTracker.java
+++ b/src/java/com/android/internal/telephony/LocaleTracker.java
@@ -100,7 +100,7 @@
 
     /** Current cell tower information */
     @Nullable
-    private List<CellInfo> mCellInfo;
+    private List<CellInfo> mCellInfoList;
 
     /** Count of invalid cell info we've got so far. Will reset once we get a successful one */
     private int mFailCellInfoCount;
@@ -146,14 +146,14 @@
             case EVENT_UNSOL_CELL_INFO:
                 processCellInfo((AsyncResult) msg.obj);
                 // If the unsol happened to be useful, use it; otherwise, pretend it didn't happen.
-                if (mCellInfo != null && mCellInfo.size() > 0) requestNextCellInfo(true);
+                if (mCellInfoList != null && mCellInfoList.size() > 0) requestNextCellInfo(true);
                 break;
 
             case EVENT_RESPONSE_CELL_INFO:
                 processCellInfo((AsyncResult) msg.obj);
                 // If the cellInfo was non-empty then it's business as usual. Either way, this
                 // cell info was requested by us, so it's our trigger to schedule another one.
-                requestNextCellInfo(mCellInfo != null && mCellInfo.size() > 0);
+                requestNextCellInfo(mCellInfoList != null && mCellInfoList.size() > 0);
                 break;
 
             case EVENT_SERVICE_STATE_CHANGED:
@@ -209,10 +209,10 @@
     @Nullable
     private String getMccFromCellInfo() {
         String selectedMcc = null;
-        if (mCellInfo != null) {
+        if (mCellInfoList != null) {
             Map<String, Integer> countryCodeMap = new HashMap<>();
             int maxCount = 0;
-            for (CellInfo cellInfo : mCellInfo) {
+            for (CellInfo cellInfo : mCellInfoList) {
                 String mcc = null;
                 if (cellInfo instanceof CellInfoGsm) {
                     mcc = ((CellInfoGsm) cellInfo).getCellIdentity().getMccString();
@@ -281,13 +281,28 @@
 
     private void processCellInfo(AsyncResult ar) {
         if (ar == null || ar.exception != null) {
-            mCellInfo = null;
+            mCellInfoList = null;
             return;
         }
-        mCellInfo = (List<CellInfo>) ar.result;
-        String msg = "getCellInfo: cell info=" + mCellInfo;
+        List<CellInfo> cellInfoList = (List<CellInfo>) ar.result;
+        String msg = "getCellInfo: cell info=" + cellInfoList;
         if (DBG) log(msg);
-        mLocalLog.log(msg);
+        if (cellInfoList != null) {
+            // We only log when cell identity changes, otherwise the local log is flooded with cell
+            // info.
+            if (mCellInfoList == null || cellInfoList.size() != mCellInfoList.size()) {
+                mLocalLog.log(msg);
+            } else {
+                for (int i = 0; i < cellInfoList.size(); i++) {
+                    if (!Objects.equals(mCellInfoList.get(i).getCellIdentity(),
+                            cellInfoList.get(i).getCellIdentity())) {
+                        mLocalLog.log(msg);
+                        break;
+                    }
+                }
+            }
+        }
+        mCellInfoList = cellInfoList;
         updateLocale();
     }
 
@@ -355,7 +370,7 @@
         String msg = "Stopping LocaleTracker";
         if (DBG) log(msg);
         mLocalLog.log(msg);
-        mCellInfo = null;
+        mCellInfoList = null;
         resetCellInfoRetry();
     }
 
@@ -392,16 +407,25 @@
             countryIso = MccTable.countryCodeForMcc(mcc);
         }
 
-        String msg = "updateLocale: mcc = " + mcc + ", country = " + countryIso;
-        log(msg);
-        mLocalLog.log(msg);
+        log("updateLocale: mcc = " + mcc + ", country = " + countryIso);
         boolean countryChanged = false;
         if (!Objects.equals(countryIso, mCurrentCountryIso)) {
-            msg = "updateLocale: Change the current country to " + countryIso;
+            String msg = "updateLocale: Change the current country to \"" + countryIso
+                    + "\", mcc = " + mcc;
             log(msg);
             mLocalLog.log(msg);
             mCurrentCountryIso = countryIso;
 
+            // Inform EmergencyNumberTrack with the change of current Country ISO
+            if (mPhone != null && mPhone.getEmergencyNumberTracker() != null) {
+                mPhone.getEmergencyNumberTracker().updateEmergencyNumberDatabaseCountryChange(
+                        getCurrentCountry());
+                log("Notified EmergencyNumberTracker");
+            } else {
+                loge("Cannot notify EmergencyNumberTracker. Phone is null? "
+                        + Boolean.toString(mPhone == null));
+            }
+
             TelephonyManager.setTelephonyProperty(mPhone.getPhoneId(),
                     TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, mCurrentCountryIso);
 
@@ -447,7 +471,7 @@
         ipw.println("mIsTracking = " + mIsTracking);
         ipw.println("mOperatorNumeric = " + mOperatorNumeric);
         ipw.println("mSimState = " + mSimState);
-        ipw.println("mCellInfo = " + mCellInfo);
+        ipw.println("mCellInfoList = " + mCellInfoList);
         ipw.println("mCurrentCountryIso = " + mCurrentCountryIso);
         ipw.println("mFailCellInfoCount = " + mFailCellInfoCount);
         ipw.println("Local logs:");
diff --git a/src/java/com/android/internal/telephony/NetworkRegistrationManager.java b/src/java/com/android/internal/telephony/NetworkRegistrationManager.java
index ae7ede0..04d09a5 100644
--- a/src/java/com/android/internal/telephony/NetworkRegistrationManager.java
+++ b/src/java/com/android/internal/telephony/NetworkRegistrationManager.java
@@ -127,7 +127,8 @@
     private class NetworkServiceConnection implements ServiceConnection {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
-            logd("service connected.");
+            logd("service " + name + " for transport "
+                    + TransportType.toString(mTransportType) + " is now connected.");
             mServiceBinder = (INetworkService.Stub) service;
             mDeathRecipient = new RegManagerDeathRecipient(name);
             try {
@@ -144,7 +145,8 @@
 
         @Override
         public void onServiceDisconnected(ComponentName name) {
-            logd("onServiceDisconnected " + name);
+            logd("service " + name + " for transport "
+                    + TransportType.toString(mTransportType) + " is now disconnected.");
             if (mServiceBinder != null) {
                 mServiceBinder.unlinkToDeath(mDeathRecipient, 0);
             }
@@ -180,6 +182,8 @@
         try {
             // We bind this as a foreground service because it is operating directly on the SIM,
             // and we do not want it subjected to power-savings restrictions while doing so.
+            logd("Trying to bind " + getPackageName() + " for transport "
+                    + TransportType.toString(mTransportType));
             return mPhone.getContext().bindService(intent, new NetworkServiceConnection(),
                     Context.BIND_AUTO_CREATE);
         } catch (SecurityException e) {
@@ -219,9 +223,6 @@
             packageName = b.getString(carrierConfig, packageName);
         }
 
-        logd("Binding to packageName " + packageName + " for transport type"
-                + mTransportType);
-
         return packageName;
     }
 
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index a968c56..9ca77b4 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.telephony;
 
+import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -40,10 +41,12 @@
 import android.provider.Settings;
 import android.service.carrier.CarrierIdentifier;
 import android.telecom.VideoProfile;
+import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.CarrierConfigManager;
 import android.telephony.CellInfo;
 import android.telephony.CellLocation;
 import android.telephony.ClientRequestStats;
+import android.telephony.DataFailCause;
 import android.telephony.ImsiEncryptionInfo;
 import android.telephony.PhoneStateListener;
 import android.telephony.PhysicalChannelConfig;
@@ -53,16 +56,22 @@
 import android.telephony.SignalStrength;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
+import android.telephony.data.ApnSetting.ApnType;
+import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.text.TextUtils;
+import android.util.SparseArray;
 
 import com.android.ims.ImsCall;
 import com.android.ims.ImsConfig;
 import com.android.ims.ImsManager;
 import com.android.internal.R;
 import com.android.internal.telephony.dataconnection.DataConnectionReasons;
+import com.android.internal.telephony.dataconnection.DataEnabledSettings;
 import com.android.internal.telephony.dataconnection.DcTracker;
 import com.android.internal.telephony.dataconnection.TransportManager;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.imsphone.ImsPhoneCall;
 import com.android.internal.telephony.test.SimulatedRadioControl;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
@@ -77,6 +86,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
@@ -160,6 +170,7 @@
     protected static final int EVENT_GET_CALL_FORWARD_DONE       = 13;
     protected static final int EVENT_CALL_RING                   = 14;
     private static final int EVENT_CALL_RING_CONTINUE            = 15;
+    private static final int EVENT_ALL_DATA_DISCONNECTED         = 16;
 
     // Used to intercept the carrier selection calls so that
     // we can save the values.
@@ -200,8 +211,11 @@
     protected static final int EVENT_VRS_OR_RAT_CHANGED             = 46;
     // Radio state change
     protected static final int EVENT_RADIO_STATE_CHANGED            = 47;
+    protected static final int EVENT_SET_CARRIER_DATA_ENABLED       = 48;
+    protected static final int EVENT_DEVICE_PROVISIONED_CHANGE      = 49;
+    protected static final int EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE = 50;
 
-    protected static final int EVENT_LAST                       = EVENT_RADIO_STATE_CHANGED;
+    protected static final int EVENT_LAST = EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE;
 
     // For shared prefs.
     private static final String GSM_ROAMING_LIST_OVERRIDE_PREFIX = "gsm_roaming_list_";
@@ -251,7 +265,11 @@
     public CommandsInterface mCi;
     protected int mVmCount = 0;
     private boolean mDnsCheckDisabled;
-    public DcTracker mDcTracker;
+    // Data connection trackers. For each transport type (e.g. WWAN, WLAN), there will be a
+    // corresponding DcTracker. The WWAN DcTracker is for cellular data connections while
+    // WLAN DcTracker is for IWLAN data connection. For IWLAN legacy mode, only one (WWAN) DcTracker
+    // will be created.
+    protected final SparseArray<DcTracker> mDcTrackers = new SparseArray<>();
     /* Used for dispatching signals to configured carrier apps */
     protected CarrierSignalAgent mCarrierSignalAgent;
     /* Used for dispatching carrier action from carrier apps */
@@ -281,6 +299,7 @@
     private final String mActionAttached;
     protected DeviceStateMonitor mDeviceStateMonitor;
     protected TransportManager mTransportManager;
+    protected DataEnabledSettings mDataEnabledSettings;
 
     protected int mPhoneId;
 
@@ -307,47 +326,35 @@
     public static final String EXTRA_KEY_ALERT_SHOW = "alertShow";
     public static final String EXTRA_KEY_NOTIFICATION_MESSAGE = "notificationMessage";
 
-    private final RegistrantList mPreciseCallStateRegistrants
-            = new RegistrantList();
+    private final RegistrantList mPreciseCallStateRegistrants = new RegistrantList();
 
-    private final RegistrantList mHandoverRegistrants
-            = new RegistrantList();
+    private final RegistrantList mHandoverRegistrants = new RegistrantList();
 
-    private final RegistrantList mNewRingingConnectionRegistrants
-            = new RegistrantList();
+    private final RegistrantList mNewRingingConnectionRegistrants = new RegistrantList();
 
-    private final RegistrantList mIncomingRingRegistrants
-            = new RegistrantList();
+    private final RegistrantList mIncomingRingRegistrants = new RegistrantList();
 
-    protected final RegistrantList mDisconnectRegistrants
-            = new RegistrantList();
+    protected final RegistrantList mDisconnectRegistrants = new RegistrantList();
 
-    private final RegistrantList mServiceStateRegistrants
-            = new RegistrantList();
+    private final RegistrantList mServiceStateRegistrants = new RegistrantList();
 
-    protected final RegistrantList mMmiCompleteRegistrants
-            = new RegistrantList();
+    protected final RegistrantList mMmiCompleteRegistrants = new RegistrantList();
 
-    protected final RegistrantList mMmiRegistrants
-            = new RegistrantList();
+    protected final RegistrantList mMmiRegistrants = new RegistrantList();
 
-    protected final RegistrantList mUnknownConnectionRegistrants
-            = new RegistrantList();
+    protected final RegistrantList mUnknownConnectionRegistrants = new RegistrantList();
 
-    protected final RegistrantList mSuppServiceFailedRegistrants
-            = new RegistrantList();
+    protected final RegistrantList mSuppServiceFailedRegistrants = new RegistrantList();
 
-    protected final RegistrantList mRadioOffOrNotAvailableRegistrants
-            = new RegistrantList();
+    protected final RegistrantList mRadioOffOrNotAvailableRegistrants = new RegistrantList();
 
-    protected final RegistrantList mSimRecordsLoadedRegistrants
-            = new RegistrantList();
+    protected final RegistrantList mSimRecordsLoadedRegistrants = new RegistrantList();
 
-    private final RegistrantList mVideoCapabilityChangedRegistrants
-            = new RegistrantList();
+    private final RegistrantList mVideoCapabilityChangedRegistrants = new RegistrantList();
 
-    protected final RegistrantList mEmergencyCallToggledRegistrants
-            = new RegistrantList();
+    protected final RegistrantList mEmergencyCallToggledRegistrants = new RegistrantList();
+
+    private final RegistrantList mAllDataDisconnectedRegistrants = new RegistrantList();
 
     private final RegistrantList mCellInfoRegistrants = new RegistrantList();
 
@@ -484,7 +491,8 @@
         mCi = ci;
         mActionDetached = this.getClass().getPackage().getName() + ".action_detached";
         mActionAttached = this.getClass().getPackage().getName() + ".action_attached";
-        mAppSmsManager = telephonyComponentFactory.makeAppSmsManager(context);
+        mAppSmsManager = telephonyComponentFactory.inject(AppSmsManager.class.getName())
+                .makeAppSmsManager(context);
 
         if (Build.IS_DEBUGGABLE) {
             mTelephonyTester = new TelephonyTester(this);
@@ -546,11 +554,15 @@
 
         // Initialize device storage and outgoing SMS usage monitors for SMSDispatchers.
         mTelephonyComponentFactory = telephonyComponentFactory;
-        mSmsStorageMonitor = mTelephonyComponentFactory.makeSmsStorageMonitor(this);
-        mSmsUsageMonitor = mTelephonyComponentFactory.makeSmsUsageMonitor(context);
+        mSmsStorageMonitor = mTelephonyComponentFactory.inject(SmsStorageMonitor.class.getName())
+                .makeSmsStorageMonitor(this);
+        mSmsUsageMonitor = mTelephonyComponentFactory.inject(SmsUsageMonitor.class.getName())
+                .makeSmsUsageMonitor(context);
         mUiccController = UiccController.getInstance();
         mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
-        mSimActivationTracker = mTelephonyComponentFactory.makeSimActivationTracker(this);
+        mSimActivationTracker = mTelephonyComponentFactory
+                .inject(SimActivationTracker.class.getName())
+                .makeSimActivationTracker(this);
         if (getPhoneType() != PhoneConstants.PHONE_TYPE_SIP) {
             mCi.registerForSrvccStateChanged(this, EVENT_SRVCC_STATE_CHANGED, null);
         }
@@ -713,6 +725,12 @@
                 onCheckForNetworkSelectionModeAutomatic(msg);
                 break;
             }
+
+            case EVENT_ALL_DATA_DISCONNECTED:
+                if (areAllDataDisconnected()) {
+                    mAllDataDisconnectedRegistrants.notifyRegistrants();
+                }
+                break;
             default:
                 throw new RuntimeException("unexpected event not handled");
         }
@@ -1624,6 +1642,13 @@
     }
 
     /**
+     * Retrieves the EmergencyNumberTracker of the phone instance.
+     */
+    public EmergencyNumberTracker getEmergencyNumberTracker() {
+        return null;
+    }
+
+    /**
     * Get call tracker
     */
     public CallTracker getCallTracker() {
@@ -1717,6 +1742,11 @@
         return (r != null) ? r.getRecordsLoaded() : false;
     }
 
+    /** Set the minimum interval for CellInfo requests to the modem */
+    public void setCellInfoMinInterval(int interval) {
+        getServiceStateTracker().setCellInfoMinInterval(interval);
+    }
+
     /**
      * @return the last known CellInfo
      */
@@ -2178,19 +2208,21 @@
         mNotifier.notifyMessageWaitingChanged(this);
     }
 
-    public void notifyDataConnection(String reason, String apnType,
-            PhoneConstants.DataState state) {
-        mNotifier.notifyDataConnection(this, reason, apnType, state);
+    public void notifyDataConnection(String apnType, PhoneConstants.DataState state) {
+        mNotifier.notifyDataConnection(this, apnType, state);
     }
 
-    public void notifyDataConnection(String reason, String apnType) {
-        mNotifier.notifyDataConnection(this, reason, apnType, getDataConnectionState(apnType));
+    public void notifyDataConnection(String apnType) {
+        mNotifier.notifyDataConnection(this, apnType, getDataConnectionState(apnType));
     }
 
-    public void notifyDataConnection(String reason) {
+    public void notifyDataConnection() {
         String types[] = getActiveApnTypes();
-        for (String apnType : types) {
-            mNotifier.notifyDataConnection(this, reason, apnType, getDataConnectionState(apnType));
+        if (types != null) {
+            for (String apnType : types) {
+                mNotifier.notifyDataConnection(this, apnType,
+                        getDataConnectionState(apnType));
+            }
         }
     }
 
@@ -2233,6 +2265,11 @@
         mNotifier.notifySrvccStateChanged(this, state);
     }
 
+    /** Notify the {@link EmergencyNumber} changes. */
+    public void notifyEmergencyNumberList() {
+        mNotifier.notifyEmergencyNumberList();
+    }
+
     /**
      * @return true if a mobile originating emergency call is active
      */
@@ -2820,15 +2857,24 @@
     /**
      * Returns an array of string identifiers for the APN types serviced by the
      * currently active.
-     *  @return The string array will always return at least one entry, Phone.APN_TYPE_DEFAULT.
-     * TODO: Revisit if we always should return at least one entry.
+     *
+     * @return The string array of APN types. Return null if no active APN types.
      */
+    @Nullable
     public String[] getActiveApnTypes() {
-        if (mDcTracker == null) {
-            return null;
+        if (mTransportManager != null) {
+            List<String> typesList = new ArrayList<>();
+            for (int transportType : mTransportManager.getAvailableTransports()) {
+                if (getDcTracker(transportType) != null) {
+                    typesList.addAll(Arrays.asList(
+                            getDcTracker(transportType).getActiveApnTypes()));
+                }
+            }
+
+            return typesList.toArray(new String[typesList.size()]);
         }
 
-        return mDcTracker.getActiveApnTypes();
+        return null;
     }
 
     /**
@@ -2836,7 +2882,10 @@
      * @return true if there is a matching DUN APN.
      */
     public boolean hasMatchedTetherApnSetting() {
-        return mDcTracker.hasMatchedTetherApnSetting();
+        if (getDcTracker(TransportType.WWAN) != null) {
+            return getDcTracker(TransportType.WWAN).hasMatchedTetherApnSetting();
+        }
+        return false;
     }
 
     /**
@@ -2844,40 +2893,71 @@
      *  @return type as a string or null if none.
      */
     public String getActiveApnHost(String apnType) {
-        return mDcTracker.getActiveApnString(apnType);
+        if (mTransportManager != null) {
+            int transportType = mTransportManager.getCurrentTransport(
+                    ApnSetting.getApnTypesBitmaskFromString(apnType));
+            if (getDcTracker(transportType) != null) {
+                return getDcTracker(transportType).getActiveApnString(apnType);
+            }
+        }
+
+        return null;
     }
 
     /**
      * Return the LinkProperties for the named apn or null if not available
      */
     public LinkProperties getLinkProperties(String apnType) {
-        return mDcTracker.getLinkProperties(apnType);
+        if (mTransportManager != null) {
+            int transport = mTransportManager.getCurrentTransport(
+                    ApnSetting.getApnTypesBitmaskFromString(apnType));
+            if (getDcTracker(transport) != null) {
+                return getDcTracker(transport).getLinkProperties(apnType);
+            }
+        }
+        return null;
     }
 
     /**
      * Return the NetworkCapabilities
      */
     public NetworkCapabilities getNetworkCapabilities(String apnType) {
-        return mDcTracker.getNetworkCapabilities(apnType);
+        if (mTransportManager != null) {
+            int transportType = mTransportManager.getCurrentTransport(
+                    ApnSetting.getApnTypesBitmaskFromString(apnType));
+            if (getDcTracker(transportType) != null) {
+                return getDcTracker(transportType).getNetworkCapabilities(apnType);
+            }
+        }
+        return null;
     }
 
     /**
-     * Report on whether data connectivity is allowed.
+     * Report on whether data connectivity is allowed for given APN type.
+     *
+     * @param apnType APN type
      *
      * @return True if data is allowed to be established.
      */
-    public boolean isDataAllowed() {
-        return ((mDcTracker != null) && (mDcTracker.isDataAllowed(null)));
+    public boolean isDataAllowed(@ApnType int apnType) {
+        return isDataAllowed(apnType, null);
     }
 
     /**
      * Report on whether data connectivity is allowed.
      *
+     * @param apnType APN type
      * @param reasons The reasons that data can/can't be established. This is an output param.
      * @return True if data is allowed to be established
      */
-    public boolean isDataAllowed(DataConnectionReasons reasons) {
-        return ((mDcTracker != null) && (mDcTracker.isDataAllowed(reasons)));
+    public boolean isDataAllowed(@ApnType int apnType, DataConnectionReasons reasons) {
+        if (mTransportManager != null) {
+            int transport = mTransportManager.getCurrentTransport(apnType);
+            if (getDcTracker(transport) != null) {
+                return getDcTracker(transport).isDataAllowed(reasons);
+            }
+        }
+        return false;
     }
 
 
@@ -3012,13 +3092,13 @@
     public void notifyCallForwardingIndicator() {
     }
 
-    public void notifyDataConnectionFailed(String reason, String apnType) {
-        mNotifier.notifyDataConnectionFailed(this, reason, apnType);
+    public void notifyDataConnectionFailed(String apnType) {
+        mNotifier.notifyDataConnectionFailed(this, apnType);
     }
 
-    public void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn,
-            String failCause) {
-        mNotifier.notifyPreciseDataConnectionFailed(this, reason, apnType, apn, failCause);
+    public void notifyPreciseDataConnectionFailed(String apnType, String apn,
+            @DataFailCause.FailCause int failCause) {
+        mNotifier.notifyPreciseDataConnectionFailed(this, apnType, apn, failCause);
     }
 
     /**
@@ -3067,7 +3147,15 @@
      * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
      */
     public String[] getPcscfAddress(String apnType) {
-        return mDcTracker.getPcscfAddress(apnType);
+        if (mTransportManager != null) {
+            int transportType = mTransportManager.getCurrentTransport(
+                    ApnSetting.getApnTypesBitmaskFromString(apnType));
+            if (getDcTracker(transportType) != null) {
+                return getDcTracker(transportType).getPcscfAddress(apnType);
+            }
+        }
+
+        return null;
     }
 
     /**
@@ -3606,31 +3694,51 @@
     }
 
     public void updateDataConnectionTracker() {
-        mDcTracker.update();
-    }
-
-    public void setInternalDataEnabled(boolean enable, Message onCompleteMsg) {
-        mDcTracker.setInternalDataEnabled(enable, onCompleteMsg);
+        if (mTransportManager != null) {
+            for (int transport : mTransportManager.getAvailableTransports()) {
+                if (getDcTracker(transport) != null) {
+                    getDcTracker(transport).update();
+                }
+            }
+        }
     }
 
     public boolean updateCurrentCarrierInProvider() {
         return false;
     }
 
-    public void registerForAllDataDisconnected(Handler h, int what, Object obj) {
-        mDcTracker.registerForAllDataDisconnected(h, what, obj);
+    /**
+     * @return True if all data connections are disconnected.
+     */
+    public boolean areAllDataDisconnected() {
+        if (mTransportManager != null) {
+            for (int transport : mTransportManager.getAvailableTransports()) {
+                if (getDcTracker(transport) != null && !getDcTracker(transport).isDisconnected()) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    public void registerForAllDataDisconnected(Handler h, int what) {
+        mAllDataDisconnectedRegistrants.addUnique(h, what, null);
+        if (mTransportManager != null) {
+            for (int transport : mTransportManager.getAvailableTransports()) {
+                if (getDcTracker(transport) != null && !getDcTracker(transport).isDisconnected()) {
+                    getDcTracker(transport).registerForAllDataDisconnected(
+                            this, EVENT_ALL_DATA_DISCONNECTED);
+                }
+            }
+        }
     }
 
     public void unregisterForAllDataDisconnected(Handler h) {
-        mDcTracker.unregisterForAllDataDisconnected(h);
+        mAllDataDisconnectedRegistrants.remove(h);
     }
 
-    public void registerForDataEnabledChanged(Handler h, int what, Object obj) {
-        mDcTracker.registerForDataEnabledChanged(h, what, obj);
-    }
-
-    public void unregisterForDataEnabledChanged(Handler h) {
-        mDcTracker.unregisterForDataEnabledChanged(h);
+    public DataEnabledSettings getDataEnabledSettings() {
+        return mDataEnabledSettings;
     }
 
     public IccSmsInterfaceManager getIccSmsInterfaceManager(){
@@ -3704,14 +3812,6 @@
     }
 
     /**
-     * Policy control of data connection. Usually used when we hit data limit.
-     * @param enabled True if enabling the data, otherwise disabling.
-     */
-    public void setPolicyDataEnabled(boolean enabled) {
-        mDcTracker.setPolicyDataEnabled(enabled);
-    }
-
-    /**
      * SIP URIs aliased to the current subscriber given by the IMS implementation.
      * Applicable only on IMS; used in absence of line1number.
      * @return array of SIP URIs aliased to the current subscriber
@@ -3745,12 +3845,21 @@
             String gid2, String pnn, String spn) {
     }
 
+    /**
+     * Get data connection tracker based on the transport type
+     *
+     * @param transportType Transport type defined in AccessNetworkConstants.TransportType
+     * @return The data connection tracker. Null if not found.
+     */
+    public @Nullable DcTracker getDcTracker(int transportType) {
+        return mDcTrackers.get(transportType);
+    }
+
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("Phone: subId=" + getSubId());
         pw.println(" mPhoneId=" + mPhoneId);
         pw.println(" mCi=" + mCi);
         pw.println(" mDnsCheckDisabled=" + mDnsCheckDisabled);
-        pw.println(" mDcTracker=" + mDcTracker);
         pw.println(" mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing);
         pw.println(" mCallRingContinueToken=" + mCallRingContinueToken);
         pw.println(" mCallRingDelay=" + mCallRingDelay);
@@ -3794,9 +3903,19 @@
             pw.println("++++++++++++++++++++++++++++++++");
         }
 
-        if (mDcTracker != null) {
+        if (mTransportManager != null) {
+            for (int transport : mTransportManager.getAvailableTransports()) {
+                if (getDcTracker(transport) != null) {
+                    getDcTracker(transport).dump(fd, pw, args);
+                    pw.flush();
+                    pw.println("++++++++++++++++++++++++++++++++");
+                }
+            }
+        }
+
+        if (getServiceStateTracker() != null) {
             try {
-                mDcTracker.dump(fd, pw, args);
+                getServiceStateTracker().dump(fd, pw, args);
             } catch (Exception e) {
                 e.printStackTrace();
             }
@@ -3805,9 +3924,9 @@
             pw.println("++++++++++++++++++++++++++++++++");
         }
 
-        if (getServiceStateTracker() != null) {
+        if (getEmergencyNumberTracker() != null) {
             try {
-                getServiceStateTracker().dump(fd, pw, args);
+                getEmergencyNumberTracker().dump(fd, pw, args);
             } catch (Exception e) {
                 e.printStackTrace();
             }
diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java
index b5eb9a7..5359941 100644
--- a/src/java/com/android/internal/telephony/PhoneFactory.java
+++ b/src/java/com/android/internal/telephony/PhoneFactory.java
@@ -259,8 +259,7 @@
                 sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones];
                 for (int i = 0; i < numPhones; i++) {
                     sTelephonyNetworkFactories[i] = new TelephonyNetworkFactory(
-                            sPhoneSwitcher, sc, sSubscriptionMonitor, Looper.myLooper(),
-                            sContext, i, sPhones[i].mDcTracker);
+                            sSubscriptionMonitor, Looper.myLooper(), sPhones[i]);
                 }
             }
         }
diff --git a/src/java/com/android/internal/telephony/PhoneInternalInterface.java b/src/java/com/android/internal/telephony/PhoneInternalInterface.java
index a304ab6..41d7ae4 100644
--- a/src/java/com/android/internal/telephony/PhoneInternalInterface.java
+++ b/src/java/com/android/internal/telephony/PhoneInternalInterface.java
@@ -123,7 +123,7 @@
      */
     static final String REASON_ROAMING_ON = "roamingOn";
     static final String REASON_ROAMING_OFF = "roamingOff";
-    static final String REASON_DATA_DISABLED = "dataDisabled";
+    static final String REASON_DATA_DISABLED_INTERNAL = "dataDisabledInternal";
     static final String REASON_DATA_ENABLED = "dataEnabled";
     static final String REASON_DATA_ATTACHED = "dataAttached";
     static final String REASON_DATA_DETACHED = "dataDetached";
@@ -740,16 +740,6 @@
     boolean isUserDataEnabled();
 
     /**
-     * @return true if data is enabled considering all factors
-     */
-    boolean isDataEnabled();
-
-    /**
-     * @param @enable set {@code true} if enable data connection
-     */
-    void setUserDataEnabled(boolean enable);
-
-    /**
      * Retrieves the unique device ID, e.g., IMEI for GSM phones and MEID for CDMA phones.
      */
     String getDeviceId();
diff --git a/src/java/com/android/internal/telephony/PhoneNotifier.java b/src/java/com/android/internal/telephony/PhoneNotifier.java
index 0568187..ce03ad8 100644
--- a/src/java/com/android/internal/telephony/PhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/PhoneNotifier.java
@@ -18,6 +18,7 @@
 
 import android.telephony.CellInfo;
 import android.telephony.CellLocation;
+import android.telephony.DataFailCause;
 import android.telephony.PhoneCapability;
 import android.telephony.PhysicalChannelConfig;
 import android.telephony.TelephonyManager;
@@ -29,40 +30,38 @@
  */
 public interface PhoneNotifier {
 
-    public void notifyPhoneState(Phone sender);
+    void notifyPhoneState(Phone sender);
 
-    public void notifyServiceState(Phone sender);
+    void notifyServiceState(Phone sender);
 
     /** Notify registrants of the current CellLocation */
     void notifyCellLocation(Phone sender, CellLocation cl);
 
-    public void notifySignalStrength(Phone sender);
+    void notifySignalStrength(Phone sender);
 
-    public void notifyMessageWaitingChanged(Phone sender);
+    void notifyMessageWaitingChanged(Phone sender);
 
-    public void notifyCallForwardingChanged(Phone sender);
+    void notifyCallForwardingChanged(Phone sender);
 
-    /** TODO - reason should never be null */
-    public void notifyDataConnection(Phone sender, String reason, String apnType,
-            PhoneConstants.DataState state);
+    void notifyDataConnection(Phone sender, String apnType, PhoneConstants.DataState state);
 
-    public void notifyDataConnectionFailed(Phone sender, String reason, String apnType);
+    void notifyDataConnectionFailed(Phone sender, String apnType);
 
-    public void notifyDataActivity(Phone sender);
+    void notifyDataActivity(Phone sender);
 
-    public void notifyOtaspChanged(Phone sender, int otaspMode);
+    void notifyOtaspChanged(Phone sender, int otaspMode);
 
-    public void notifyCellInfo(Phone sender, List<CellInfo> cellInfo);
+    void notifyCellInfo(Phone sender, List<CellInfo> cellInfo);
 
     /** Notify of change to PhysicalChannelConfiguration. */
     void notifyPhysicalChannelConfiguration(Phone sender, List<PhysicalChannelConfig> configs);
 
-    public void notifyPreciseCallState(Phone sender);
+    void notifyPreciseCallState(Phone sender);
 
-    public void notifyDisconnectCause(int cause, int preciseCause);
+    void notifyDisconnectCause(int cause, int preciseCause);
 
-    public void notifyPreciseDataConnectionFailed(Phone sender, String reason, String apnType,
-            String apn, String failCause);
+    public void notifyPreciseDataConnectionFailed(Phone sender, String apnType, String apn,
+                                                  @DataFailCause.FailCause int failCause);
 
     /** send a notification that the SRVCC state has changed.*/
     void notifySrvccStateChanged(Phone sender, @TelephonyManager.SrvccState int state);
@@ -78,4 +77,7 @@
     public void notifyPhoneCapabilityChanged(PhoneCapability capability);
 
     void notifyRadioPowerStateChanged(@TelephonyManager.RadioPowerState int state);
+
+    /** Notify of change to EmergencyNumberList. */
+    void notifyEmergencyNumberList();
 }
diff --git a/src/java/com/android/internal/telephony/PhoneSwitcher.java b/src/java/com/android/internal/telephony/PhoneSwitcher.java
index 75dd049..74897d2 100644
--- a/src/java/com/android/internal/telephony/PhoneSwitcher.java
+++ b/src/java/com/android/internal/telephony/PhoneSwitcher.java
@@ -17,6 +17,7 @@
 package com.android.internal.telephony;
 
 import static android.telephony.PhoneStateListener.LISTEN_PHONE_CAPABILITY_CHANGE;
+import static android.telephony.SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
 import static android.telephony.SubscriptionManager.INVALID_PHONE_INDEX;
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
@@ -137,18 +138,18 @@
     }
 
     @VisibleForTesting
-    public PhoneSwitcher(Looper looper) {
+    public PhoneSwitcher(int numPhones, Looper looper) {
         super(looper);
         mMaxActivePhones = 0;
         mSubscriptionController = null;
-        mPhoneSubscriptions = null;
         mCommandsInterfaces = null;
         mContext = null;
         mPhoneStates = null;
         mPhones = null;
         mLocalLog = null;
         mActivePhoneRegistrants = null;
-        mNumPhones = 0;
+        mNumPhones = numPhones;
+        mPhoneSubscriptions = new int[numPhones];
         mRadioConfig = RadioConfig.getInstance(mContext);
         mPhoneStateListener = new PhoneStateListener(looper) {
             public void onPhoneCapabilityChanged(PhoneCapability capability) {
@@ -385,6 +386,11 @@
         if (diffDetected) {
             log("evaluating due to " + sb.toString());
             if (mHalCommandToUse == HAL_COMMAND_PREFERRED_DATA) {
+                // With HAL_COMMAND_PREFERRED_DATA, all phones are assumed to allow PS attach.
+                // So marking all phone as active.
+                for (int phoneId = 0; phoneId < mNumPhones; phoneId++) {
+                    activate(phoneId);
+                }
                 if (SubscriptionManager.isUsableSubIdValue(mPreferredDataPhoneId)) {
                     mRadioConfig.setPreferredDataModem(mPreferredDataPhoneId, null);
                 }
@@ -485,7 +491,7 @@
         if (mHalCommandToUse == HAL_COMMAND_ALLOW_DATA || mHalCommandToUse == HAL_COMMAND_UNKNOWN) {
             // Skip ALLOW_DATA for single SIM device
             if (mNumPhones > 1) {
-                mCommandsInterfaces[phoneId].setDataAllowed(mPhoneStates[phoneId].active, null);
+                mCommandsInterfaces[phoneId].setDataAllowed(isPhoneActive(phoneId), null);
             }
         } else {
             mRadioConfig.setPreferredDataModem(mPreferredDataPhoneId, null);
@@ -503,9 +509,38 @@
     }
 
     private int phoneIdForRequest(NetworkRequest netRequest) {
-        NetworkSpecifier specifier = netRequest.networkCapabilities.getNetworkSpecifier();
+        int subId = getSubIdFromNetworkRequest(netRequest);
+
+        if (subId == DEFAULT_SUBSCRIPTION_ID) return mPreferredDataPhoneId;
+        if (subId == INVALID_SUBSCRIPTION_ID) return INVALID_PHONE_INDEX;
+
+        int preferredDataSubId = SubscriptionManager.isValidPhoneId(mPreferredDataPhoneId)
+                ? mPhoneSubscriptions[mPreferredDataPhoneId] : INVALID_SUBSCRIPTION_ID;
+        // Currently we assume multi-SIM devices will only support one Internet PDN connection. So
+        // if Internet PDN is established on the non-preferred phone, it will interrupt
+        // Internet connection on the preferred phone. So we only accept Internet request with
+        // preferred data subscription or no specified subscription.
+        if (netRequest.networkCapabilities.hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_INTERNET) && subId != preferredDataSubId) {
+            // Returning INVALID_PHONE_INDEX will result in netRequest not being handled.
+            return INVALID_PHONE_INDEX;
+        }
+
+        // Try to find matching phone ID. If it doesn't exist, we'll end up returning INVALID.
+        int phoneId = INVALID_PHONE_INDEX;
+        for (int i = 0; i < mNumPhones; i++) {
+            if (mPhoneSubscriptions[i] == subId) {
+                phoneId = i;
+                break;
+            }
+        }
+        return phoneId;
+    }
+
+    private int getSubIdFromNetworkRequest(NetworkRequest networkRequest) {
+        NetworkSpecifier specifier = networkRequest.networkCapabilities.getNetworkSpecifier();
         if (specifier == null) {
-            return mPreferredDataPhoneId;
+            return DEFAULT_SUBSCRIPTION_ID;
         }
 
         int subId;
@@ -516,22 +551,13 @@
             } catch (NumberFormatException e) {
                 Rlog.e(LOG_TAG, "NumberFormatException on "
                         + ((StringNetworkSpecifier) specifier).specifier);
-                subId = INVALID_SUBSCRIPTION_ID;
+                return INVALID_SUBSCRIPTION_ID;
             }
         } else {
-            subId = INVALID_SUBSCRIPTION_ID;
+            return INVALID_SUBSCRIPTION_ID;
         }
 
-        int phoneId = INVALID_PHONE_INDEX;
-        if (subId == INVALID_SUBSCRIPTION_ID) return phoneId;
-
-        for (int i = 0 ; i < mNumPhones; i++) {
-            if (mPhoneSubscriptions[i] == subId) {
-                phoneId = i;
-                break;
-            }
-        }
-        return phoneId;
+        return subId;
     }
 
     private int getSubIdForDefaultNetworkRequests() {
@@ -560,28 +586,20 @@
         mPreferredDataPhoneId = phoneId;
     }
 
-    /**
-     * Returns whether phone should handle network requests
-     * that don't specify a subId.
-     */
-    public boolean shouldApplyUnspecifiedRequests(int phoneId) {
+    public boolean shouldApplyNetworkRequest(NetworkRequest networkRequest, int phoneId) {
         validatePhoneId(phoneId);
-        if (mHalCommandToUse == HAL_COMMAND_PREFERRED_DATA) {
-            return phoneId == mPreferredDataPhoneId;
-        } else {
-            return mPhoneStates[phoneId].active && phoneId == mPreferredDataPhoneId;
-        }
+
+        // In any case, if phone state is inactive, don't apply the network request.
+        if (!isPhoneActive(phoneId)) return false;
+
+        int phoneIdToHandle = phoneIdForRequest(networkRequest);
+
+        return phoneId == phoneIdToHandle;
     }
 
-    /**
-     * Returns whether phone should handle network requests
-     * that specify a subId.
-     */
-    public boolean shouldApplySpecifiedRequests(int phoneId) {
-        validatePhoneId(phoneId);
-        // If we use SET_PREFERRED_DATA, always apply specified network requests. Otherwise,
-        // only apply network requests if the phone is active (dataAllowed).
-        return mHalCommandToUse == HAL_COMMAND_PREFERRED_DATA || mPhoneStates[phoneId].active;
+    @VisibleForTesting
+    protected boolean isPhoneActive(int phoneId) {
+        return mPhoneStates[phoneId].active;
     }
 
     /**
@@ -598,7 +616,8 @@
         mActivePhoneRegistrants.remove(h);
     }
 
-    private void validatePhoneId(int phoneId) {
+    @VisibleForTesting
+    protected void validatePhoneId(int phoneId) {
         if (phoneId < 0 || phoneId >= mNumPhones) {
             throw new IllegalArgumentException("Invalid PhoneId");
         }
diff --git a/src/java/com/android/internal/telephony/ProxyController.java b/src/java/com/android/internal/telephony/ProxyController.java
index 231ec78..7afdb7e 100644
--- a/src/java/com/android/internal/telephony/ProxyController.java
+++ b/src/java/com/android/internal/telephony/ProxyController.java
@@ -147,28 +147,11 @@
         logd("Constructor - Exit");
     }
 
-    public void updateDataConnectionTracker(int sub) {
-        mPhones[sub].updateDataConnectionTracker();
-    }
-
-    public void enableDataConnectivity(int sub) {
-        mPhones[sub].setInternalDataEnabled(true, null);
-    }
-
-    public void disableDataConnectivity(int sub,
-            Message dataCleanedUpMsg) {
-        mPhones[sub].setInternalDataEnabled(false, dataCleanedUpMsg);
-    }
-
-    public void updateCurrentCarrierInProvider(int sub) {
-        mPhones[sub].updateCurrentCarrierInProvider();
-    }
-
-    public void registerForAllDataDisconnected(int subId, Handler h, int what, Object obj) {
+    public void registerForAllDataDisconnected(int subId, Handler h, int what) {
         int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
 
         if (phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount()) {
-            mPhones[phoneId].registerForAllDataDisconnected(h, what, obj);
+            mPhones[phoneId].registerForAllDataDisconnected(h, what);
         }
     }
 
@@ -180,17 +163,6 @@
         }
     }
 
-    public boolean isDataDisconnected(int subId) {
-        int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
-
-        if (phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount()) {
-            return mPhones[phoneId].mDcTracker.isDisconnected();
-        } else {
-            // if we can't find a phone for the given subId, it is disconnected.
-            return true;
-        }
-    }
-
     /**
      * Get phone radio type and access technology.
      *
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 9181e98..41081e6 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -26,12 +26,6 @@
 import android.hardware.radio.V1_0.CdmaSmsAck;
 import android.hardware.radio.V1_0.CdmaSmsMessage;
 import android.hardware.radio.V1_0.CdmaSmsWriteArgs;
-import android.hardware.radio.V1_0.CellInfoCdma;
-import android.hardware.radio.V1_0.CellInfoGsm;
-import android.hardware.radio.V1_0.CellInfoLte;
-import android.hardware.radio.V1_0.CellInfoTdscdma;
-import android.hardware.radio.V1_0.CellInfoType;
-import android.hardware.radio.V1_0.CellInfoWcdma;
 import android.hardware.radio.V1_0.DataProfileId;
 import android.hardware.radio.V1_0.Dial;
 import android.hardware.radio.V1_0.GsmBroadcastSmsConfigInfo;
@@ -63,7 +57,6 @@
 import android.os.Handler;
 import android.os.HwBinder;
 import android.os.Message;
-import android.os.Parcel;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
 import android.os.RemoteException;
@@ -72,9 +65,7 @@
 import android.os.WorkSource;
 import android.service.carrier.CarrierIdentifier;
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
-import android.telephony.CellIdentityCdma;
 import android.telephony.CellInfo;
-import android.telephony.CellSignalStrengthCdma;
 import android.telephony.ClientRequestStats;
 import android.telephony.ImsiEncryptionInfo;
 import android.telephony.ModemActivityInfo;
@@ -85,10 +76,10 @@
 import android.telephony.RadioAccessSpecifier;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
 import android.telephony.SmsManager;
 import android.telephony.TelephonyHistogram;
 import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
 import android.telephony.data.DataProfile;
 import android.telephony.data.DataService;
 import android.text.TextUtils;
@@ -135,7 +126,7 @@
     // Have a separate wakelock instance for Ack
     static final String RILJ_ACK_WAKELOCK_NAME = "RILJ_ACK_WL";
     static final boolean RILJ_LOGD = true;
-    static final boolean RILJ_LOGV = false; // STOPSHIP if true
+    static final boolean RILJ_LOGV = true; // STOPSHIP if true
     static final int RIL_HISTOGRAM_BUCKET_COUNT = 5;
 
     /**
@@ -860,12 +851,20 @@
     }
 
     @Override
-    public void dial(String address, int clirMode, Message result) {
-        dial(address, clirMode, null, result);
+    public void dial(String address, boolean isEmergencyCall, int emergencyServiceCategories,
+                     int clirMode, Message result) {
+        dial(address, isEmergencyCall, emergencyServiceCategories, clirMode, null, result);
     }
 
     @Override
-    public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
+    public void dial(String address, boolean isEmergencyCall, int emergencyServiceCategories,
+                     int clirMode, UUSInfo uusInfo, Message result) {
+        if (isEmergencyCall && mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_4)) {
+            emergencyDial(address, emergencyServiceCategories, clirMode, uusInfo,
+                    result);
+            return;
+        }
+
         IRadio radioProxy = getRadioProxy(result);
         if (radioProxy != null) {
             RILRequest rr = obtainRequest(RIL_REQUEST_DIAL, result,
@@ -895,6 +894,39 @@
         }
     }
 
+    private void emergencyDial(String address, int emergencyServiceCategories, int clirMode,
+                              UUSInfo uusInfo, Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        // IRadio V1.4
+        android.hardware.radio.V1_4.IRadio radioProxy14 =
+                (android.hardware.radio.V1_4.IRadio) radioProxy;
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_EMERGENCY_DIAL, result,
+                    mRILDefaultWorkSource);
+            Dial dialInfo = new Dial();
+            dialInfo.address = convertNullToEmptyString(address);
+            dialInfo.clir = clirMode;
+            if (uusInfo != null) {
+                UusInfo info = new UusInfo();
+                info.uusType = uusInfo.getType();
+                info.uusDcs = uusInfo.getDcs();
+                info.uusData = new String(uusInfo.getUserData());
+                dialInfo.uusInfo.add(info);
+            }
+
+            if (RILJ_LOGD) {
+                // Do not log function arg for privacy
+                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+            }
+
+            try {
+                radioProxy14.emergencyDial(rr.mSerial, dialInfo, emergencyServiceCategories);
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "emergencyDial", e);
+            }
+        }
+    }
+
     @Override
     public void getIMSI(Message result) {
         getIMSIForApp(null, result);
@@ -1256,8 +1288,8 @@
                 new android.hardware.radio.V1_4.DataProfileInfo();
 
         dpi.apn = dp.getApn();
-        dpi.protocol = dp.getProtocol();
-        dpi.roamingProtocol = dp.getRoamingProtocol();
+        dpi.protocol = ApnSetting.getProtocolIntFromString(dp.getProtocol());
+        dpi.roamingProtocol = ApnSetting.getProtocolIntFromString(dp.getRoamingProtocol());
         dpi.authType = dp.getAuthType();
         dpi.user = dp.getUserName();
         dpi.password = dp.getPassword();
@@ -2420,10 +2452,21 @@
             mPreferredNetworkType = networkType;
             mMetrics.writeSetPreferredNetworkType(mPhoneId, networkType);
 
-            try {
-                radioProxy.setPreferredNetworkType(rr.mSerial, networkType);
-            } catch (RemoteException | RuntimeException e) {
-                handleRadioProxyExceptionForRR(rr, "setPreferredNetworkType", e);
+            if (mRadioVersion.lessOrEqual(RADIO_HAL_VERSION_1_3)) {
+                try {
+                    radioProxy.setPreferredNetworkType(rr.mSerial, networkType);
+                } catch (RemoteException | RuntimeException e) {
+                    handleRadioProxyExceptionForRR(rr, "setPreferredNetworkType", e);
+                }
+            } else if (mRadioVersion.equals(RADIO_HAL_VERSION_1_4)) {
+                android.hardware.radio.V1_4.IRadio radioProxy14 =
+                        (android.hardware.radio.V1_4.IRadio) radioProxy;
+                try {
+                    radioProxy14.setPreferredNetworkTypeBitmap(
+                            rr.mSerial, RadioAccessFamily.getRafFromNetworkType(networkType));
+                } catch (RemoteException | RuntimeException e) {
+                    handleRadioProxyExceptionForRR(rr, "setPreferredNetworkTypeBitmap", e);
+                }
             }
         }
     }
@@ -2434,13 +2477,21 @@
         if (radioProxy != null) {
             RILRequest rr = obtainRequest(RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, result,
                     mRILDefaultWorkSource);
-
             if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
-            try {
-                radioProxy.getPreferredNetworkType(rr.mSerial);
-            } catch (RemoteException | RuntimeException e) {
-                handleRadioProxyExceptionForRR(rr, "getPreferredNetworkType", e);
+            if (mRadioVersion.lessOrEqual(RADIO_HAL_VERSION_1_3)) {
+                try {
+                    radioProxy.getPreferredNetworkType(rr.mSerial);
+                } catch (RemoteException | RuntimeException e) {
+                    handleRadioProxyExceptionForRR(rr, "getPreferredNetworkType", e);
+                }
+            } else if (mRadioVersion.equals(RADIO_HAL_VERSION_1_4)) {
+                android.hardware.radio.V1_4.IRadio radioProxy14 =
+                        (android.hardware.radio.V1_4.IRadio) radioProxy;
+                try {
+                    radioProxy14.getPreferredNetworkTypeBitmap(rr.mSerial);
+                } catch (RemoteException | RuntimeException e) {
+                    handleRadioProxyExceptionForRR(rr, "getPreferredNetworkTypeBitmap", e);
+                }
             }
         }
     }
@@ -3138,10 +3189,6 @@
         }
     }
 
-    void setCellInfoListRate() {
-        setCellInfoListRate(Integer.MAX_VALUE, null, mRILDefaultWorkSource);
-    }
-
     @Override
     public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, Message result) {
 
@@ -3273,8 +3320,9 @@
             if (RILJ_LOGD) {
                 if (Build.IS_DEBUGGABLE) {
                     riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
-                            + " cla = " + cla + " instruction = " + instruction
-                            + " p1 = " + p1 + " p2 = " + " p3 = " + p3 + " data = " + data);
+                            + String.format(" cla = 0x%02X ins = 0x%02X", cla, instruction)
+                            + String.format(" p1 = 0x%02X p2 = 0x%02X p3 = 0x%02X", p1, p2, p3)
+                            + " data = " + data);
                 } else {
                     riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
                 }
@@ -3349,9 +3397,11 @@
 
             if (RILJ_LOGD) {
                 if (Build.IS_DEBUGGABLE) {
-                    riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " channel = "
-                            + channel + " cla = " + cla + " instruction = " + instruction
-                            + " p1 = " + p1 + " p2 = " + " p3 = " + p3 + " data = " + data);
+                    riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+                            + String.format(" channel = %d", channel)
+                            + String.format(" cla = 0x%02X ins = 0x%02X", cla, instruction)
+                            + String.format(" p1 = 0x%02X p2 = 0x%02X p3 = 0x%02X", p1, p2, p3)
+                            + " data = " + data);
                 } else {
                     riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
                 }
@@ -5402,101 +5452,6 @@
         return lce;
     }
 
-    // TODO(b/119224773) refactor the converter of CellInfo.
-    private static void writeToParcelForGsm(
-            Parcel p, int lac, int cid, int arfcn, int bsic, String mcc, String mnc,
-            String al, String as, int ss, int ber, int ta) {
-        p.writeInt(CellInfo.TYPE_GSM);
-        p.writeString(mcc);
-        p.writeString(mnc);
-        p.writeString(al);
-        p.writeString(as);
-        p.writeInt(lac);
-        p.writeInt(cid);
-        p.writeInt(arfcn);
-        p.writeInt(bsic);
-        p.writeInt(ss);
-        p.writeInt(ber);
-        p.writeInt(ta);
-    }
-
-    // TODO(b/119224773) refactor the converter of CellInfo.
-    private static void writeToParcelForCdma(
-            Parcel p, int ni, int si, int bsi, int lon, int lat, String al, String as,
-            int dbm, int ecio, int eDbm, int eEcio, int eSnr) {
-        new CellIdentityCdma(ni, si, bsi, lon, lat, al, as).writeToParcel(p, 0);
-        new CellSignalStrengthCdma(dbm, ecio, eDbm, eEcio, eSnr).writeToParcel(p, 0);
-    }
-
-    // TODO(b/119224773) refactor the converter of CellInfo.
-    private static void writeToParcelForLte(
-            Parcel p, int ci, int pci, int tac, int earfcn, int bandwidth, String mcc, String mnc,
-            String al, String as, int ss, int rsrp, int rsrq, int rssnr, int cqi, int ta,
-            boolean isEndcAvailable) {
-
-        // General CellInfo
-        p.writeInt(CellInfo.TYPE_LTE);
-        p.writeString(mcc);
-        p.writeString(mnc);
-        p.writeString(al);
-        p.writeString(as);
-
-        // CellIdentity
-        p.writeInt(ci);
-        p.writeInt(pci);
-        p.writeInt(tac);
-        p.writeInt(earfcn);
-        p.writeInt(bandwidth);
-
-        // CellSignalStrength
-        p.writeInt(ss);
-        p.writeInt(rsrp);
-        p.writeInt(rsrq);
-        p.writeInt(rssnr);
-        p.writeInt(cqi);
-        p.writeInt(ta);
-
-        // CellConfigLte
-        p.writeBoolean(isEndcAvailable);
-    }
-
-    // TODO(b/119224773) refactor the converter of CellInfo.
-    private static void writeToParcelForWcdma(
-            Parcel p, int lac, int cid, int psc, int uarfcn, String mcc, String mnc,
-            String al, String as, int ss, int ber, int rscp, int ecno) {
-        p.writeInt(CellInfo.TYPE_WCDMA);
-        p.writeString(mcc);
-        p.writeString(mnc);
-        p.writeString(al);
-        p.writeString(as);
-        p.writeInt(lac);
-        p.writeInt(cid);
-        p.writeInt(psc);
-        p.writeInt(uarfcn);
-        p.writeInt(ss);
-        p.writeInt(ber);
-        p.writeInt(rscp);
-        p.writeInt(ecno);
-    }
-
-    // TODO(b/119224773) refactor the converter of CellInfo.
-    private static void writeToParcelForTdscdma(
-            Parcel p, int lac, int cid, int cpid, int uarfcn, String mcc, String mnc,
-            String al, String as, int ss, int ber, int rscp) {
-        p.writeInt(CellInfo.TYPE_TDSCDMA);
-        p.writeString(mcc);
-        p.writeString(mnc);
-        p.writeString(al);
-        p.writeString(as);
-        p.writeInt(lac);
-        p.writeInt(cid);
-        p.writeInt(cpid);
-        p.writeInt(uarfcn);
-        p.writeInt(ss);
-        p.writeInt(ber);
-        p.writeInt(rscp);
-    }
-
     /**
      * Convert CellInfo defined in 1.0/types.hal to CellInfo type.
      * @param records List of CellInfo defined in 1.0/types.hal
@@ -5508,117 +5463,7 @@
         ArrayList<CellInfo> response = new ArrayList<CellInfo>(records.size());
 
         for (android.hardware.radio.V1_0.CellInfo record : records) {
-            // first convert RIL CellInfo to Parcel
-            Parcel p = Parcel.obtain();
-            p.writeInt(record.cellInfoType);
-            p.writeInt(record.registered ? 1 : 0);
-            p.writeLong(SystemClock.elapsedRealtimeNanos());
-            p.writeInt(CellInfo.CONNECTION_UNKNOWN);
-            switch (record.cellInfoType) {
-                case CellInfoType.GSM: {
-                    CellInfoGsm cellInfoGsm = record.gsm.get(0);
-                    writeToParcelForGsm(
-                            p,
-                            cellInfoGsm.cellIdentityGsm.lac,
-                            cellInfoGsm.cellIdentityGsm.cid,
-                            cellInfoGsm.cellIdentityGsm.arfcn,
-                            Byte.toUnsignedInt(cellInfoGsm.cellIdentityGsm.bsic),
-                            cellInfoGsm.cellIdentityGsm.mcc,
-                            cellInfoGsm.cellIdentityGsm.mnc,
-                            EMPTY_ALPHA_LONG,
-                            EMPTY_ALPHA_SHORT,
-                            cellInfoGsm.signalStrengthGsm.signalStrength,
-                            cellInfoGsm.signalStrengthGsm.bitErrorRate,
-                            cellInfoGsm.signalStrengthGsm.timingAdvance);
-                    break;
-                }
-
-                case CellInfoType.CDMA: {
-                    CellInfoCdma cellInfoCdma = record.cdma.get(0);
-                    writeToParcelForCdma(
-                            p,
-                            cellInfoCdma.cellIdentityCdma.networkId,
-                            cellInfoCdma.cellIdentityCdma.systemId,
-                            cellInfoCdma.cellIdentityCdma.baseStationId,
-                            cellInfoCdma.cellIdentityCdma.longitude,
-                            cellInfoCdma.cellIdentityCdma.latitude,
-                            EMPTY_ALPHA_LONG,
-                            EMPTY_ALPHA_SHORT,
-                            cellInfoCdma.signalStrengthCdma.dbm,
-                            cellInfoCdma.signalStrengthCdma.ecio,
-                            cellInfoCdma.signalStrengthEvdo.dbm,
-                            cellInfoCdma.signalStrengthEvdo.ecio,
-                            cellInfoCdma.signalStrengthEvdo.signalNoiseRatio);
-                    break;
-                }
-
-                case CellInfoType.LTE: {
-                    CellInfoLte cellInfoLte = record.lte.get(0);
-                    writeToParcelForLte(
-                            p,
-                            cellInfoLte.cellIdentityLte.ci,
-                            cellInfoLte.cellIdentityLte.pci,
-                            cellInfoLte.cellIdentityLte.tac,
-                            cellInfoLte.cellIdentityLte.earfcn,
-                            Integer.MAX_VALUE,
-                            cellInfoLte.cellIdentityLte.mcc,
-                            cellInfoLte.cellIdentityLte.mnc,
-                            EMPTY_ALPHA_LONG,
-                            EMPTY_ALPHA_SHORT,
-                            cellInfoLte.signalStrengthLte.signalStrength,
-                            cellInfoLte.signalStrengthLte.rsrp,
-                            cellInfoLte.signalStrengthLte.rsrq,
-                            cellInfoLte.signalStrengthLte.rssnr,
-                            cellInfoLte.signalStrengthLte.cqi,
-                            cellInfoLte.signalStrengthLte.timingAdvance,
-                            false /* isEndcAvailable */);
-                    break;
-                }
-
-                case CellInfoType.WCDMA: {
-                    CellInfoWcdma cellInfoWcdma = record.wcdma.get(0);
-                    writeToParcelForWcdma(
-                            p,
-                            cellInfoWcdma.cellIdentityWcdma.lac,
-                            cellInfoWcdma.cellIdentityWcdma.cid,
-                            cellInfoWcdma.cellIdentityWcdma.psc,
-                            cellInfoWcdma.cellIdentityWcdma.uarfcn,
-                            cellInfoWcdma.cellIdentityWcdma.mcc,
-                            cellInfoWcdma.cellIdentityWcdma.mnc,
-                            EMPTY_ALPHA_LONG,
-                            EMPTY_ALPHA_SHORT,
-                            cellInfoWcdma.signalStrengthWcdma.signalStrength,
-                            cellInfoWcdma.signalStrengthWcdma.bitErrorRate,
-                            Integer.MAX_VALUE,
-                            Integer.MAX_VALUE);
-                    break;
-                }
-
-                case CellInfoType.TD_SCDMA: {
-                    CellInfoTdscdma cellInfoTdscdma = record.tdscdma.get(0);
-                    writeToParcelForTdscdma(
-                            p,
-                            cellInfoTdscdma.cellIdentityTdscdma.lac,
-                            cellInfoTdscdma.cellIdentityTdscdma.cid,
-                            cellInfoTdscdma.cellIdentityTdscdma.cpid,
-                            Integer.MAX_VALUE,
-                            cellInfoTdscdma.cellIdentityTdscdma.mcc,
-                            cellInfoTdscdma.cellIdentityTdscdma.mnc,
-                            EMPTY_ALPHA_LONG,
-                            EMPTY_ALPHA_SHORT,
-                            Integer.MAX_VALUE,
-                            Integer.MAX_VALUE,
-                            convertTdscdmaRscpTo1_2(cellInfoTdscdma.signalStrengthTdscdma.rscp));
-                    break;
-                }
-                default:
-                    throw new RuntimeException("unexpected cellinfotype: " + record.cellInfoType);
-            }
-
-            p.setDataPosition(0);
-            CellInfo InfoRec = CellInfo.CREATOR.createFromParcel(p);
-            p.recycle();
-            response.add(InfoRec);
+            response.add(CellInfo.create(record));
         }
 
         return response;
@@ -5635,178 +5480,11 @@
         ArrayList<CellInfo> response = new ArrayList<CellInfo>(records.size());
 
         for (android.hardware.radio.V1_2.CellInfo record : records) {
-            // first convert RIL CellInfo to Parcel
-            Parcel p = Parcel.obtain();
-            p.writeInt(record.cellInfoType);
-            p.writeInt(record.registered ? 1 : 0);
-            p.writeLong(SystemClock.elapsedRealtimeNanos());
-            p.writeInt(record.connectionStatus);
-            switch (record.cellInfoType) {
-                case CellInfoType.GSM: {
-                    android.hardware.radio.V1_2.CellInfoGsm cellInfoGsm = record.gsm.get(0);
-                    writeToParcelForGsm(
-                            p,
-                            cellInfoGsm.cellIdentityGsm.base.lac,
-                            cellInfoGsm.cellIdentityGsm.base.cid,
-                            cellInfoGsm.cellIdentityGsm.base.arfcn,
-                            Byte.toUnsignedInt(cellInfoGsm.cellIdentityGsm.base.bsic),
-                            cellInfoGsm.cellIdentityGsm.base.mcc,
-                            cellInfoGsm.cellIdentityGsm.base.mnc,
-                            cellInfoGsm.cellIdentityGsm.operatorNames.alphaLong,
-                            cellInfoGsm.cellIdentityGsm.operatorNames.alphaShort,
-                            cellInfoGsm.signalStrengthGsm.signalStrength,
-                            cellInfoGsm.signalStrengthGsm.bitErrorRate,
-                            cellInfoGsm.signalStrengthGsm.timingAdvance);
-                    break;
-                }
-
-                case CellInfoType.CDMA: {
-                    android.hardware.radio.V1_2.CellInfoCdma cellInfoCdma = record.cdma.get(0);
-                    writeToParcelForCdma(
-                            p,
-                            cellInfoCdma.cellIdentityCdma.base.networkId,
-                            cellInfoCdma.cellIdentityCdma.base.systemId,
-                            cellInfoCdma.cellIdentityCdma.base.baseStationId,
-                            cellInfoCdma.cellIdentityCdma.base.longitude,
-                            cellInfoCdma.cellIdentityCdma.base.latitude,
-                            cellInfoCdma.cellIdentityCdma.operatorNames.alphaLong,
-                            cellInfoCdma.cellIdentityCdma.operatorNames.alphaShort,
-                            cellInfoCdma.signalStrengthCdma.dbm,
-                            cellInfoCdma.signalStrengthCdma.ecio,
-                            cellInfoCdma.signalStrengthEvdo.dbm,
-                            cellInfoCdma.signalStrengthEvdo.ecio,
-                            cellInfoCdma.signalStrengthEvdo.signalNoiseRatio);
-                    break;
-                }
-
-                case CellInfoType.LTE: {
-                    android.hardware.radio.V1_2.CellInfoLte cellInfoLte = record.lte.get(0);
-                    writeToParcelForLte(
-                            p,
-                            cellInfoLte.cellIdentityLte.base.ci,
-                            cellInfoLte.cellIdentityLte.base.pci,
-                            cellInfoLte.cellIdentityLte.base.tac,
-                            cellInfoLte.cellIdentityLte.base.earfcn,
-                            cellInfoLte.cellIdentityLte.bandwidth,
-                            cellInfoLte.cellIdentityLte.base.mcc,
-                            cellInfoLte.cellIdentityLte.base.mnc,
-                            cellInfoLte.cellIdentityLte.operatorNames.alphaLong,
-                            cellInfoLte.cellIdentityLte.operatorNames.alphaShort,
-                            cellInfoLte.signalStrengthLte.signalStrength,
-                            cellInfoLte.signalStrengthLte.rsrp,
-                            cellInfoLte.signalStrengthLte.rsrq,
-                            cellInfoLte.signalStrengthLte.rssnr,
-                            cellInfoLte.signalStrengthLte.cqi,
-                            cellInfoLte.signalStrengthLte.timingAdvance,
-                            false /* isEndcAvailable */);
-                    break;
-                }
-
-                case CellInfoType.WCDMA: {
-                    android.hardware.radio.V1_2.CellInfoWcdma cellInfoWcdma = record.wcdma.get(0);
-                    writeToParcelForWcdma(
-                            p,
-                            cellInfoWcdma.cellIdentityWcdma.base.lac,
-                            cellInfoWcdma.cellIdentityWcdma.base.cid,
-                            cellInfoWcdma.cellIdentityWcdma.base.psc,
-                            cellInfoWcdma.cellIdentityWcdma.base.uarfcn,
-                            cellInfoWcdma.cellIdentityWcdma.base.mcc,
-                            cellInfoWcdma.cellIdentityWcdma.base.mnc,
-                            cellInfoWcdma.cellIdentityWcdma.operatorNames.alphaLong,
-                            cellInfoWcdma.cellIdentityWcdma.operatorNames.alphaShort,
-                            cellInfoWcdma.signalStrengthWcdma.base.signalStrength,
-                            cellInfoWcdma.signalStrengthWcdma.base.bitErrorRate,
-                            cellInfoWcdma.signalStrengthWcdma.rscp,
-                            cellInfoWcdma.signalStrengthWcdma.ecno);
-                    break;
-                }
-
-                case CellInfoType.TD_SCDMA: {
-                    android.hardware.radio.V1_2.CellInfoTdscdma cellInfoTdscdma =
-                            record.tdscdma.get(0);
-                    writeToParcelForTdscdma(
-                            p,
-                            cellInfoTdscdma.cellIdentityTdscdma.base.lac,
-                            cellInfoTdscdma.cellIdentityTdscdma.base.cid,
-                            cellInfoTdscdma.cellIdentityTdscdma.base.cpid,
-                            cellInfoTdscdma.cellIdentityTdscdma.uarfcn,
-                            cellInfoTdscdma.cellIdentityTdscdma.base.mcc,
-                            cellInfoTdscdma.cellIdentityTdscdma.base.mnc,
-                            cellInfoTdscdma.cellIdentityTdscdma.operatorNames.alphaLong,
-                            cellInfoTdscdma.cellIdentityTdscdma.operatorNames.alphaShort,
-                            cellInfoTdscdma.signalStrengthTdscdma.signalStrength,
-                            cellInfoTdscdma.signalStrengthTdscdma.bitErrorRate,
-                            cellInfoTdscdma.signalStrengthTdscdma.rscp);
-                    break;
-                }
-
-                default:
-                    throw new RuntimeException("unexpected cellinfotype: " + record.cellInfoType);
-            }
-
-            p.setDataPosition(0);
-            CellInfo InfoRec = CellInfo.CREATOR.createFromParcel(p);
-            p.recycle();
-            response.add(InfoRec);
+            response.add(CellInfo.create(record));
         }
-
         return response;
     }
 
-    private static int convertTdscdmaRscpTo1_2(int rscp) {
-        // The HAL 1.0 range is 25..120; the ASU/ HAL 1.2 range is 0..96;
-        // yes, this means the range in 1.0 cannot express -24dBm = 96
-        if (rscp >= 25 && rscp <= 120) {
-            // First we flip the sign to convert from the HALs -rscp to the actual RSCP value.
-            int rscpDbm = -rscp;
-            // Then to convert from RSCP to ASU, we apply the offset which aligns 0 ASU to -120dBm.
-            return rscpDbm + 120;
-        }
-        return Integer.MAX_VALUE;
-    }
-
-    /** Convert HAL 1.0 Signal Strength to android SignalStrength */
-    @VisibleForTesting
-    public static SignalStrength convertHalSignalStrength(
-            android.hardware.radio.V1_0.SignalStrength signalStrength) {
-        return new SignalStrength(
-                signalStrength.gw.signalStrength,
-                signalStrength.gw.bitErrorRate,
-                signalStrength.cdma.dbm,
-                signalStrength.cdma.ecio,
-                signalStrength.evdo.dbm,
-                signalStrength.evdo.ecio,
-                signalStrength.evdo.signalNoiseRatio,
-                signalStrength.lte.signalStrength,
-                signalStrength.lte.rsrp,
-                signalStrength.lte.rsrq,
-                signalStrength.lte.rssnr,
-                signalStrength.lte.cqi,
-                convertTdscdmaRscpTo1_2(signalStrength.tdScdma.rscp));
-    }
-
-    /** Convert HAL 1.2 Signal Strength to android SignalStrength */
-    @VisibleForTesting
-    public static SignalStrength convertHalSignalStrength_1_2(
-            android.hardware.radio.V1_2.SignalStrength signalStrength) {
-        return new SignalStrength(
-                signalStrength.gsm.signalStrength,
-                signalStrength.gsm.bitErrorRate,
-                signalStrength.cdma.dbm,
-                signalStrength.cdma.ecio,
-                signalStrength.evdo.dbm,
-                signalStrength.evdo.ecio,
-                signalStrength.evdo.signalNoiseRatio,
-                signalStrength.lte.signalStrength,
-                signalStrength.lte.rsrp,
-                signalStrength.lte.rsrq,
-                signalStrength.lte.rssnr,
-                signalStrength.lte.cqi,
-                signalStrength.tdScdma.rscp,
-                signalStrength.wcdma.base.signalStrength,
-                signalStrength.wcdma.rscp);
-    }
-
     /**
      * @return The {@link IwlanOperationMode IWLAN operation mode}
      */
diff --git a/src/java/com/android/internal/telephony/RadioConfig.java b/src/java/com/android/internal/telephony/RadioConfig.java
index 3706dc1..b47b4f7 100644
--- a/src/java/com/android/internal/telephony/RadioConfig.java
+++ b/src/java/com/android/internal/telephony/RadioConfig.java
@@ -41,6 +41,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.NoSuchElementException;
 import java.util.concurrent.atomic.AtomicLong;
 
 /**
@@ -53,8 +54,16 @@
 
     private static final int EVENT_SERVICE_DEAD = 1;
 
+    private static final HalVersion RADIO_CONFIG_HAL_VERSION_UNKNOWN = new HalVersion(-1, -1);
+
+    private static final HalVersion RADIO_CONFIG_HAL_VERSION_1_0 = new HalVersion(1, 0);
+
+    private static final HalVersion RADIO_CONFIG_HAL_VERSION_1_1 = new HalVersion(1, 1);
+
     private final boolean mIsMobileNetworkSupported;
     private volatile IRadioConfig mRadioConfigProxy = null;
+    // IRadioConfig version
+    private HalVersion mRadioConfigVersion = RADIO_CONFIG_HAL_VERSION_UNKNOWN;
     private final ServiceDeathRecipient mServiceDeathRecipient;
     private final AtomicLong mRadioConfigProxyCookie = new AtomicLong(0);
     private final RadioConfigResponse mRadioConfigResponse;
@@ -166,24 +175,9 @@
             return mRadioConfigProxy;
         }
 
-        try {
-            mRadioConfigProxy = IRadioConfig.getService(true);
-            if (mRadioConfigProxy != null) {
-                mRadioConfigProxy.linkToDeath(mServiceDeathRecipient,
-                        mRadioConfigProxyCookie.incrementAndGet());
-                mRadioConfigProxy.setResponseFunctions(mRadioConfigResponse,
-                        mRadioConfigIndication);
-            } else {
-                loge("getRadioConfigProxy: mRadioConfigProxy == null");
-            }
-        } catch (RemoteException | RuntimeException e) {
-            mRadioConfigProxy = null;
-            loge("getRadioConfigProxy: RadioConfigProxy getService/setResponseFunctions: " + e);
-        }
+        updateRadioConfigProxy();
 
         if (mRadioConfigProxy == null) {
-            // getService() is a blocking call, so this should never happen
-            loge("getRadioConfigProxy: mRadioConfigProxy == null");
             if (result != null) {
                 AsyncResult.forMessage(result, null,
                         CommandException.fromRilErrno(RADIO_NOT_AVAILABLE));
@@ -194,6 +188,42 @@
         return mRadioConfigProxy;
     }
 
+    private void updateRadioConfigProxy() {
+        try {
+            // Try to get service from different versions.
+            try {
+                mRadioConfigProxy = android.hardware.radio.config.V1_1.IRadioConfig.getService(
+                        true);
+                mRadioConfigVersion = RADIO_CONFIG_HAL_VERSION_1_1;
+            } catch (NoSuchElementException e) {
+            }
+
+            if (mRadioConfigProxy == null) {
+                try {
+                    mRadioConfigProxy = android.hardware.radio.config.V1_0
+                            .IRadioConfig.getService(true);
+                    mRadioConfigVersion = RADIO_CONFIG_HAL_VERSION_1_0;
+                } catch (NoSuchElementException e) {
+                }
+            }
+
+            if (mRadioConfigProxy == null) {
+                loge("getRadioConfigProxy: mRadioConfigProxy == null");
+                return;
+            }
+
+            // Link to death recipient and set response. If fails, set proxy to null and return.
+            mRadioConfigProxy.linkToDeath(mServiceDeathRecipient,
+                    mRadioConfigProxyCookie.incrementAndGet());
+            mRadioConfigProxy.setResponseFunctions(mRadioConfigResponse,
+                    mRadioConfigIndication);
+        } catch (RemoteException | RuntimeException e) {
+            mRadioConfigProxy = null;
+            loge("getRadioConfigProxy: RadioConfigProxy setResponseFunctions: " + e);
+            return;
+        }
+    }
+
     private RILRequest obtainRequest(int request, Message result, WorkSource workSource) {
         RILRequest rr = RILRequest.obtain(request, result, workSource);
         synchronized (mRequestList) {
diff --git a/src/java/com/android/internal/telephony/RadioConfigIndication.java b/src/java/com/android/internal/telephony/RadioConfigIndication.java
index 5774bb1..39af57b 100644
--- a/src/java/com/android/internal/telephony/RadioConfigIndication.java
+++ b/src/java/com/android/internal/telephony/RadioConfigIndication.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.hardware.radio.config.V1_0.IRadioConfigIndication;
+import android.hardware.radio.config.V1_2.IRadioConfigIndication;
 import android.os.AsyncResult;
 import android.telephony.Rlog;
 
diff --git a/src/java/com/android/internal/telephony/RadioConfigResponse.java b/src/java/com/android/internal/telephony/RadioConfigResponse.java
index 1d78af4..3b333ae 100644
--- a/src/java/com/android/internal/telephony/RadioConfigResponse.java
+++ b/src/java/com/android/internal/telephony/RadioConfigResponse.java
@@ -18,6 +18,7 @@
 
 import android.hardware.radio.V1_0.RadioError;
 import android.hardware.radio.V1_0.RadioResponseInfo;
+import android.hardware.radio.config.V1_1.PhoneCapability;
 import android.hardware.radio.config.V1_2.IRadioConfigResponse;
 import android.telephony.Rlog;
 
@@ -110,5 +111,16 @@
         }
     }
 
+    /**
+     * Response function for IRadioConfig.getPhoneCapability().
+     */
+    public void getPhoneCapabilityResponse(RadioResponseInfo info,
+            PhoneCapability phoneCapability) {
+    }
 
+    /**
+     * Response function for IRadioConfig.setPreferredDataModem().
+     */
+    public void setPreferredDataModemResponse(RadioResponseInfo info) {
+    }
 }
diff --git a/src/java/com/android/internal/telephony/RadioIndication.java b/src/java/com/android/internal/telephony/RadioIndication.java
index f2214d6..e097212 100644
--- a/src/java/com/android/internal/telephony/RadioIndication.java
+++ b/src/java/com/android/internal/telephony/RadioIndication.java
@@ -25,6 +25,7 @@
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CELL_INFO_LIST;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_DATA_CALL_LIST_CHANGED;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_EMERGENCY_NUMBER_LIST;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_HARDWARE_CONFIG_CHANGED;
@@ -92,6 +93,7 @@
 import android.telephony.SignalStrength;
 import android.telephony.SmsMessage;
 import android.telephony.TelephonyManager;
+import android.telephony.emergency.EmergencyNumber;
 
 import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
 import com.android.internal.telephony.cdma.CdmaInformationRecords;
@@ -229,7 +231,7 @@
                                       android.hardware.radio.V1_0.SignalStrength signalStrength) {
         mRil.processIndication(indicationType);
 
-        SignalStrength ss = RIL.convertHalSignalStrength(signalStrength);
+        SignalStrength ss = new SignalStrength(signalStrength);
         // Note this is set to "verbose" because it happens frequently
         if (RIL.RILJ_LOGV) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss);
 
@@ -261,7 +263,7 @@
                                       android.hardware.radio.V1_2.SignalStrength signalStrength) {
         mRil.processIndication(indicationType);
 
-        SignalStrength ss = RIL.convertHalSignalStrength_1_2(signalStrength);
+        SignalStrength ss = new SignalStrength(signalStrength);
         // Note this is set to "verbose" because it happens frequently
         if (RIL.RILJ_LOGV) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss);
 
@@ -306,6 +308,27 @@
                 new AsyncResult(null, response, null));
     }
 
+    /**
+     * Indicates current emergency number list.
+     */
+    public void currentEmergencyNumberList(int indicationType,
+            ArrayList<android.hardware.radio.V1_4.EmergencyNumber> emergencyNumberList) {
+        List<EmergencyNumber> response = new ArrayList<>(emergencyNumberList.size());
+
+        for (android.hardware.radio.V1_4.EmergencyNumber emergencyNumberHal
+                : emergencyNumberList) {
+            EmergencyNumber emergencyNumber = new EmergencyNumber(emergencyNumberHal.number,
+                    MccTable.countryCodeForMcc(emergencyNumberHal.mcc), emergencyNumberHal.mnc,
+                    emergencyNumberHal.categories, emergencyNumberHal.sources);
+            response.add(emergencyNumber);
+        }
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_EMERGENCY_NUMBER_LIST, response);
+
+        mRil.mEmergencyNumberListRegistrants.notifyRegistrants(
+                new AsyncResult(null, response, null));
+    }
+
     public void dataCallListChanged(int indicationType, ArrayList<SetupDataCallResult> dcList) {
         mRil.processIndication(indicationType);
 
@@ -672,7 +695,6 @@
         // Initial conditions
         mRil.setRadioPower(false, null);
         mRil.setCdmaSubscriptionSource(mRil.mCdmaSubscription, null);
-        mRil.setCellInfoListRate();
         // todo: this should not require a version number now. Setting it to latest RIL version for
         // now.
         mRil.notifyRegistrantsRilConnectionChanged(15);
diff --git a/src/java/com/android/internal/telephony/RadioResponse.java b/src/java/com/android/internal/telephony/RadioResponse.java
index af6dcc3..7057612 100644
--- a/src/java/com/android/internal/telephony/RadioResponse.java
+++ b/src/java/com/android/internal/telephony/RadioResponse.java
@@ -42,6 +42,7 @@
 import android.telephony.ModemActivityInfo;
 import android.telephony.NeighboringCellInfo;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.RadioAccessFamily;
 import android.telephony.SignalStrength;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -349,6 +350,24 @@
 
     /**
      * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param dataRegResponse Current Data registration response as defined by DataRegStateResult in
+     *        1.4/types.hal
+     */
+    public void getDataRegistrationStateResponse_1_4(RadioResponseInfo responseInfo,
+            android.hardware.radio.V1_4.DataRegStateResult dataRegResponse) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            if (responseInfo.error == RadioError.NONE) {
+                sendMessageResponse(rr.mResult, dataRegResponse);
+            }
+            mRil.processResponseDone(rr, responseInfo, dataRegResponse);
+        }
+    }
+
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
      * @param longName is long alpha ONS or EONS or empty string if unregistered
      * @param shortName is short alpha ONS or EONS or empty string if unregistered
      * @param numeric is 5 or 6 digit numeric code (MCC + MNC) or empty string if unregistered
@@ -727,6 +746,14 @@
     }
 
     /**
+     * Callback of setPreferredNetworkTypeBitmap defined in IRadio.hal.
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setPreferredNetworkTypeBitmapResponse(RadioResponseInfo responseInfo) {
+        responseVoid(responseInfo);
+    }
+
+    /**
      *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param nwType RadioPreferredNetworkType defined in types.hal
@@ -737,6 +764,19 @@
     }
 
     /**
+     * Callback of the getPreferredNetworkTypeBitmap defined in the IRadio.hal.
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param networkTypeBitmap a 32-bit bitmap of
+     * {@link android.telephony.TelephonyManager.NetworkTypeBitMask}.
+     */
+    public void getPreferredNetworkTypeBitmapResponse(
+            RadioResponseInfo responseInfo, int networkTypeBitmap) {
+        int networkType = RadioAccessFamily.getNetworkTypeFromRaf(networkTypeBitmap);
+        mRil.mPreferredNetworkType = networkType;
+        responseInts(responseInfo, networkType);
+    }
+
+    /**
      *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param cells Vector of neighboring radio cell information
@@ -1468,6 +1508,13 @@
         }
     }
 
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void emergencyDialResponse(RadioResponseInfo responseInfo) {
+        responseVoid(responseInfo);
+    }
+
     private void responseInts(RadioResponseInfo responseInfo, int ...var) {
         final ArrayList<Integer> ints = new ArrayList<>();
         for (int i = 0; i < var.length; i++) {
@@ -1720,7 +1767,7 @@
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
-            SignalStrength ret = RIL.convertHalSignalStrength(signalStrength);
+            SignalStrength ret = new SignalStrength(signalStrength);
             if (responseInfo.error == RadioError.NONE) {
                 sendMessageResponse(rr.mResult, ret);
             }
@@ -1734,7 +1781,7 @@
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
-            SignalStrength ret = RIL.convertHalSignalStrength_1_2(signalStrength);
+            SignalStrength ret = new SignalStrength(signalStrength);
             if (responseInfo.error == RadioError.NONE) {
                 sendMessageResponse(rr.mResult, ret);
             }
diff --git a/src/java/com/android/internal/telephony/RatRatcheter.java b/src/java/com/android/internal/telephony/RatRatcheter.java
index 6b76414..59078a4 100644
--- a/src/java/com/android/internal/telephony/RatRatcheter.java
+++ b/src/java/com/android/internal/telephony/RatRatcheter.java
@@ -111,6 +111,10 @@
             mDataRatchetEnabled = false;
             return;
         }
+
+        boolean newUsingCA = oldSS.isUsingCarrierAggregation()
+                || newSS.isUsingCarrierAggregation()
+                || newSS.getCellBandwidths().length > 1;
         if (mVoiceRatchetEnabled) {
             int newVoiceRat = ratchetRat(oldSS.getRilVoiceRadioTechnology(),
                     newSS.getRilVoiceRadioTechnology());
@@ -129,9 +133,6 @@
             mDataRatchetEnabled = true;
         }
 
-        boolean newUsingCA = oldSS.isUsingCarrierAggregation()
-                || newSS.isUsingCarrierAggregation()
-                || newSS.getCellBandwidths().length > 1;
         newSS.setIsUsingCarrierAggregation(newUsingCA);
     }
 
diff --git a/src/java/com/android/internal/telephony/RcsController.java b/src/java/com/android/internal/telephony/RcsController.java
deleted file mode 100644
index e04b4b6..0000000
--- a/src/java/com/android/internal/telephony/RcsController.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-import android.content.Context;
-import android.os.ServiceManager;
-import android.telephony.Rlog;
-import android.telephony.rcs.RcsManager;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.rcs.IRcs;
-
-/** Backing implementation of {@link RcsManager}. */
-public class RcsController extends IRcs.Stub {
-    private static final String TAG = "RcsController";
-    private static final String RCS_SERVICE_NAME = "ircs";
-
-    private static RcsController sInstance;
-
-    private final Context mContext;
-
-    /** Initialize the instance. Should only be called once. */
-    public static RcsController init(Context context) {
-        synchronized (RcsController.class) {
-            if (sInstance == null) {
-                sInstance = new RcsController(context);
-            } else {
-                Rlog.e(TAG, "init() called multiple times! sInstance = " + sInstance);
-            }
-        }
-        return sInstance;
-    }
-
-    private RcsController(Context context) {
-        mContext = context;
-        if (ServiceManager.getService(RCS_SERVICE_NAME) == null) {
-            ServiceManager.addService(RCS_SERVICE_NAME, this);
-        }
-    }
-
-    @VisibleForTesting
-    public RcsController(Context context, Void unused) {
-        mContext = context;
-    }
-
-    @Override
-    public void deleteThread(int threadId) {
-        // TODO - add implementation
-    }
-
-    @Override
-    public int getMessageCount(int rcsThreadId) {
-        // TODO - add implementation. Return a magic number for now to test the RPC calls
-        return 1018;
-    }
-}
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index 1d29516..c94a36d 100644
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -34,6 +34,7 @@
 import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.hardware.radio.V1_0.CellInfoType;
+import android.net.NetworkCapabilities;
 import android.os.AsyncResult;
 import android.os.BaseBundle;
 import android.os.Build;
@@ -50,6 +51,7 @@
 import android.provider.Settings;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
+import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.CarrierConfigManager;
 import android.telephony.CellIdentity;
 import android.telephony.CellIdentityCdma;
@@ -82,6 +84,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
 import com.android.internal.telephony.cdma.EriInfo;
+import com.android.internal.telephony.dataconnection.DataConnection;
 import com.android.internal.telephony.dataconnection.DcTracker;
 import com.android.internal.telephony.dataconnection.TransportManager;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
@@ -129,13 +132,13 @@
     private ServiceState mNewSS;
 
     // This is the minimum interval at which CellInfo requests will be serviced by the modem.
-    // Any requests that arrive within MAX_AGE of the previous reuqest will simply receive the
+    // Any requests that arrive within MinInterval of the previous reuqest will simply receive the
     // cached result. This is a power-saving feature, because requests to the modem may require
     // wakeup of a separate chip and bus communication. Because the cost of wakeups is
     // architecture dependent, it would be preferable if this sort of optimization could be
     // handled in SoC-specific code, but for now, keep it here to ensure that in case further
     // optimizations are not present elsewhere, there is a power-management scheme of last resort.
-    private static final long LAST_CELL_INFO_LIST_MAX_AGE_MS = 2000;
+    private int mCellInfoMinIntervalMs =  2000;
 
     // Maximum time to wait for a CellInfo request before assuming it won't arrive and returning
     // null to callers. Note, that if a CellInfo response does arrive later, then it will be
@@ -446,8 +449,7 @@
                 updateSpnDisplay();
             } else if (intent.getAction().equals(ACTION_RADIO_OFF)) {
                 mAlarmSwitch = false;
-                DcTracker dcTracker = mPhone.mDcTracker;
-                powerOffRadioSafely(dcTracker);
+                powerOffRadioSafely();
             }
         }
     };
@@ -496,7 +498,9 @@
     private static final int INVALID_LTE_EARFCN = -1;
 
     public ServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) {
-        mNitzState = TelephonyComponentFactory.getInstance().makeNitzStateMachine(phone);
+        mNitzState = TelephonyComponentFactory.getInstance()
+                .inject(NitzStateMachine.class.getName())
+                .makeNitzStateMachine(phone);
         mPhone = phone;
         mCi = ci;
 
@@ -524,9 +528,9 @@
             mRegStateManagers.get(transportType).registerForNetworkRegistrationStateChanged(
                     this, EVENT_NETWORK_STATE_CHANGED, null);
         }
-
-        mLocaleTracker = TelephonyComponentFactory.getInstance().makeLocaleTracker(
-                mPhone, mNitzState, getLooper());
+        mLocaleTracker = TelephonyComponentFactory.getInstance()
+                .inject(LocaleTracker.class.getName())
+                .makeLocaleTracker(mPhone, mNitzState, getLooper());
 
         mCi.registerForImsNetworkStateChanged(this, EVENT_IMS_STATE_CHANGED, null);
         mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
@@ -579,6 +583,7 @@
 
     @VisibleForTesting
     public void updatePhoneType() {
+
         // If we are previously voice roaming, we need to notify that roaming status changed before
         // we change back to non-roaming.
         if (mSS != null && mSS.getVoiceRoaming()) {
@@ -617,6 +622,7 @@
         mNitzState.handleNetworkCountryCodeUnavailable();
         mCellIdentity = null;
         mNewCellIdentity = null;
+        mRuimRecordsLoaded = false;
 
         //cancel any pending pollstate request on voice tech switching
         cancelPollState();
@@ -1438,9 +1444,16 @@
                     }
                     mPhone.notifyPhysicalChannelConfiguration(list);
                     mLastPhysicalChannelConfigList = list;
+                    boolean hasChanged =
+                            updateNrFrequencyRangeFromPhysicalChannelConfigs(list, mSS);
+                    hasChanged |= updateNrStatusFromPhysicalChannelConfigs(
+                            list,
+                            mSS.getNetworkRegistrationState(
+                                    NetworkRegistrationState.DOMAIN_PS, AccessNetworkType.EUTRAN));
 
-                    // only notify if bandwidths changed
-                    if (RatRatcheter.updateBandwidths(getBandwidthsFromConfigs(list), mSS)) {
+                    // Notify NR frequency, NR connection status or bandwidths changed.
+                    if (hasChanged
+                            || RatRatcheter.updateBandwidths(getBandwidthsFromConfigs(list), mSS)) {
                         mPhone.notifyServiceStateChanged(mSS);
                     }
                 }
@@ -1812,6 +1825,78 @@
         return cdmaRoaming && !isSameOperatorNameFromSimAndSS(s);
     }
 
+    private boolean isNrStatusChanged(
+            NetworkRegistrationState oldRegState, NetworkRegistrationState newRegState) {
+        if (oldRegState == null || newRegState == null) {
+            return oldRegState != newRegState;
+        }
+
+        return oldRegState.getNrStatus() != newRegState.getNrStatus();
+    }
+
+    private boolean updateNrFrequencyRangeFromPhysicalChannelConfigs(
+            List<PhysicalChannelConfig> physicalChannelConfigs, ServiceState ss) {
+        int newFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN;
+
+        if (physicalChannelConfigs != null) {
+            DcTracker dcTracker = mPhone.getDcTracker(TransportType.WWAN);
+            for (PhysicalChannelConfig config : physicalChannelConfigs) {
+                if (isNrPhysicalChannelConfig(config)) {
+                    // Update the frequency range of the NR parameters if there is an internet data
+                    // connection associate to this NR physical channel channel config.
+                    int[] contextIds = config.getContextIds();
+                    for (int cid : contextIds) {
+                        DataConnection dc = dcTracker.getDataConnectionByContextId(cid);
+                        if (dc != null && dc.getNetworkCapabilities().hasCapability(
+                                NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
+                            newFrequencyRange = ServiceState.getBetterNRFrequencyRange(
+                                    newFrequencyRange, config.getFrequencyRange());
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        boolean hasChanged = newFrequencyRange != ss.getNrFrequencyRange();
+        ss.setNrFrequencyRange(newFrequencyRange);
+        return hasChanged;
+    }
+
+    private boolean updateNrStatusFromPhysicalChannelConfigs(
+            List<PhysicalChannelConfig> configs, NetworkRegistrationState regState) {
+
+        if (regState == null || configs == null) return false;
+
+        boolean hasNrSecondaryServingCell = false;
+        for (PhysicalChannelConfig config : configs) {
+            if (isNrPhysicalChannelConfig(config) && config.getConnectionStatus()
+                    == PhysicalChannelConfig.CONNECTION_SECONDARY_SERVING) {
+                hasNrSecondaryServingCell = true;
+                break;
+            }
+        }
+
+        int newNrStatus = regState.getNrStatus();
+        if (hasNrSecondaryServingCell) {
+            if (regState.getNrStatus() == NetworkRegistrationState.NR_STATUS_NOT_RESTRICTED) {
+                newNrStatus = NetworkRegistrationState.NR_STATUS_CONNECTED;
+            }
+        } else {
+            if (regState.getNrStatus() == NetworkRegistrationState.NR_STATUS_CONNECTED) {
+                newNrStatus = NetworkRegistrationState.NR_STATUS_NOT_RESTRICTED;
+            }
+        }
+
+        boolean hasChanged = newNrStatus != regState.getNrStatus();
+        regState.setNrStatus(newNrStatus);
+        return hasChanged;
+    }
+
+    private boolean isNrPhysicalChannelConfig(PhysicalChannelConfig config) {
+        return config.getRat() == TelephonyManager.NETWORK_TYPE_NR;
+    }
+
     void handlePollStateResultMessage(int what, AsyncResult ar) {
         int ints[];
         switch (what) {
@@ -1904,14 +1989,17 @@
                         networkRegState.getAccessNetworkTechnology());
                 mNewSS.setDataRegState(serviceState);
                 mNewSS.setRilDataRadioTechnology(newDataRat);
-                mNewSS.addNetworkRegistrationState(networkRegState);
 
                 // When we receive OOS reset the PhyChanConfig list so that non-return-to-idle
                 // implementers of PhyChanConfig unsol will not carry forward a CA report
                 // (2 or more cells) to a new cell if they camp for emergency service only.
                 if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) {
                     mLastPhysicalChannelConfigList = null;
+                    updateNrFrequencyRangeFromPhysicalChannelConfigs(null, mNewSS);
                 }
+                updateNrStatusFromPhysicalChannelConfigs(
+                        mLastPhysicalChannelConfigList, networkRegState);
+                mNewSS.addNetworkRegistrationState(networkRegState);
                 setPhyCellInfoFromCellIdentity(mNewSS, networkRegState.getCellIdentity());
 
                 if (mPhone.isPhoneTypeGsm()) {
@@ -2592,12 +2680,10 @@
                     am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                             SystemClock.elapsedRealtime() + 3000, mRadioOffIntent);
                 } else {
-                    DcTracker dcTracker = mPhone.mDcTracker;
-                    powerOffRadioSafely(dcTracker);
+                    powerOffRadioSafely();
                 }
             } else {
-                DcTracker dcTracker = mPhone.mDcTracker;
-                powerOffRadioSafely(dcTracker);
+                powerOffRadioSafely();
             }
         } else if (mDeviceShuttingDown
                 && (mCi.getRadioState() != TelephonyManager.RADIO_POWER_UNAVAILABLE)) {
@@ -2852,6 +2938,15 @@
         boolean hasVoiceRegStateChanged =
                 mSS.getVoiceRegState() != mNewSS.getVoiceRegState();
 
+        boolean hasNrFrequencyRangeChanged =
+                mSS.getNrFrequencyRange() != mNewSS.getNrFrequencyRange();
+
+        boolean hasNrStatusChanged = isNrStatusChanged(
+                mSS.getNetworkRegistrationState(
+                        NetworkRegistrationState.DOMAIN_PS, AccessNetworkType.EUTRAN),
+                mNewSS.getNetworkRegistrationState(
+                        NetworkRegistrationState.DOMAIN_PS, AccessNetworkType.EUTRAN));
+
         // TODO: loosen this restriction to exempt fields that are provided through system
         // information; otherwise, we will get false positives when things like the operator
         // alphas are provided later - that's better than missing location changes, but
@@ -2915,23 +3010,25 @@
 
         if (DBG) {
             log("pollStateDone:"
-                    + " hasRegistered=" + hasRegistered
-                    + " hasDeregistered=" + hasDeregistered
-                    + " hasDataAttached=" + hasDataAttached
-                    + " hasDataDetached=" + hasDataDetached
-                    + " hasDataRegStateChanged=" + hasDataRegStateChanged
-                    + " hasRilVoiceRadioTechnologyChanged= " + hasRilVoiceRadioTechnologyChanged
-                    + " hasRilDataRadioTechnologyChanged=" + hasRilDataRadioTechnologyChanged
-                    + " hasChanged=" + hasChanged
-                    + " hasVoiceRoamingOn=" + hasVoiceRoamingOn
-                    + " hasVoiceRoamingOff=" + hasVoiceRoamingOff
-                    + " hasDataRoamingOn=" + hasDataRoamingOn
-                    + " hasDataRoamingOff=" + hasDataRoamingOff
-                    + " hasLocationChanged=" + hasLocationChanged
+                    + " hasRegistered = " + hasRegistered
+                    + " hasDeregistered = " + hasDeregistered
+                    + " hasDataAttached = " + hasDataAttached
+                    + " hasDataDetached = " + hasDataDetached
+                    + " hasDataRegStateChanged = " + hasDataRegStateChanged
+                    + " hasRilVoiceRadioTechnologyChanged = " + hasRilVoiceRadioTechnologyChanged
+                    + " hasRilDataRadioTechnologyChanged = " + hasRilDataRadioTechnologyChanged
+                    + " hasChanged = " + hasChanged
+                    + " hasVoiceRoamingOn = " + hasVoiceRoamingOn
+                    + " hasVoiceRoamingOff = " + hasVoiceRoamingOff
+                    + " hasDataRoamingOn =" + hasDataRoamingOn
+                    + " hasDataRoamingOff = " + hasDataRoamingOff
+                    + " hasLocationChanged = " + hasLocationChanged
                     + " has4gHandoff = " + has4gHandoff
-                    + " hasMultiApnSupport=" + hasMultiApnSupport
-                    + " hasLostMultiApnSupport=" + hasLostMultiApnSupport
-                    + " hasCssIndicatorChanged=" + hasCssIndicatorChanged);
+                    + " hasMultiApnSupport = " + hasMultiApnSupport
+                    + " hasLostMultiApnSupport = " + hasLostMultiApnSupport
+                    + " hasCssIndicatorChanged = " + hasCssIndicatorChanged
+                    + " hasNrFrequencyRangeChanged = " + hasNrFrequencyRangeChanged
+                    + " hasNrStatusChanged = " + hasNrStatusChanged);
         }
 
         // Add an event log when connection state changes
@@ -2966,7 +3063,7 @@
             }
 
             if (hasCssIndicatorChanged) {
-                mPhone.notifyDataConnection(Phone.REASON_CSS_INDICATOR_CHANGED);
+                mPhone.notifyDataConnection();
             }
 
             mReasonDataDenied = mNewReasonDataDenied;
@@ -3094,7 +3191,6 @@
         if (hasRilDataRadioTechnologyChanged || hasRilVoiceRadioTechnologyChanged) {
             logRatChange();
 
-            updateRatTypeForSignalStrength();
             notifySignalStrength();
         }
 
@@ -3104,13 +3200,7 @@
 
         if (hasDataRegStateChanged || hasRilDataRadioTechnologyChanged) {
             notifyDataRegStateRilRadioTechnologyChanged();
-
-            if (ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
-                    == mSS.getRilDataRadioTechnology()) {
-                mPhone.notifyDataConnection(Phone.REASON_IWLAN_AVAILABLE);
-            } else {
-                mPhone.notifyDataConnection(null);
-            }
+            mPhone.notifyDataConnection();
         }
 
         if (hasVoiceRoamingOn || hasVoiceRoamingOff || hasDataRoamingOn || hasDataRoamingOff) {
@@ -4063,12 +4153,12 @@
      *
      * Hang up the existing voice calls to decrease call drop rate.
      */
-    public void powerOffRadioSafely(DcTracker dcTracker) {
+    public void powerOffRadioSafely() {
         synchronized (this) {
             if (!mPendingRadioPowerOffAfterDataOff) {
                 // To minimize race conditions we call cleanUpAllConnections on
                 // both if else paths instead of before this isDisconnected test.
-                if (dcTracker.isDisconnected()) {
+                if (mPhone.areAllDataDisconnected()) {
                     // To minimize race conditions we do this after isDisconnected
                     if (DBG) log("Data disconnected, turn off radio right away.");
                     hangupAndPowerOff();
@@ -4083,9 +4173,14 @@
                     // Data is not disconnected. Wait for the data disconnect complete
                     // before sending the RADIO_POWER off.
                     ProxyController.getInstance().registerForAllDataDisconnected(
-                            mPhone.getSubId(), this, EVENT_ALL_DATA_DISCONNECTED, null);
+                            mPhone.getSubId(), this, EVENT_ALL_DATA_DISCONNECTED);
                     mPendingRadioPowerOffAfterDataOff = true;
-                    dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF);
+                    for (int transport : mTransportManager.getAvailableTransports()) {
+                        if (mPhone.getDcTracker(transport) != null) {
+                            mPhone.getDcTracker(transport).cleanUpAllConnections(
+                                    Phone.REASON_RADIO_TURNED_OFF);
+                        }
+                    }
 
                     Message msg = Message.obtain(this);
                     msg.what = EVENT_SET_RADIO_POWER_OFF;
@@ -4243,53 +4338,19 @@
 
         if ((ar.exception == null) && (ar.result != null)) {
             mSignalStrength = (SignalStrength) ar.result;
-            mSignalStrength.validateInput();
-            mSignalStrength.setLteRsrpBoost(mSS.getLteEarfcnRsrpBoost());
 
             PersistableBundle config = getCarrierConfig();
-            mSignalStrength.setUseOnlyRsrpForLteLevel(config.getBoolean(
-                    CarrierConfigManager.KEY_USE_ONLY_RSRP_FOR_LTE_SIGNAL_BAR_BOOL));
-            mSignalStrength.setLteRsrpThresholds(config.getIntArray(
-                    CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY));
-            mSignalStrength.setWcdmaDefaultSignalMeasurement(config.getString(
-                    CarrierConfigManager.KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING));
-            mSignalStrength.setWcdmaRscpThresholds(config.getIntArray(
-                    CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY));
+            mSignalStrength.updateLevel(config, mSS);
         } else {
             log("onSignalStrengthResult() Exception from RIL : " + ar.exception);
-            mSignalStrength = new SignalStrength(true);
+            mSignalStrength = new SignalStrength();
         }
 
-        updateRatTypeForSignalStrength();
         boolean ssChanged = notifySignalStrength();
 
         return ssChanged;
     }
 
-    private void updateRatTypeForSignalStrength() {
-        if (mSignalStrength != null) {
-            boolean isGsm = false;
-            int dataRat = mSS.getRilDataRadioTechnology();
-            int voiceRat = mSS.getRilVoiceRadioTechnology();
-
-            // Override isGsm based on currently camped data and voice RATs
-            // Set isGsm to true if the RAT belongs to GSM family and not IWLAN
-            if ((dataRat != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
-                    && ServiceState.isGsm(dataRat))
-                    || (voiceRat != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
-                    && ServiceState.isGsm(voiceRat))) {
-                isGsm = true;
-            }
-
-            if (dataRat == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN
-                    && voiceRat == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
-                mSignalStrength.fixType();
-            } else {
-                mSignalStrength.setGsm(isGsm);
-            }
-        }
-    }
-
     /**
      * Hang up all voice call and turn off radio. Implemented by derived class.
      */
@@ -4352,6 +4413,11 @@
         return mLastCellInfoList;
     }
 
+    /** Set the minimum time between CellInfo requests to the modem, in milliseconds */
+    public void setCellInfoMinInterval(int interval) {
+        mCellInfoMinIntervalMs = interval;
+    }
+
     /**
      * Request the latest CellInfo from the modem.
      *
@@ -4379,7 +4445,7 @@
             // Check to see whether the elapsed time is sufficient for a new request; if not, then
             // return the result of the last request (if expected).
             final long curTime = SystemClock.elapsedRealtime();
-            if ((curTime - mLastCellInfoReqTime) < LAST_CELL_INFO_LIST_MAX_AGE_MS) {
+            if ((curTime - mLastCellInfoReqTime) < mCellInfoMinIntervalMs) {
                 if (rspMsg != null) {
                     if (DBG) log("SST.requestAllCellInfo(): return last, back to back calls");
                     AsyncResult.forMessage(rspMsg, mLastCellInfoList, null);
@@ -4561,6 +4627,7 @@
         pw.println(" mDeviceShuttingDown=" + mDeviceShuttingDown);
         pw.println(" mSpnUpdatePending=" + mSpnUpdatePending);
         pw.println(" mLteRsrpBoost=" + mLteRsrpBoost);
+        pw.println(" mCellInfoMinIntervalMs=" + mCellInfoMinIntervalMs);
         dumpEarfcnPairList(pw);
 
         mLocaleTracker.dump(fd, pw, args);
@@ -4752,7 +4819,7 @@
     }
 
     private void setSignalStrengthDefaultValues() {
-        mSignalStrength = new SignalStrength(true);
+        mSignalStrength = new SignalStrength();
     }
 
     protected String getHomeOperatorNumeric() {
diff --git a/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java b/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java
index 32edb9c..516ca3f 100644
--- a/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java
+++ b/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java
@@ -165,7 +165,8 @@
             while (cursor.moveToNext()) {
                 InboundSmsTracker tracker;
                 try {
-                    tracker = TelephonyComponentFactory.getInstance().makeInboundSmsTracker(cursor,
+                    tracker = TelephonyComponentFactory.getInstance()
+                            .inject(InboundSmsTracker.class.getName()).makeInboundSmsTracker(cursor,
                             isCurrentFormat3gpp2);
                 } catch (IllegalArgumentException e) {
                     Rlog.e(TAG, "error loading SmsTracker: " + e);
diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java
index 0568e8d..0789c5e 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -19,8 +19,10 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
+import android.app.PendingIntent;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -301,12 +303,17 @@
                 SubscriptionManager.MCC_STRING));
         String mnc = cursor.getString(cursor.getColumnIndexOrThrow(
                 SubscriptionManager.MNC_STRING));
+        // cardId is the private ICCID/EID string, also known as the card string
         String cardId = cursor.getString(cursor.getColumnIndexOrThrow(
                 SubscriptionManager.CARD_ID));
-        // FIXME: consider stick this into database too
-        String countryIso = getSubscriptionCountryIso(id);
+        String countryIso = cursor.getString(cursor.getColumnIndexOrThrow(
+                SubscriptionManager.ISO_COUNTRY_CODE));
+        // publicCardId is the publicly exposed int card ID
+        int publicCardId = UiccController.getInstance().convertToPublicCardId(cardId);
         boolean isEmbedded = cursor.getInt(cursor.getColumnIndexOrThrow(
                 SubscriptionManager.IS_EMBEDDED)) == 1;
+        int carrierId = cursor.getInt(cursor.getColumnIndexOrThrow(
+                SubscriptionManager.CARRIER_ID));
         UiccAccessRule[] accessRules;
         if (isEmbedded) {
             accessRules = UiccAccessRule.decodeRules(cursor.getBlob(
@@ -320,17 +327,21 @@
                 SubscriptionManager.GROUP_UUID));
         boolean isMetered = cursor.getInt(cursor.getColumnIndexOrThrow(
                 SubscriptionManager.IS_METERED)) == 1;
+        int profileClass = cursor.getInt(cursor.getColumnIndexOrThrow(
+                SubscriptionManager.PROFILE_CLASS));
 
         if (VDBG) {
             String iccIdToPrint = SubscriptionInfo.givePrintableIccid(iccId);
             String cardIdToPrint = SubscriptionInfo.givePrintableIccid(cardId);
             logd("[getSubInfoRecord] id:" + id + " iccid:" + iccIdToPrint + " simSlotIndex:"
-                    + simSlotIndex + " displayName:" + displayName + " nameSource:" + nameSource
-                    + " iconTint:" + iconTint + " dataRoaming:" + dataRoaming
-                    + " mcc:" + mcc + " mnc:" + mnc + " countIso:" + countryIso + " isEmbedded:"
+                    + simSlotIndex + " carrierid:" + carrierId + " displayName:" + displayName
+                    + " nameSource:" + nameSource + " iconTint:" + iconTint
+                    + " dataRoaming:" + dataRoaming + " mcc:" + mcc + " mnc:" + mnc
+                    + " countIso:" + countryIso + " isEmbedded:"
                     + isEmbedded + " accessRules:" + Arrays.toString(accessRules)
-                    + " cardId:" + cardIdToPrint + " isOpportunistic:" + isOpportunistic
-                    + " groupUUID:" + groupUUID + " isMetered:" + isMetered);
+                    + " cardId:" + cardIdToPrint + " publicCardId:" + publicCardId
+                    + " isOpportunistic:" + isOpportunistic + " groupUUID:" + groupUUID
+                    + " isMetered:" + isMetered + " profileClass:" + profileClass);
         }
 
         // If line1number has been set to a different number, use it instead.
@@ -339,22 +350,9 @@
             number = line1Number;
         }
         return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
-                nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
-                isEmbedded, accessRules, cardId, isOpportunistic, groupUUID, isMetered);
-    }
-
-    /**
-     * Get ISO country code for the subscription's provider
-     *
-     * @param subId The subscription ID
-     * @return The ISO country code for the subscription's provider
-     */
-    private String getSubscriptionCountryIso(int subId) {
-        final int phoneId = getPhoneId(subId);
-        if (phoneId < 0) {
-            return "";
-        }
-        return mTelephonyManager.getSimCountryIsoForPhone(phoneId);
+            nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
+            isEmbedded, accessRules, cardId, publicCardId, isOpportunistic, groupUUID,
+            isMetered, false /* isGroupDisabled */, carrierId, profileClass);
     }
 
     /**
@@ -629,7 +627,7 @@
             return;
         }
 
-        boolean opptSubListChanged = false;
+        boolean opptSubListChanged;
 
         synchronized (mSubInfoListLock) {
             mCacheActiveSubInfoList.clear();
@@ -1354,6 +1352,39 @@
     }
 
     /**
+     * Set carrier id by subId
+     * @param carrierId the subscription carrier id.
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     *
+     * @see TelephonyManager#getSimCarrierId()
+     */
+    public int setCarrierId(int carrierId, int subId) {
+        if (DBG) logd("[setCarrierId]+ carrierId:" + carrierId + " subId:" + subId);
+
+        enforceModifyPhoneState("setCarrierId");
+
+        // Now that all security checks passes, perform the operation as ourselves.
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            validateSubId(subId);
+            ContentValues value = new ContentValues(1);
+            value.put(SubscriptionManager.CARRIER_ID, carrierId);
+            int result = mContext.getContentResolver().update(
+                    SubscriptionManager.getUriForSubscriptionId(subId), value, null, null);
+
+            // Refresh the Cache of Active Subscription Info List
+            refreshCachedActiveSubscriptionInfoList();
+
+            notifySubscriptionInfoChanged();
+
+            return result;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
      * Set MCC/MNC by subscription ID
      * @param mccMnc MCC/MNC associated with the subscription
      * @param subId the unique SubInfoRecord index in database
@@ -1388,6 +1419,27 @@
         return result;
     }
 
+    /**
+     * Set ISO country code by subscription ID
+     * @param iso iso country code associated with the subscription
+     * @param subId the unique SubInfoRecord index in database
+     * @return the number of records updated
+     */
+    public int setCountryIso(String iso, int subId) {
+        if (DBG) logd("[setCountryIso]+ iso:" + iso + " subId:" + subId);
+        ContentValues value = new ContentValues();
+        value.put(SubscriptionManager.ISO_COUNTRY_CODE, iso);
+
+        int result = mContext.getContentResolver().update(
+                SubscriptionManager.getUriForSubscriptionId(subId), value, null, null);
+
+        // Refresh the Cache of Active Subscription Info List
+        refreshCachedActiveSubscriptionInfoList();
+
+        notifySubscriptionInfoChanged();
+        return result;
+    }
+
     @Override
     public int getSlotIndex(int subId) {
         if (VDBG) printStackTrace("[getSlotIndex] subId=" + subId);
@@ -1909,20 +1961,14 @@
      * @return the list of subId's that are active, is never null but the length maybe 0.
      */
     @Override
-    public int[] getActiveSubIdList() {
-        Set<Entry<Integer, Integer>> simInfoSet = new HashSet<>(sSlotIndexToSubId.entrySet());
-
-        int[] subIdArr = new int[simInfoSet.size()];
-        int i = 0;
-        for (Entry<Integer, Integer> entry: simInfoSet) {
-            int sub = entry.getValue();
-            subIdArr[i] = sub;
-            i++;
-        }
+    public @NonNull int[] getActiveSubIdList() {
+        int[] subIdArr = sSlotIndexToSubId.keySet().stream()
+                .sorted()
+                .mapToInt(slotId -> sSlotIndexToSubId.get(slotId))
+                .toArray();
 
         if (VDBG) {
-            logdl("[getActiveSubIdList] simInfoSet=" + simInfoSet + " subIdArr.length="
-                    + subIdArr.length);
+            logdl("[getActiveSubIdList] subIdArr=" + Arrays.toString(subIdArr));
         }
         return subIdArr;
     }
@@ -2299,95 +2345,220 @@
      * Being in the same group means they might be activated or deactivated
      * together, some of them may be invisible to the users, etc.
      *
-     * Caller will either have {@link android.Manifest.permission.MODIFY_PHONE_STATE}
-     * permission or can manage all subscriptions in the list, according to their
-     * access rules.
+     * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+     * permission or had carrier privilege permission on the subscriptions:
+     * {@link TelephonyManager#hasCarrierPrivileges(int)} or
+     * {@link SubscriptionManager#canManageSubscription(SubscriptionInfo)}
      *
+     * @throws SecurityException if the caller doesn't meet the requirements
+     *             outlined above.
+     *
+     * @param subIdList list of subId that will be in the same group
      * @return groupUUID a UUID assigned to the subscription group. It returns
      * null if fails.
      *
      */
     @Override
     public String setSubscriptionGroup(int[] subIdList, String callingPackage) {
-        boolean hasModifyPermission = mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.MODIFY_PHONE_STATE) == PERMISSION_GRANTED;
+        if (subIdList == null || subIdList.length == 0) {
+            return null;
+        }
+        // If it doesn't have modify phone state permission, or carrier privilege permission,
+        // a SecurityException will be thrown. If it's due to invalid parameter or internal state,
+        // it will return null.
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+                != PERMISSION_GRANTED && !checkCarrierPrivilegeOnSubList(
+                        subIdList, callingPackage)) {
+            return null;
+        }
 
-        // If caller doesn't have modify permission or carrier privilege permission on certain
-        // subscriptions, maybe because the they are not active. So we keep them in a hashset and
-        // later check access rules in our database to know whether they can manage them.
-        Set<Integer> subIdCheckList = new HashSet<>();
+        long identity = Binder.clearCallingIdentity();
+
+        try {
+            // Generate a UUID.
+            String groupUUID = UUID.randomUUID().toString();
+
+            ContentValues value = new ContentValues();
+            value.put(SubscriptionManager.GROUP_UUID, groupUUID);
+            int result = mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI,
+                    value, getSelectionForSubIdList(subIdList), null);
+
+            if (DBG) logdl("setSubscriptionGroup update DB result: " + result);
+
+            refreshCachedActiveSubscriptionInfoList();
+
+            return groupUUID;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Remove a list of subscriptions from their subscription group.
+     * See {@link #setSubscriptionGroup(int[], String)} for more details.
+     *
+     * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+     * permission or had carrier privilege permission on the subscriptions:
+     * {@link TelephonyManager#hasCarrierPrivileges(int)} or
+     * {@link SubscriptionManager#canManageSubscription(SubscriptionInfo)}
+     *
+     * @throws SecurityException if the caller doesn't meet the requirements
+     *             outlined above.
+     *
+     * @param subIdList list of subId that need removing from their groups.
+     * @return whether the operation succeeds.
+     *
+     */
+    public boolean removeSubscriptionsFromGroup(int[] subIdList, String callingPackage) {
+        if (subIdList == null || subIdList.length == 0) {
+            return false;
+        }
+        // If it doesn't have modify phone state permission, or carrier privilege permission,
+        // a SecurityException will be thrown. If it's due to invalid parameter or internal state,
+        // it will return null.
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+                != PERMISSION_GRANTED && !checkCarrierPrivilegeOnSubList(
+                subIdList, callingPackage)) {
+            return false;
+        }
+
+        long identity = Binder.clearCallingIdentity();
+
+        try {
+            ContentValues value = new ContentValues();
+            value.put(SubscriptionManager.GROUP_UUID, (String) null);
+            int result = mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI,
+                    value, getSelectionForSubIdList(subIdList), null);
+
+            if (DBG) logdl("setSubscriptionGroup update DB result: " + result);
+
+            refreshCachedActiveSubscriptionInfoList();
+
+            return result != 0;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     *  Helper function to check if the caller has carrier privilege permissions on a list of subId.
+     *  The check can either be processed against access rules on currently active SIM cards, or
+     *  the access rules we keep in our database for currently inactive eSIMs.
+     *
+     *  Throws {@link SecurityException} if it fails.
+     *
+     *  @return true if checking passes on all subId. false if subId is invalid or doesn't exist,
+     *  or sub controller is not ready yet.
+     */
+    private boolean checkCarrierPrivilegeOnSubList(int[] subIdList, String callingPackage) {
+        mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
+        // Check carrier privilege permission on active subscriptions first.
+        // If it fails, they could be inactive. So keep them in a HashSet and later check
+        // access rules in our database.
+        Set<Integer> checkSubList = new HashSet<>();
         for (int subId : subIdList) {
-            if (!mTelephonyManager.hasCarrierPrivileges(subId)) {
-                subIdCheckList.add(subId);
+            if (isActiveSubId(subId)) {
+                if (!mTelephonyManager.hasCarrierPrivileges(subId)) {
+                    throw new SecurityException("Need carrier privilege on subId " + subId);
+                }
+            } else {
+                checkSubList.add(subId);
             }
         }
 
+        if (checkSubList.isEmpty()) {
+            return true;
+        }
+
         long identity = Binder.clearCallingIdentity();
 
         try {
             if (!isSubInfoReady()) {
                 if (DBG) logdl("[getSubscriptionInfoList] Sub Controller not ready");
-                return null;
+                return false;
             }
 
+            // Check access rules for each sub info.
             SubscriptionManager subscriptionManager = (SubscriptionManager)
                     mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
-            List<SubscriptionInfo> subList = getSubInfo(null, null);
-
+            List<SubscriptionInfo> subList = getSubInfo(getSelectionForSubIdList(subIdList), null);
             for (SubscriptionInfo subInfo : subList) {
-                if (subIdCheckList.contains(subInfo.getSubscriptionId())) {
-                    // If caller doesn't have modify permission or privilege access to
-                    // the subscription, operation is invalid and returns null.
-                    if (hasModifyPermission || (subInfo.isEmbedded()
-                            && subscriptionManager.canManageSubscription(
-                                    subInfo, callingPackage))) {
-                        subIdCheckList.remove(subInfo.getSubscriptionId());
+                if (checkSubList.contains(subInfo.getSubscriptionId())) {
+                    if (subInfo.isEmbedded() && subscriptionManager.canManageSubscription(
+                            subInfo, callingPackage)) {
+                        checkSubList.remove(subInfo.getSubscriptionId());
                     } else {
-                        if (DBG) {
-                            logdl("setSubscriptionGroup doesn't have permission on"
-                                    + " subInfo " + subInfo);
-                        }
-                        return null;
+                        throw new SecurityException("Need carrier privilege on subId "
+                                + subInfo.getSubscriptionId());
                     }
                 }
             }
 
-            if (!subIdCheckList.isEmpty()) {
-                // Some SubId not found.
-                StringBuilder subIdNotFound = new StringBuilder();
-                for (int subId : subIdCheckList) {
-                    subIdNotFound.append(subId + " ");
-                }
-                if (DBG) {
-                    logdl("setSubscriptionGroup subId not existed: "
-                            + subIdNotFound.toString());
-                }
+            return checkSubList.isEmpty();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
 
+    /**
+     * Helper function to create selection argument of a list of subId.
+     * The result should be: "in (subId1, subId2, ...)".
+     */
+    private String getSelectionForSubIdList(int[] subId) {
+        StringBuilder selection = new StringBuilder();
+        selection.append(SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID);
+        selection.append(" IN (");
+        for (int i = 0; i < subId.length - 1; i++) {
+            selection.append(subId[i] + ", ");
+        }
+        selection.append(subId[subId.length - 1]);
+        selection.append(")");
+
+        return selection.toString();
+    }
+
+    /**
+     * Get subscriptionInfo list of subscriptions that are in the same group of given subId.
+     * See {@link #setSubscriptionGroup(int[], String)} for more details.
+     *
+     * Caller will either have {@link android.Manifest.permission#READ_PHONE_STATE}
+     * permission or had carrier privilege permission on the subscription.
+     * {@link TelephonyManager#hasCarrierPrivileges(int)}
+     *
+     * @throws SecurityException if the caller doesn't meet the requirements
+     *             outlined above.
+     *
+     * @param subId of which list of subInfo from the same group will be returned.
+     * @return list of subscriptionInfo that belong to the same group, including the given
+     * subscription itself. It will return null if the subscription doesn't exist or it
+     * doesn't belong to any group.
+     *
+     */
+    public List<SubscriptionInfo> getSubscriptionsInGroup(int subId, String callingPackage) {
+        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
+                mContext, subId, callingPackage, "getSubscriptionsInGroup")) {
+            return null;
+        }
+
+        long identity = Binder.clearCallingIdentity();
+
+        try {
+            SubscriptionInfo info = getActiveSubscriptionInfo(subId, callingPackage);
+            if (info == null || TextUtils.isEmpty(info.getGroupUuid())) {
                 return null;
             }
 
-            // Generate a UUID.
-            String groupUUID = UUID.randomUUID().toString();
+            String groupUuid = info.getGroupUuid();
+            List<SubscriptionInfo> infoList = getAvailableSubscriptionInfoList(callingPackage);
 
-            // Selection should be: "in (subId1, subId2, ...)".
-            StringBuilder selection = new StringBuilder();
-            selection.append(SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID);
-            selection.append(" IN (");
-            for (int i = 0; i < subIdList.length - 1; i++) {
-                selection.append(subIdList[i] + ", ");
+            // Shouldn't happen because we've verified the subId belongs to an active subscription.
+            if (infoList == null) {
+                return null;
             }
-            selection.append(subIdList[subIdList.length - 1]);
-            selection.append(")");
-            ContentValues value = new ContentValues();
-            value.put(SubscriptionManager.GROUP_UUID, groupUUID);
-            int result = mContext.getContentResolver().update(
-                    SubscriptionManager.CONTENT_URI, value, selection.toString(), null);
 
-            if (DBG) logdl("setSubscriptionGroup update DB result: " + result);
-
-            refreshCachedActiveSubscriptionInfoList();
-
-            return groupUUID;
+            return infoList.stream().filter(
+                    subscriptionInfo -> groupUuid.equals(subscriptionInfo.getGroupUuid()))
+                    .collect(Collectors.toList());
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -2443,14 +2614,31 @@
         }
     }
 
-
     private boolean refreshCachedOpportunisticSubscriptionInfoList() {
         synchronized (mSubInfoListLock) {
             List<SubscriptionInfo> oldOpptCachedList = mCacheOpportunisticSubInfoList;
 
-            mCacheOpportunisticSubInfoList = mCacheActiveSubInfoList.stream()
-                    .filter(subscriptionInfo -> subscriptionInfo.isOpportunistic())
-                    .collect(Collectors.toList());
+            List<SubscriptionInfo> subList = getSubInfo(
+                    SubscriptionManager.IS_OPPORTUNISTIC + "=1 AND ("
+                            + SubscriptionManager.SIM_SLOT_INDEX + ">=0 OR "
+                            + SubscriptionManager.IS_EMBEDDED + "=1)", null);
+
+            if (subList != null) {
+                subList.sort(SUBSCRIPTION_INFO_COMPARATOR);
+            } else {
+                subList = new ArrayList<>();
+            }
+
+            mCacheOpportunisticSubInfoList = subList;
+
+            for (SubscriptionInfo info : mCacheOpportunisticSubInfoList) {
+                if (shouldDisableSubGroup(info.getGroupUuid())) {
+                    info.setGroupDisabled(true);
+                    if (isActiveSubId(info.getSubscriptionId())) {
+                        deactivateSubscription(info);
+                    }
+                }
+            }
 
             if (DBG_CACHE) {
                 if (!mCacheOpportunisticSubInfoList.isEmpty()) {
@@ -2466,4 +2654,25 @@
             return !oldOpptCachedList.equals(mCacheOpportunisticSubInfoList);
         }
     }
+
+    private boolean shouldDisableSubGroup(String groupUuid) {
+        if (groupUuid == null) return false;
+
+        for (SubscriptionInfo activeInfo : mCacheActiveSubInfoList) {
+            if (!activeInfo.isOpportunistic() && groupUuid.equals(activeInfo.getGroupUuid())) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private void deactivateSubscription(SubscriptionInfo info) {
+        // TODO: b/120439488 deactivate pSIM.
+        if (info.isEmbedded()) {
+            EuiccManager euiccManager = new EuiccManager(mContext);
+            euiccManager.switchToSubscription(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+                    PendingIntent.getService(mContext, 0, new Intent(), 0));
+        }
+    }
 }
diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
index 4e94146..7611620 100644
--- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
+++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
@@ -66,6 +66,8 @@
     private static final String LOG_TAG = "SubscriptionInfoUpdater";
     private static final int PROJECT_SIM_NUM = TelephonyManager.getDefault().getPhoneCount();
 
+    private static final boolean DBG = true;
+
     private static final int EVENT_INVALID = -1;
     private static final int EVENT_GET_NETWORK_SELECTION_MODE_DONE = 2;
     private static final int EVENT_SIM_LOADED = 3;
@@ -276,16 +278,8 @@
                 break;
 
             case EVENT_SIM_NOT_READY:
-                broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_NOT_READY,
-                        null);
-                broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_PRESENT);
-                broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_NOT_READY);
+                handleSimNotReady(msg.arg1);
                 // intentional fall through
-                // ICC_NOT_READY is a terminal state for an eSIM on the boot profile. At this
-                // phase, the subscription list is accessible.
-                // TODO(b/64216093): Clean up this special case, likely by treating NOT_READY
-                // as equivalent to ABSENT, once the rest of the system can handle it. Currently
-                // this breaks SystemUI which shows a "No SIM" icon.
 
             case EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS:
                 if (updateEmbeddedSubscriptions()) {
@@ -359,6 +353,26 @@
         }
     }
 
+    private void handleSimNotReady(int slotId) {
+        logd("handleSimNotReady: slotId: " + slotId);
+
+        IccCard iccCard = mPhone[slotId].getIccCard();
+        if (iccCard.isEmptyProfile()) {
+            // ICC_NOT_READY is a terminal state for an eSIM on the boot profile. At this
+            // phase, the subscription list is accessible. Treating NOT_READY
+            // as equivalent to ABSENT, once the rest of the system can handle it.
+            mIccId[slotId] = ICCID_STRING_FOR_NO_SIM;
+            if (isAllIccIdQueryDone()) {
+                updateSubscriptionInfoByIccId();
+            }
+        }
+
+        broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_NOT_READY,
+                null);
+        broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_PRESENT);
+        broadcastSimApplicationStateChanged(slotId, TelephonyManager.SIM_STATE_NOT_READY);
+    }
+
     private void handleSimLoaded(int slotId) {
         logd("handleSimLoaded: slotId: " + slotId);
 
@@ -400,6 +414,14 @@
                     logd("EVENT_RECORDS_LOADED Operator name is null");
                 }
 
+                String iso = tm.getSimCountryIsoForPhone(slotId);
+
+                if (!TextUtils.isEmpty(iso)) {
+                    SubscriptionController.getInstance().setCountryIso(iso, subId);
+                } else {
+                    logd("EVENT_RECORDS_LOADED sim country iso is null");
+                }
+
                 String msisdn = tm.getLine1Number(subId);
                 ContentResolver contentResolver = mContext.getContentResolver();
 
@@ -683,6 +705,7 @@
      */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     public boolean updateEmbeddedSubscriptions() {
+        if (DBG) logd("updateEmbeddedSubscriptions");
         // Do nothing if eUICCs are disabled. (Previous entries may remain in the cache, but they
         // are filtered out of list calls as long as EuiccManager.isEnabled returns false).
         if (!mEuiccManager.isEnabled()) {
@@ -718,6 +741,8 @@
             embeddedIccids[i] = embeddedProfiles[i].getIccid();
         }
 
+        if (DBG) logd("Get eUICC profile list of size " + embeddedProfiles.length);
+
         // Note that this only tracks whether we make any writes to the DB. It's possible this will
         // be set to true for an update even when the row contents remain exactly unchanged from
         // before, since we don't compare against the previous value. Since this is only intended to
@@ -741,6 +766,12 @@
             } else {
                 existingSubscriptions.remove(index);
             }
+
+            if (DBG) {
+                logd("embeddedProfile " + embeddedProfile + " existing record "
+                        + (index < 0 ? "not found" : "found"));
+            }
+
             ContentValues values = new ContentValues();
             values.put(SubscriptionManager.IS_EMBEDDED, 1);
             List<UiccAccessRule> ruleList = embeddedProfile.getUiccAccessRules();
@@ -754,6 +785,7 @@
             values.put(SubscriptionManager.IS_REMOVABLE, isRemovable);
             values.put(SubscriptionManager.DISPLAY_NAME, embeddedProfile.getNickname());
             values.put(SubscriptionManager.NAME_SOURCE, SubscriptionManager.NAME_SOURCE_USER_INPUT);
+            values.put(SubscriptionManager.PROFILE_CLASS, embeddedProfile.getProfileClass());
             hasChanges = true;
             contentResolver.update(SubscriptionManager.CONTENT_URI, values,
                     SubscriptionManager.ICC_ID + "=\"" + embeddedProfile.getIccid() + "\"", null);
@@ -767,10 +799,15 @@
         // around in case the subscription is added back later, which is equivalent to a removable
         // SIM being removed and reinserted).
         if (!existingSubscriptions.isEmpty()) {
+            if (DBG) {
+                logd("Removing existing embedded subscriptions of size"
+                        + existingSubscriptions.size());
+            }
             List<String> iccidsToRemove = new ArrayList<>();
             for (int i = 0; i < existingSubscriptions.size(); i++) {
                 SubscriptionInfo info = existingSubscriptions.get(i);
                 if (info.isEmbedded()) {
+                    if (DBG) logd("Removing embedded subscription of IccId " + info.getIccId());
                     iccidsToRemove.add("\"" + info.getIccId() + "\"");
                 }
             }
@@ -785,6 +822,7 @@
             SubscriptionController.getInstance().refreshCachedActiveSubscriptionInfoList();
         }
 
+        if (DBG) logd("updateEmbeddedSubscriptions done hasChanges=" + hasChanges);
         return hasChanges;
     }
 
diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
index f3099bc..35b8344 100644
--- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
+++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
@@ -16,18 +16,22 @@
 
 package com.android.internal.telephony;
 
+import android.annotation.NonNull;
 import android.content.Context;
+import android.content.res.XmlResourceParser;
 import android.database.Cursor;
 import android.os.Handler;
 import android.os.IDeviceIdleController;
 import android.os.Looper;
 import android.os.ServiceManager;
-import android.telephony.AccessNetworkConstants.TransportType;
+import android.telephony.Rlog;
 
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
 import com.android.internal.telephony.cdma.EriManager;
+import com.android.internal.telephony.dataconnection.DataEnabledSettings;
 import com.android.internal.telephony.dataconnection.DcTracker;
 import com.android.internal.telephony.dataconnection.TransportManager;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
 import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
@@ -35,14 +39,149 @@
 import com.android.internal.telephony.uicc.UiccCard;
 import com.android.internal.telephony.uicc.UiccProfile;
 
+import dalvik.system.PathClassLoader;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Consumer;
+
 /**
  * This class has one-line methods to instantiate objects only. The purpose is to make code
  * unit-test friendly and use this class as a way to do dependency injection. Instantiating objects
  * this way makes it easier to mock them in tests.
  */
 public class TelephonyComponentFactory {
+
+    private static final String TAG = TelephonyComponentFactory.class.getSimpleName();
+
     private static TelephonyComponentFactory sInstance;
 
+    private InjectedComponents mInjectedComponents;
+
+    private static class InjectedComponents {
+        private static final String ATTRIBUTE_JAR = "jar";
+        private static final String ATTRIBUTE_PACKAGE = "package";
+        private static final String TAG_INJECTION = "injection";
+        private static final String TAG_COMPONENTS = "components";
+        private static final String TAG_COMPONENT = "component";
+
+        private final Set<String> mComponentNames = new HashSet<>();
+        private TelephonyComponentFactory mInjectedInstance;
+        private String mPackageName;
+        private String mJarPath;
+
+        private boolean isInjected() {
+            return mPackageName != null && mJarPath != null;
+        }
+
+        private void makeInjectedInstance() {
+            if (isInjected()) {
+                PathClassLoader classLoader = new PathClassLoader(mJarPath,
+                        ClassLoader.getSystemClassLoader());
+                try {
+                    Class<?> cls = classLoader.loadClass(mPackageName);
+                    mInjectedInstance = (TelephonyComponentFactory) cls.newInstance();
+                } catch (ClassNotFoundException e) {
+                    Rlog.e(TAG, "failed: " + e.getMessage());
+                } catch (IllegalAccessException | InstantiationException e) {
+                    Rlog.e(TAG, "injection failed: " + e.getMessage());
+                }
+            }
+        }
+
+        private boolean isComponentInjected(String componentName) {
+            if (mInjectedInstance == null) {
+                return false;
+            }
+            return mComponentNames.contains(componentName);
+        }
+
+        /**
+         * Find the injection tag, set attributes, and then parse the injection.
+         */
+        private void parseXml(@NonNull XmlPullParser parser) {
+            parseXmlByTag(parser, false, p -> {
+                setAttributes(p);
+                parseInjection(p);
+            }, TAG_INJECTION);
+        }
+
+        /**
+         * Only parse the first injection tag. Find the components tag, then try parse it next.
+         */
+        private void parseInjection(@NonNull XmlPullParser parser) {
+            parseXmlByTag(parser, false, p -> parseComponents(p), TAG_COMPONENTS);
+        }
+
+        /**
+         * Only parse the first components tag. Find the component tags, then try parse them next.
+         */
+        private void parseComponents(@NonNull XmlPullParser parser) {
+            parseXmlByTag(parser, true, p -> parseComponent(p), TAG_COMPONENT);
+        }
+
+        /**
+         * Extract text values from component tags.
+         */
+        private void parseComponent(@NonNull XmlPullParser parser) {
+            try {
+                int outerDepth = parser.getDepth();
+                int type;
+                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                        && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                    if (type == XmlPullParser.TEXT) {
+                        mComponentNames.add(parser.getText());
+                    }
+                }
+            } catch (XmlPullParserException | IOException e) {
+                Rlog.e(TAG, "Failed to parse the component." , e);
+            }
+        }
+
+        /**
+         * Iterates the tags, finds the corresponding tag and then applies the consumer.
+         */
+        private void parseXmlByTag(@NonNull XmlPullParser parser, boolean allowDuplicate,
+                @NonNull Consumer<XmlPullParser> consumer, @NonNull final String tag) {
+            try {
+                int outerDepth = parser.getDepth();
+                int type;
+                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                        && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                    if (type == XmlPullParser.START_TAG && tag.equals(parser.getName())) {
+                        consumer.accept(parser);
+                        if (!allowDuplicate) {
+                            return;
+                        }
+                    }
+                }
+            } catch (XmlPullParserException | IOException e) {
+                Rlog.e(TAG, "Failed to parse or find tag: " + tag, e);
+            }
+        }
+
+        /**
+         * Sets the mPackageName and mJarPath by <injection/> tag.
+         * @param parser
+         * @return
+         */
+        private void setAttributes(@NonNull XmlPullParser parser) {
+            for (int i = 0; i < parser.getAttributeCount(); i++) {
+                String name = parser.getAttributeName(i);
+                String value = parser.getAttributeValue(i);
+                if (InjectedComponents.ATTRIBUTE_PACKAGE.equals(name)) {
+                    mPackageName = value;
+                } else if (InjectedComponents.ATTRIBUTE_JAR.equals(name)) {
+                    mJarPath = value;
+                }
+            }
+        }
+    }
+
     public static TelephonyComponentFactory getInstance() {
         if (sInstance == null) {
             sInstance = new TelephonyComponentFactory();
@@ -50,6 +189,46 @@
         return sInstance;
     }
 
+    /**
+     * Inject TelephonyComponentFactory using a xml config file.
+     * @param parser a nullable {@link XmlResourceParser} created with the injection config file.
+     * The config xml should has below formats:
+     * <injection package="package.InjectedTelephonyComponentFactory" jar="path to jar file">
+     *     <components>
+     *         <component>example.package.ComponentAbc</component>
+     *         <component>example.package.ComponentXyz</component>
+     *         <!-- e.g. com.android.internal.telephony.GsmCdmaPhone -->
+     *     </components>
+     * </injection>
+     */
+    public void injectTheComponentFactory(XmlResourceParser parser) {
+        if (mInjectedComponents != null) {
+            Rlog.i(TAG, "Already injected.");
+            return;
+        }
+
+        if (parser != null) {
+            mInjectedComponents = new InjectedComponents();
+            mInjectedComponents.parseXml(parser);
+            mInjectedComponents.makeInjectedInstance();
+            Rlog.i(TAG, "Total components injected: "
+                    + mInjectedComponents.mComponentNames.size());
+        }
+    }
+
+    /**
+     * Use the injected TelephonyComponentFactory if configured. Otherwise, use the default.
+     * @param componentName Name of the component class uses the injected component factory,
+     * e.g. GsmCdmaPhone.class.getName() for {@link GsmCdmaPhone}
+     * @return injected component factory. If not configured or injected, return the default one.
+     */
+    public TelephonyComponentFactory inject(String componentName) {
+        if (mInjectedComponents != null && mInjectedComponents.isComponentInjected(componentName)) {
+            return mInjectedComponents.mInjectedInstance;
+        }
+        return sInstance;
+    }
+
     public GsmCdmaCallTracker makeGsmCdmaCallTracker(GsmCdmaPhone phone) {
         return new GsmCdmaCallTracker(phone);
     }
@@ -67,6 +246,13 @@
     }
 
     /**
+     * Create a new EmergencyNumberTracker.
+     */
+    public EmergencyNumberTracker makeEmergencyNumberTracker(Phone phone, CommandsInterface ci) {
+        return new EmergencyNumberTracker(phone, ci);
+    }
+
+    /**
      * Sets the NitzStateMachine implementation to use during implementation. This boolean
      * should be removed once the new implementation is stable.
      */
@@ -85,8 +271,8 @@
         return new SimActivationTracker(phone);
     }
 
-    public DcTracker makeDcTracker(Phone phone) {
-        return new DcTracker(phone, TransportType.WWAN);
+    public DcTracker makeDcTracker(Phone phone, int transportType) {
+        return new DcTracker(phone, transportType);
     }
 
     public CarrierSignalAgent makeCarrierSignalAgent(Phone phone) {
@@ -186,8 +372,13 @@
         return IDeviceIdleController.Stub.asInterface(
                 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
     }
+
     public LocaleTracker makeLocaleTracker(Phone phone, NitzStateMachine nitzStateMachine,
                                            Looper looper) {
         return new LocaleTracker(phone, nitzStateMachine, looper);
     }
+
+    public DataEnabledSettings makeDataEnabledSettings(Phone phone) {
+        return new DataEnabledSettings(phone);
+    }
 }
diff --git a/src/java/com/android/internal/telephony/TransportManager.java b/src/java/com/android/internal/telephony/TransportManager.java
index 83b2947..a093b00 100644
--- a/src/java/com/android/internal/telephony/TransportManager.java
+++ b/src/java/com/android/internal/telephony/TransportManager.java
@@ -17,12 +17,14 @@
 package com.android.internal.telephony.dataconnection;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
 import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.CarrierConfigManager;
 import android.telephony.Rlog;
+import android.telephony.data.ApnSetting.ApnType;
 import android.text.TextUtils;
 
 import com.android.internal.telephony.Phone;
@@ -80,7 +82,8 @@
 
     private final Phone mPhone;
 
-    private final List<Integer> mAvailableTransports = new ArrayList<>();
+    /** The available transports. Must be one or more of AccessNetworkConstants.TransportType.XXX */
+    private final int[] mAvailableTransports;
 
     private final AccessNetworksManager mAccessNetworksManager;
 
@@ -91,13 +94,12 @@
         mAccessNetworksManager.registerForQualifiedNetworksChanged(this,
                 EVENT_QUALIFIED_NETWORKS_CHANGED);
 
-        // WWAN should be always available.
-        mAvailableTransports.add(TransportType.WWAN);
-
-        // TODO: Add more logic to check whether we should add WLAN as a transport. For now, if
-        // the device operate in non-legacy mode, then we always add WLAN as a transport.
-        if (!isInLegacyMode()) {
-            mAvailableTransports.add(TransportType.WLAN);
+        if (isInLegacyMode()) {
+            // For legacy mode, WWAN is the only transport to handle all data connections, even
+            // the IWLAN ones.
+            mAvailableTransports = new int[]{TransportType.WWAN};
+        } else {
+            mAvailableTransports = new int[]{TransportType.WWAN, TransportType.WLAN};
         }
     }
 
@@ -120,8 +122,14 @@
         //TODO: Update available networks and transports.
     }
 
-    public synchronized List<Integer> getAvailableTransports() {
-        return new ArrayList<>(mAvailableTransports);
+    /**
+     * @return The available transports. Note that on legacy devices, the only available transport
+     * would be WWAN only. If the device is configured as AP-assisted mode, the available transport
+     * will always be WWAN and WLAN (even if the device is not camped on IWLAN).
+     * See {@link #isInLegacyMode()} for mode details.
+     */
+    public synchronized @NonNull int[] getAvailableTransports() {
+        return mAvailableTransports;
     }
 
     /**
@@ -142,6 +150,17 @@
     }
 
     /**
+     * Get the corresponding transport based on the APN type
+     *
+     * @param apnType APN type
+     * @return The transport type
+     */
+    public int getCurrentTransport(@ApnType int apnType) {
+        // TODO: Look up the transport from the transport type map
+        return TransportType.WWAN;
+    }
+
+    /**
      * Dump the state of transport manager
      *
      * @param fd File descriptor
@@ -154,8 +173,8 @@
         pw.increaseIndent();
         pw.print("mAvailableTransports=");
         List<String> transportsStrings = new ArrayList<>();
-        for (int i = 0; i < mAvailableTransports.size(); i++) {
-            transportsStrings.add(TransportType.toString(mAvailableTransports.get(i)));
+        for (int i = 0; i < mAvailableTransports.length; i++) {
+            transportsStrings.add(TransportType.toString(mAvailableTransports[i]));
         }
         pw.println("[" + TextUtils.join(",", transportsStrings) + "]");
         mAccessNetworksManager.dump(fd, pw, args);
diff --git a/src/java/com/android/internal/telephony/WapPushOverSms.java b/src/java/com/android/internal/telephony/WapPushOverSms.java
index eff5c67..2e66a6d 100755
--- a/src/java/com/android/internal/telephony/WapPushOverSms.java
+++ b/src/java/com/android/internal/telephony/WapPushOverSms.java
@@ -19,6 +19,7 @@
 import static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_DELIVERY_IND;
 import static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND;
 import static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_READ_ORIG_IND;
+
 import android.app.Activity;
 import android.app.AppOpsManager;
 import android.app.BroadcastOptions;
@@ -38,7 +39,6 @@
 import android.os.IBinder;
 import android.os.IDeviceIdleController;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Telephony;
@@ -51,8 +51,6 @@
 
 import com.android.internal.telephony.uicc.IccUtils;
 
-import java.util.HashMap;
-
 import com.google.android.mms.MmsException;
 import com.google.android.mms.pdu.DeliveryInd;
 import com.google.android.mms.pdu.GenericPdu;
@@ -62,6 +60,8 @@
 import com.google.android.mms.pdu.PduPersister;
 import com.google.android.mms.pdu.ReadOrigInd;
 
+import java.util.HashMap;
+
 /**
  * WAP push handler class.
  *
@@ -133,7 +133,8 @@
 
     public WapPushOverSms(Context context) {
         mContext = context;
-        mDeviceIdleController = TelephonyComponentFactory.getInstance().getIDeviceIdleController();
+        mDeviceIdleController = TelephonyComponentFactory.getInstance()
+                .inject(IDeviceIdleController.class.getName()).getIDeviceIdleController();
 
         UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
 
@@ -200,9 +201,9 @@
                     return result;
                 }
             }
-
             WspTypeDecoder pduDecoder =
-                    TelephonyComponentFactory.getInstance().makeWspTypeDecoder(pdu);
+                    TelephonyComponentFactory.getInstance().inject(WspTypeDecoder.class.getName())
+                            .makeWspTypeDecoder(pdu);
 
             /**
              * Parse HeaderLen(unsigned integer).
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java b/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java
index 46d0243..fcea2d9 100644
--- a/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java
@@ -286,8 +286,8 @@
         // pass the user data portion of the PDU to the shared handler in SMSDispatcher
         byte[] userData = new byte[pdu.length - index];
         System.arraycopy(pdu, index, userData, 0, pdu.length - index);
-
-        InboundSmsTracker tracker = TelephonyComponentFactory.getInstance().makeInboundSmsTracker(
+        InboundSmsTracker tracker = TelephonyComponentFactory.getInstance()
+                .inject(InboundSmsTracker.class.getName()).makeInboundSmsTracker(
                 userData, timestamp, destinationPort, true, address, dispAddr, referenceNumber,
                 segment, totalSegments, true, HexDump.toHexString(userData));
 
diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
index fa13dac..0b4da48 100644
--- a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
+++ b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
@@ -344,7 +344,6 @@
      */
     public boolean isConnectable() {
         return isReady() && ((mState == DctConstants.State.IDLE)
-                                || (mState == DctConstants.State.SCANNING)
                                 || (mState == DctConstants.State.RETRYING)
                                 || (mState == DctConstants.State.FAILED));
     }
@@ -364,7 +363,6 @@
     public boolean isConnectedOrConnecting() {
         return isReady() && ((mState == DctConstants.State.CONNECTED)
                                 || (mState == DctConstants.State.CONNECTING)
-                                || (mState == DctConstants.State.SCANNING)
                                 || (mState == DctConstants.State.RETRYING));
     }
 
diff --git a/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java b/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
index cbc3efe..555b6e9 100644
--- a/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
+++ b/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
@@ -69,6 +69,8 @@
 
         private final Handler mHandler;
 
+        private final HandlerThread mHandlerThread;
+
         private final Phone mPhone;
 
         private CellularDataServiceProvider(int slotId) {
@@ -76,9 +78,9 @@
 
             mPhone = PhoneFactory.getPhone(getSlotId());
 
-            HandlerThread thread = new HandlerThread(CellularDataService.class.getSimpleName());
-            thread.start();
-            mLooper = thread.getLooper();
+            mHandlerThread = new HandlerThread(CellularDataService.class.getSimpleName());
+            mHandlerThread.start();
+            mLooper = mHandlerThread.getLooper();
             mHandler = new Handler(mLooper) {
                 @Override
                 public void handleMessage(Message message) {
@@ -219,6 +221,12 @@
             }
             mPhone.mCi.getDataCallList(message);
         }
+
+        @Override
+        public void close() {
+            mPhone.mCi.unregisterForDataCallListChanged(mHandler);
+            mHandlerThread.quit();
+        }
     }
 
     @Override
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index e683c47..39b443a 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -40,6 +40,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.telephony.AccessNetworkConstants.TransportType;
+import android.telephony.DataFailCause;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
@@ -173,14 +174,16 @@
     private ApnSetting mApnSetting;
     private ConnectionParams mConnectionParams;
     private DisconnectParams mDisconnectParams;
-    private DcFailCause mDcFailCause;
+    @DataFailCause.FailCause
+    private int mDcFailCause;
 
     private Phone mPhone;
     private DataServiceManager mDataServiceManager;
     private LinkProperties mLinkProperties = new LinkProperties();
     private long mCreateTime;
     private long mLastFailTime;
-    private DcFailCause mLastFailCause;
+    @DataFailCause.FailCause
+    private int mLastFailCause;
     private static final String NULL_IP = "0.0.0.0";
     private Object mUserData;
     private int mSubscriptionOverride;
@@ -189,6 +192,7 @@
     private NetworkInfo mNetworkInfo;
     private DcNetworkAgent mNetworkAgent;
     private LocalLog mNetCapsLocalLog = new LocalLog(50);
+    private int mDisabledApnTypeBitMask = 0;
 
     int mTag;
     public int mCid;
@@ -349,10 +353,10 @@
         ERROR_STALE,
         ERROR_DATA_SERVICE_SPECIFIC_ERROR;
 
-        public DcFailCause mFailCause;
+        public int mFailCause;
 
         SetupResult() {
-            mFailCause = DcFailCause.fromInt(0);
+            mFailCause = DataFailCause.getFailCause(0);
         }
 
         @Override
@@ -513,7 +517,7 @@
         // Check if we should fake an error.
         if (mDcTesterFailBringUpAll.getDcFailBringUp().mCounter  > 0) {
             DataCallResponse response = new DataCallResponse(
-                    mDcTesterFailBringUpAll.getDcFailBringUp().mFailCause.getErrorCode(),
+                    mDcTesterFailBringUpAll.getDcFailBringUp().mFailCause,
                     mDcTesterFailBringUpAll.getDcFailBringUp().mSuggestedRetryTime, 0, 0, "", "",
                     null, null, null, null, PhoneConstants.UNSET_MTU);
 
@@ -530,7 +534,7 @@
 
         mCreateTime = -1;
         mLastFailTime = -1;
-        mLastFailCause = DcFailCause.NONE;
+        mLastFailCause = DataFailCause.NONE;
 
         Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
         msg.obj = cp;
@@ -594,34 +598,22 @@
             ApnContext apnContext = cp.mApnContext;
             if (apnContext == alreadySent) continue;
             if (reason != null) apnContext.setReason(reason);
-            Pair<ApnContext, Integer> pair =
-                    new Pair<ApnContext, Integer>(apnContext, cp.mConnectionGeneration);
+            Pair<ApnContext, Integer> pair = new Pair<>(apnContext, cp.mConnectionGeneration);
             Message msg = mDct.obtainMessage(event, pair);
             AsyncResult.forMessage(msg);
             msg.sendToTarget();
         }
     }
 
-    private void notifyAllOfConnected(String reason) {
-        notifyAllWithEvent(null, DctConstants.EVENT_DATA_SETUP_COMPLETE, reason);
-    }
-
-    private void notifyAllOfDisconnectDcRetrying(String reason) {
-        notifyAllWithEvent(null, DctConstants.EVENT_DISCONNECT_DC_RETRYING, reason);
-    }
-    private void notifyAllDisconnectCompleted(DcFailCause cause) {
-        notifyAllWithEvent(null, DctConstants.EVENT_DISCONNECT_DONE, cause.toString());
-    }
-
-
     /**
      * Send the connectionCompletedMsg.
      *
      * @param cp is the ConnectionParams
-     * @param cause and if no error the cause is DcFailCause.NONE
+     * @param cause and if no error the cause is DataFailCause.NONE
      * @param sendAll is true if all contexts are to be notified
      */
-    private void notifyConnectCompleted(ConnectionParams cp, DcFailCause cause, boolean sendAll) {
+    private void notifyConnectCompleted(ConnectionParams cp, @DataFailCause.FailCause int cause,
+                                        boolean sendAll) {
         ApnContext alreadySent = null;
 
         if (cp != null && cp.mOnCompletedMsg != null) {
@@ -633,7 +625,7 @@
             long timeStamp = System.currentTimeMillis();
             connectionCompletedMsg.arg1 = mCid;
 
-            if (cause == DcFailCause.NONE) {
+            if (cause == DataFailCause.NONE) {
                 mCreateTime = timeStamp;
                 AsyncResult.forMessage(connectionCompletedMsg);
             } else {
@@ -641,9 +633,9 @@
                 mLastFailTime = timeStamp;
 
                 // Return message with a Throwable exception to signify an error.
-                if (cause == null) cause = DcFailCause.UNKNOWN;
+                if (cause == DataFailCause.NONE) cause = DataFailCause.UNKNOWN;
                 AsyncResult.forMessage(connectionCompletedMsg, cause,
-                        new Throwable(cause.toString()));
+                        new Throwable(DataFailCause.toString(cause)));
             }
             if (DBG) {
                 log("notifyConnectCompleted at " + timeStamp + " cause=" + cause
@@ -653,9 +645,9 @@
             connectionCompletedMsg.sendToTarget();
         }
         if (sendAll) {
-            log("Send to all. " + alreadySent + " " + cause.toString());
+            log("Send to all. " + alreadySent + " " + DataFailCause.toString(cause));
             notifyAllWithEvent(alreadySent, DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR,
-                    cause.toString());
+                    DataFailCause.toString(cause));
         }
     }
 
@@ -687,7 +679,7 @@
         }
         if (sendAll) {
             if (reason == null) {
-                reason = DcFailCause.UNKNOWN.toString();
+                reason = DataFailCause.toString(DataFailCause.UNKNOWN);
             }
             notifyAllWithEvent(alreadySent, DctConstants.EVENT_DISCONNECT_DONE, reason);
         }
@@ -727,7 +719,7 @@
 
         mCreateTime = -1;
         mLastFailTime = -1;
-        mLastFailCause = DcFailCause.NONE;
+        mLastFailCause = DataFailCause.NONE;
         mCid = -1;
 
         mPcscfAddr = new String[5];
@@ -737,7 +729,8 @@
         mApnSetting = null;
         mUnmeteredUseOnly = false;
         mRestrictedNetworkOverride = false;
-        mDcFailCause = null;
+        mDcFailCause = DataFailCause.NONE;
+        mDisabledApnTypeBitMask = 0;
     }
 
     /**
@@ -760,14 +753,14 @@
             result = SetupResult.ERROR_STALE;
         } else if (resultCode == DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE) {
             result = SetupResult.ERROR_RADIO_NOT_AVAILABLE;
-            result.mFailCause = DcFailCause.RADIO_NOT_AVAILABLE;
+            result.mFailCause = DataFailCause.RADIO_NOT_AVAILABLE;
         } else if (response.getStatus() != 0) {
-            if (response.getStatus() == DcFailCause.RADIO_NOT_AVAILABLE.getErrorCode()) {
+            if (response.getStatus() == DataFailCause.RADIO_NOT_AVAILABLE) {
                 result = SetupResult.ERROR_RADIO_NOT_AVAILABLE;
-                result.mFailCause = DcFailCause.RADIO_NOT_AVAILABLE;
+                result.mFailCause = DataFailCause.RADIO_NOT_AVAILABLE;
             } else {
                 result = SetupResult.ERROR_DATA_SERVICE_SPECIFIC_ERROR;
-                result.mFailCause = DcFailCause.fromInt(response.getStatus());
+                result.mFailCause = DataFailCause.getFailCause(response.getStatus());
             }
         } else {
             if (DBG) log("onSetupConnectionCompleted received successful DataCallResponse");
@@ -950,7 +943,7 @@
 
         // If the data is disabled, then we need to restrict the network so only privileged apps can
         // use the restricted network while data is disabled.
-        if (!mDct.isDataEnabled()) {
+        if (!mPhone.getDataEnabledSettings().isDataEnabled()) {
             return true;
         }
 
@@ -981,13 +974,16 @@
         return true;
     }
 
-    NetworkCapabilities getNetworkCapabilities() {
+    /**
+     * @return the {@link NetworkCapabilities} of this data connection.
+     */
+    public NetworkCapabilities getNetworkCapabilities() {
         NetworkCapabilities result = new NetworkCapabilities();
         result.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
 
         if (mApnSetting != null) {
             final String[] types = ApnSetting.getApnTypesStringFromBitmask(
-                mApnSetting.getApnTypeBitmask()).split(",");
+                mApnSetting.getApnTypeBitmask() & ~mDisabledApnTypeBitMask).split(",");
             for (String type : types) {
                 if (!mRestrictedNetworkOverride && mUnmeteredUseOnly
                         && ApnSettingUtils.isMeteredApnType(type, mPhone)) {
@@ -1132,7 +1128,7 @@
         // a failure we'll clear again at the bottom of this code.
         linkProperties.clear();
 
-        if (response.getStatus() == DcFailCause.NONE.getErrorCode()) {
+        if (response.getStatus() == DataFailCause.NONE) {
             try {
                 // set interface name
                 linkProperties.setInterfaceName(response.getIfname());
@@ -1177,6 +1173,26 @@
                     throw new UnknownHostException("Empty dns response and no system default dns");
                 }
 
+                // set pcscf
+                if (response.getPcscfs().size() > 0) {
+                    for (String pcscf : response.getPcscfs()) {
+                        if (pcscf == null) continue;
+                        pcscf = pcscf.trim();
+                        if (pcscf.isEmpty()) continue;
+                        InetAddress ia;
+                        try {
+                            ia = NetworkUtils.numericToInetAddress(pcscf);
+                        } catch (IllegalArgumentException e) {
+                            throw new UnknownHostException("Non-numeric pcscf addr=" + pcscf);
+                        }
+                        if (!ia.isAnyLocalAddress()) {
+                            linkProperties.addPcscfServer(ia);
+                        } else {
+                            log("bad address in PCSCF");
+                        }
+                    }
+                }
+
                 for (InetAddress gateway : response.getGateways()) {
                     // Allow 0.0.0.0 or :: as a gateway;
                     // this indicates a point-to-point interface.
@@ -1290,7 +1306,7 @@
             mPhone = null;
             mDataServiceManager = null;
             mLinkProperties = null;
-            mLastFailCause = null;
+            mLastFailCause = DataFailCause.NONE;
             mUserData = null;
             mDcController = null;
             mDcTesterFailBringUpAll = null;
@@ -1312,7 +1328,7 @@
                 case EVENT_CONNECT:
                     if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected");
                     ConnectionParams cp = (ConnectionParams) msg.obj;
-                    notifyConnectCompleted(cp, DcFailCause.UNKNOWN, false);
+                    notifyConnectCompleted(cp, DataFailCause.UNKNOWN, false);
                     break;
 
                 case EVENT_DISCONNECT:
@@ -1426,7 +1442,8 @@
      */
     private class DcInactiveState extends State {
         // Inform all contexts we've failed connecting
-        public void setEnterNotificationParams(ConnectionParams cp, DcFailCause cause) {
+        public void setEnterNotificationParams(ConnectionParams cp,
+                                               @DataFailCause.FailCause int cause) {
             if (VDBG) log("DcInactiveState: setEnterNotificationParams cp,cause");
             mConnectionParams = cp;
             mDisconnectParams = null;
@@ -1438,11 +1455,11 @@
             if (VDBG) log("DcInactiveState: setEnterNotificationParams dp");
             mConnectionParams = null;
             mDisconnectParams = dp;
-            mDcFailCause = DcFailCause.NONE;
+            mDcFailCause = DataFailCause.NONE;
         }
 
         // Inform all contexts of the failure cause
-        public void setEnterNotificationParams(DcFailCause cause) {
+        public void setEnterNotificationParams(@DataFailCause.FailCause int cause) {
             mConnectionParams = null;
             mDisconnectParams = null;
             mDcFailCause = cause;
@@ -1473,12 +1490,14 @@
                 }
                 notifyDisconnectCompleted(mDisconnectParams, true);
             }
-            if (mDisconnectParams == null && mConnectionParams == null && mDcFailCause != null) {
+            if (mDisconnectParams == null && mConnectionParams == null
+                    && mDcFailCause != DataFailCause.NONE) {
                 if (DBG) {
                     log("DcInactiveState: enter notifyAllDisconnectCompleted failCause="
                             + mDcFailCause);
                 }
-                notifyAllDisconnectCompleted(mDcFailCause);
+                notifyAllWithEvent(null, DctConstants.EVENT_DISCONNECT_DONE,
+                        DataFailCause.toString(mDcFailCause));
             }
 
             // Remove ourselves from cid mapping, before clearSettings
@@ -1515,7 +1534,7 @@
                         if (DBG) {
                             log("DcInactiveState: msg.what=EVENT_CONNECT initConnection failed");
                         }
-                        notifyConnectCompleted(cp, DcFailCause.UNACCEPTABLE_NETWORK_PARAMETER,
+                        notifyConnectCompleted(cp, DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER,
                                 false);
                     }
                     retVal = HANDLED;
@@ -1595,7 +1614,7 @@
                     switch (result) {
                         case SUCCESS:
                             // All is well
-                            mDcFailCause = DcFailCause.NONE;
+                            mDcFailCause = DataFailCause.NONE;
                             transitionTo(mActiveState);
                             break;
                         case ERROR_RADIO_NOT_AVAILABLE:
@@ -1624,8 +1643,8 @@
                                     + " delay=" + delay
                                     + " result=" + result
                                     + " result.isRadioRestartFailure="
-                                    + result.mFailCause.isRadioRestartFailure(mPhone.getContext(),
-                                            mPhone.getSubId())
+                                    + DataFailCause.isRadioRestartFailure(mPhone.getContext(),
+                                    result.mFailCause, mPhone.getSubId())
                                     + " isPermanentFailure=" +
                                     mDct.isPermanentFailure(result.mFailCause);
                             if (DBG) log(str);
@@ -1676,7 +1695,8 @@
             updateNetworkInfo();
 
             // If we were retrying there maybe more than one, otherwise they'll only be one.
-            notifyAllOfConnected(Phone.REASON_CONNECTED);
+            notifyAllWithEvent(null, DctConstants.EVENT_DATA_SETUP_COMPLETE,
+                    Phone.REASON_CONNECTED);
 
             mPhone.getCallTracker().registerForVoiceCallStarted(getHandler(),
                     DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED, null);
@@ -1727,8 +1747,8 @@
                 reason = Phone.REASON_CARRIER_CHANGE;
             } else if (mDisconnectParams != null && mDisconnectParams.mReason != null) {
                 reason = mDisconnectParams.mReason;
-            } else if (mDcFailCause != null) {
-                reason = mDcFailCause.toString();
+            } else {
+                reason = DataFailCause.toString(mDcFailCause);
             }
             mPhone.getCallTracker().unregisterForVoiceCallStarted(getHandler());
             mPhone.getCallTracker().unregisterForVoiceCallEnded(getHandler());
@@ -1756,10 +1776,14 @@
                     // either add this new apn context to our set or
                     // update the existing cp with the latest connection generation number
                     mApnContexts.put(cp.mApnContext, cp);
+                    // TODO (b/118347948): evaluate if it's still needed after assigning
+                    // different scores to different Cellular network.
+                    mDisabledApnTypeBitMask &= ~cp.mApnContext.getApnTypeBitmask();
+                    mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities());
                     if (DBG) {
                         log("DcActiveState: EVENT_CONNECT cp=" + cp + " dc=" + DataConnection.this);
                     }
-                    notifyConnectCompleted(cp, DcFailCause.NONE, false);
+                    notifyConnectCompleted(cp, DataFailCause.NONE, false);
                     retVal = HANDLED;
                     break;
                 }
@@ -1784,6 +1808,10 @@
                             transitionTo(mDisconnectingState);
                         } else {
                             mApnContexts.remove(dp.mApnContext);
+                            // TODO (b/118347948): evaluate if it's still needed after assigning
+                            // different scores to different Cellular network.
+                            mDisabledApnTypeBitMask |= dp.mApnContext.getApnTypeBitmask();
+                            mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities());
                             notifyDisconnectCompleted(dp, false);
                         }
                     } else {
@@ -1813,7 +1841,7 @@
                         log("DcActiveState EVENT_LOST_CONNECTION dc=" + DataConnection.this);
                     }
 
-                    mInactiveState.setEnterNotificationParams(DcFailCause.LOST_CONNECTION);
+                    mInactiveState.setEnterNotificationParams(DataFailCause.LOST_CONNECTION);
                     transitionTo(mInactiveState);
                     retVal = HANDLED;
                     break;
@@ -2101,7 +2129,7 @@
                         // Transition to inactive but send notifications after
                         // we've entered the mInactive state.
                         mInactiveState.setEnterNotificationParams(cp,
-                                DcFailCause.UNACCEPTABLE_NETWORK_PARAMETER);
+                                DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER);
                         transitionTo(mInactiveState);
                     } else {
                         if (DBG) {
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java b/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java
index 87521b1..be6892b 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java
@@ -17,6 +17,7 @@
 package com.android.internal.telephony.dataconnection;
 
 
+import android.annotation.IntDef;
 import android.content.ContentResolver;
 import android.os.Handler;
 import android.os.RegistrantList;
@@ -32,6 +33,8 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
  * The class to hold different data enabled/disabled settings. Also it allows clients to register
@@ -42,6 +45,19 @@
 
     private static final String LOG_TAG = "DataEnabledSettings";
 
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"REASON_"},
+            value = {
+                    REASON_REGISTERED,
+                    REASON_INTERNAL_DATA_ENABLED,
+                    REASON_USER_DATA_ENABLED,
+                    REASON_POLICY_DATA_ENABLED,
+                    REASON_DATA_ENABLED_BY_CARRIER,
+                    REASON_PROVISIONED_CHANGED,
+                    REASON_PROVISIONING_DATA_ENABLED_CHANGED
+            })
+    public @interface DataEnabledChangedReason {}
+
     public static final int REASON_REGISTERED = 0;
 
     public static final int REASON_INTERNAL_DATA_ENABLED = 1;
@@ -75,10 +91,11 @@
 
     private boolean mIsDataEnabled = false;
 
-    private Phone mPhone = null;
+    private final Phone mPhone;
+
     private ContentResolver mResolver = null;
 
-    private final RegistrantList mDataEnabledChangedRegistrants = new RegistrantList();
+    private final RegistrantList mOverallDataEnabledChangedRegistrants = new RegistrantList();
 
     private final LocalLog mSettingChangeLocalLog = new LocalLog(50);
 
@@ -99,9 +116,10 @@
 
     public synchronized void setInternalDataEnabled(boolean enabled) {
         localLog("InternalDataEnabled", enabled);
-        mInternalDataEnabled = enabled;
-
-        updateDataEnabledAndNotify(REASON_INTERNAL_DATA_ENABLED);
+        if (mInternalDataEnabled != enabled) {
+            mInternalDataEnabled = enabled;
+            updateDataEnabledAndNotify(REASON_INTERNAL_DATA_ENABLED);
+        }
     }
     public synchronized boolean isInternalDataEnabled() {
         return mInternalDataEnabled;
@@ -110,7 +128,7 @@
     public synchronized void setUserDataEnabled(boolean enabled) {
         localLog("UserDataEnabled", enabled);
         Settings.Global.putInt(mResolver, getMobileDataSettingName(), enabled ? 1 : 0);
-
+        mPhone.notifyUserMobileDataStateChanged(enabled);
         updateDataEnabledAndNotify(REASON_USER_DATA_ENABLED);
     }
 
@@ -136,9 +154,10 @@
 
     public synchronized void setPolicyDataEnabled(boolean enabled) {
         localLog("PolicyDataEnabled", enabled);
-        mPolicyDataEnabled = enabled;
-
-        updateDataEnabledAndNotify(REASON_POLICY_DATA_ENABLED);
+        if (mPolicyDataEnabled != enabled) {
+            mPolicyDataEnabled = enabled;
+            updateDataEnabledAndNotify(REASON_POLICY_DATA_ENABLED);
+        }
     }
 
     public synchronized boolean isPolicyDataEnabled() {
@@ -147,9 +166,10 @@
 
     public synchronized void setCarrierDataEnabled(boolean enabled) {
         localLog("CarrierDataEnabled", enabled);
-        mCarrierDataEnabled = enabled;
-
-        updateDataEnabledAndNotify(REASON_DATA_ENABLED_BY_CARRIER);
+        if (mCarrierDataEnabled != enabled) {
+            mCarrierDataEnabled = enabled;
+            updateDataEnabledAndNotify(REASON_DATA_ENABLED_BY_CARRIER);
+        }
     }
 
     public synchronized boolean isCarrierDataEnabled() {
@@ -212,16 +232,16 @@
     }
 
     private void notifyDataEnabledChanged(boolean enabled, int reason) {
-        mDataEnabledChangedRegistrants.notifyResult(new Pair<>(enabled, reason));
+        mOverallDataEnabledChangedRegistrants.notifyResult(new Pair<>(enabled, reason));
     }
 
     public void registerForDataEnabledChanged(Handler h, int what, Object obj) {
-        mDataEnabledChangedRegistrants.addUnique(h, what, obj);
+        mOverallDataEnabledChangedRegistrants.addUnique(h, what, obj);
         notifyDataEnabledChanged(isDataEnabled(), REASON_REGISTERED);
     }
 
     public void unregisterForDataEnabledChanged(Handler h) {
-        mDataEnabledChangedRegistrants.remove(h);
+        mOverallDataEnabledChangedRegistrants.remove(h);
     }
 
     private void log(String s) {
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcController.java b/src/java/com/android/internal/telephony/dataconnection/DcController.java
index 322b9c0..d18d552 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcController.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcController.java
@@ -27,6 +27,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.telephony.AccessNetworkConstants.TransportType;
+import android.telephony.DataFailCause;
 import android.telephony.PhoneStateListener;
 import android.telephony.Rlog;
 import android.telephony.TelephonyManager;
@@ -34,7 +35,6 @@
 
 import com.android.internal.telephony.DctConstants;
 import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.dataconnection.DataConnection.UpdateLinkPropertyResult;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
@@ -330,8 +330,8 @@
                             apnsToCleanup.addAll(apnContexts);
                             mDct.isCleanupRequired.set(false);
                         } else {
-                            DcFailCause failCause = DcFailCause.fromInt(newState.getStatus());
-                            if (failCause.isRadioRestartFailure(mPhone.getContext(),
+                            int failCause = DataFailCause.getFailCause(newState.getStatus());
+                            if (DataFailCause.isRadioRestartFailure(mPhone.getContext(), failCause,
                                         mPhone.getSubId())) {
                                 if (DBG) {
                                     log("onDataStateChanged: X restart radio, failCause="
@@ -394,9 +394,7 @@
                                         if (DBG) log("onDataStateChanged: simple change");
 
                                         for (ApnContext apnContext : apnContexts) {
-                                             mPhone.notifyDataConnection(
-                                                 PhoneConstants.REASON_LINK_PROPERTIES_CHANGED,
-                                                 apnContext.getApnType());
+                                            mPhone.notifyDataConnection(apnContext.getApnType());
                                         }
                                     }
                                 } else {
@@ -451,7 +449,7 @@
 
             // Cleanup connections that have changed
             for (ApnContext apnContext : apnsToCleanup) {
-               mDct.sendCleanUpConnection(true, apnContext);
+                mDct.cleanUpConnection(apnContext);
             }
 
             // Retry connections that have disappeared
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java b/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java
index c24d0bf..20e13ff 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java
@@ -17,6 +17,7 @@
 package com.android.internal.telephony.dataconnection;
 
 import android.content.Intent;
+import android.telephony.DataFailCause;
 import android.telephony.Rlog;
 
 /**
@@ -39,8 +40,9 @@
 
     // failCause with its --ei option name and default value
     static final String FAIL_CAUSE = "fail_cause";
-    static final DcFailCause DEFAULT_FAIL_CAUSE = DcFailCause.ERROR_UNSPECIFIED;
-    DcFailCause mFailCause;
+    static final int DEFAULT_FAIL_CAUSE = DataFailCause.ERROR_UNSPECIFIED;
+    @DataFailCause.FailCause
+    int mFailCause;
 
     // suggestedRetryTime with its --ei option name and default value
     static final String SUGGESTED_RETRY_TIME = "suggested_retry_time";
@@ -51,8 +53,8 @@
     void saveParameters(Intent intent, String s) {
         if (DBG) log(s + ".saveParameters: action=" + intent.getAction());
         mCounter = intent.getIntExtra(COUNTER, DEFAULT_COUNTER);
-        mFailCause = DcFailCause.fromInt(
-                intent.getIntExtra(FAIL_CAUSE, DEFAULT_FAIL_CAUSE.getErrorCode()));
+        mFailCause = DataFailCause.getFailCause(
+                intent.getIntExtra(FAIL_CAUSE, DEFAULT_FAIL_CAUSE));
         mSuggestedRetryTime =
                 intent.getIntExtra(SUGGESTED_RETRY_TIME, DEFAULT_SUGGESTED_RETRY_TIME);
         if (DBG) {
@@ -60,9 +62,10 @@
         }
     }
 
-    public void saveParameters(int counter, int failCause, int suggestedRetryTime) {
+    public void saveParameters(int counter, @DataFailCause.FailCause int failCause,
+                               int suggestedRetryTime) {
         mCounter = counter;
-        mFailCause = DcFailCause.fromInt(failCause);
+        mFailCause = DataFailCause.getFailCause(failCause);
         mSuggestedRetryTime = suggestedRetryTime;
     }
 
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcFailCause.java b/src/java/com/android/internal/telephony/dataconnection/DcFailCause.java
deleted file mode 100644
index 79c79de..0000000
--- a/src/java/com/android/internal/telephony/dataconnection/DcFailCause.java
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.telephony.dataconnection;
-
-import android.content.Context;
-import android.os.PersistableBundle;
-import android.telephony.CarrierConfigManager;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-
-/**
- * Returned as the reason for a connection failure as defined
- * by RIL_DataCallFailCause in ril.h and some local errors.
- */
-public enum DcFailCause {
-    NONE(0),
-
-    // This series of errors as specified by the standards
-    // specified in ril.h
-    OPERATOR_BARRED(0x08),                  /* no retry */
-    NAS_SIGNALLING(0x0E),
-    LLC_SNDCP(0x19),
-    INSUFFICIENT_RESOURCES(0x1A),
-    MISSING_UNKNOWN_APN(0x1B),              /* no retry */
-    UNKNOWN_PDP_ADDRESS_TYPE(0x1C),         /* no retry */
-    USER_AUTHENTICATION(0x1D),              /* no retry */
-    ACTIVATION_REJECT_GGSN(0x1E),           /* no retry */
-    ACTIVATION_REJECT_UNSPECIFIED(0x1F),
-    SERVICE_OPTION_NOT_SUPPORTED(0x20),     /* no retry */
-    SERVICE_OPTION_NOT_SUBSCRIBED(0x21),    /* no retry */
-    SERVICE_OPTION_OUT_OF_ORDER(0x22),
-    NSAPI_IN_USE(0x23),                     /* no retry */
-    REGULAR_DEACTIVATION(0x24),             /* possibly restart radio, based on config */
-    QOS_NOT_ACCEPTED(0x25),
-    NETWORK_FAILURE(0x26),
-    UMTS_REACTIVATION_REQ(0x27),
-    FEATURE_NOT_SUPP(0x28),
-    TFT_SEMANTIC_ERROR(0x29),
-    TFT_SYTAX_ERROR(0x2A),
-    UNKNOWN_PDP_CONTEXT(0x2B),
-    FILTER_SEMANTIC_ERROR(0x2C),
-    FILTER_SYTAX_ERROR(0x2D),
-    PDP_WITHOUT_ACTIVE_TFT(0x2E),
-    ONLY_IPV4_ALLOWED(0x32),                /* no retry */
-    ONLY_IPV6_ALLOWED(0x33),                /* no retry */
-    ONLY_SINGLE_BEARER_ALLOWED(0x34),
-    ESM_INFO_NOT_RECEIVED(0x35),
-    PDN_CONN_DOES_NOT_EXIST(0x36),
-    MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED(0x37),
-    MAX_ACTIVE_PDP_CONTEXT_REACHED(0x41),
-    UNSUPPORTED_APN_IN_CURRENT_PLMN(0x42),
-    INVALID_TRANSACTION_ID(0x51),
-    MESSAGE_INCORRECT_SEMANTIC(0x5F),
-    INVALID_MANDATORY_INFO(0x60),
-    MESSAGE_TYPE_UNSUPPORTED(0x61),
-    MSG_TYPE_NONCOMPATIBLE_STATE(0x62),
-    UNKNOWN_INFO_ELEMENT(0x63),
-    CONDITIONAL_IE_ERROR(0x64),
-    MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE(0x65),
-    PROTOCOL_ERRORS(0x6F),                  /* no retry */
-    APN_TYPE_CONFLICT(0x70),
-    INVALID_PCSCF_ADDR(0x71),
-    INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN(0x72),
-    EMM_ACCESS_BARRED(0x73),
-    EMERGENCY_IFACE_ONLY(0x74),
-    IFACE_MISMATCH(0x75),
-    COMPANION_IFACE_IN_USE(0x76),
-    IP_ADDRESS_MISMATCH(0x77),
-    IFACE_AND_POL_FAMILY_MISMATCH(0x78),
-    EMM_ACCESS_BARRED_INFINITE_RETRY(0x79),
-    AUTH_FAILURE_ON_EMERGENCY_CALL(0x7A),
-
-    // OEM sepecific error codes. To be used by OEMs when they don't
-    // want to reveal error code which would be replaced by ERROR_UNSPECIFIED
-    OEM_DCFAILCAUSE_1(0x1001),
-    OEM_DCFAILCAUSE_2(0x1002),
-    OEM_DCFAILCAUSE_3(0x1003),
-    OEM_DCFAILCAUSE_4(0x1004),
-    OEM_DCFAILCAUSE_5(0x1005),
-    OEM_DCFAILCAUSE_6(0x1006),
-    OEM_DCFAILCAUSE_7(0x1007),
-    OEM_DCFAILCAUSE_8(0x1008),
-    OEM_DCFAILCAUSE_9(0x1009),
-    OEM_DCFAILCAUSE_10(0x100A),
-    OEM_DCFAILCAUSE_11(0x100B),
-    OEM_DCFAILCAUSE_12(0x100C),
-    OEM_DCFAILCAUSE_13(0x100D),
-    OEM_DCFAILCAUSE_14(0x100E),
-    OEM_DCFAILCAUSE_15(0x100F),
-
-    // Local errors generated by Vendor RIL
-    // specified in ril.h
-    REGISTRATION_FAIL(-1),
-    GPRS_REGISTRATION_FAIL(-2),
-    SIGNAL_LOST(-3),                        /* no retry */
-    PREF_RADIO_TECH_CHANGED(-4),
-    RADIO_POWER_OFF(-5),                    /* no retry */
-    TETHERED_CALL_ACTIVE(-6),               /* no retry */
-    ERROR_UNSPECIFIED(0xFFFF),
-
-    // Errors generated by the Framework
-    // specified here
-    UNKNOWN(0x10000),
-    RADIO_NOT_AVAILABLE(0x10001),                   /* no retry */
-    UNACCEPTABLE_NETWORK_PARAMETER(0x10002),        /* no retry */
-    CONNECTION_TO_DATACONNECTIONAC_BROKEN(0x10003),
-    LOST_CONNECTION(0x10004),
-    RESET_BY_FRAMEWORK(0x10005);
-
-    private final int mErrorCode;
-    private static final HashMap<Integer, DcFailCause> sErrorCodeToFailCauseMap;
-    static {
-        sErrorCodeToFailCauseMap = new HashMap<Integer, DcFailCause>();
-        for (DcFailCause fc : values()) {
-            sErrorCodeToFailCauseMap.put(fc.getErrorCode(), fc);
-        }
-    }
-
-    /**
-     * Map of subId -> set of data call setup permanent failure for the carrier.
-     */
-    private static final HashMap<Integer, HashSet<DcFailCause>> sPermanentFailureCache =
-            new HashMap<>();
-
-    DcFailCause(int errorCode) {
-        mErrorCode = errorCode;
-    }
-
-    public int getErrorCode() {
-        return mErrorCode;
-    }
-
-    /**
-     * Returns whether or not the fail cause is a failure that requires a modem restart
-     *
-     * @param context device context
-     * @param subId subscription index
-     * @return true if the fail cause code needs platform to trigger a modem restart.
-     */
-    public boolean isRadioRestartFailure(Context context, int subId) {
-        CarrierConfigManager configManager = (CarrierConfigManager)
-                context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
-        if (configManager != null) {
-            PersistableBundle b = configManager.getConfigForSubId(subId);
-
-            if (b != null) {
-                if (this == REGULAR_DEACTIVATION
-                        && b.getBoolean(CarrierConfigManager
-                        .KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL)) {
-                    // This is for backward compatibility support. We need to continue support this
-                    // old configuration until it gets removed in the future.
-                    return true;
-                }
-                // Check the current configurations.
-                int[] causeCodes = b.getIntArray(CarrierConfigManager
-                        .KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY);
-                if (causeCodes != null) {
-                    return Arrays.stream(causeCodes).anyMatch(i -> i == getErrorCode());
-                }
-            }
-        }
-
-        return false;
-    }
-
-    public boolean isPermanentFailure(Context context, int subId) {
-
-        synchronized (sPermanentFailureCache) {
-
-            HashSet<DcFailCause> permanentFailureSet = sPermanentFailureCache.get(subId);
-
-            // In case of cache miss, we need to look up the settings from carrier config.
-            if (permanentFailureSet == null) {
-                // Retrieve the permanent failure from carrier config
-                CarrierConfigManager configManager = (CarrierConfigManager)
-                        context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
-                if (configManager != null) {
-                    PersistableBundle b = configManager.getConfigForSubId(subId);
-                    if (b != null) {
-                        String[] permanentFailureStrings = b.getStringArray(CarrierConfigManager.
-                                KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS);
-
-                        if (permanentFailureStrings != null) {
-                            permanentFailureSet = new HashSet<>();
-                            for (String failure : permanentFailureStrings) {
-                                permanentFailureSet.add(DcFailCause.valueOf(failure));
-                            }
-                        }
-                    }
-                }
-
-                // If we are not able to find the configuration from carrier config, use the default
-                // ones.
-                if (permanentFailureSet == null) {
-                    permanentFailureSet = new HashSet<DcFailCause>() {
-                        {
-                            add(OPERATOR_BARRED);
-                            add(MISSING_UNKNOWN_APN);
-                            add(UNKNOWN_PDP_ADDRESS_TYPE);
-                            add(USER_AUTHENTICATION);
-                            add(ACTIVATION_REJECT_GGSN);
-                            add(SERVICE_OPTION_NOT_SUPPORTED);
-                            add(SERVICE_OPTION_NOT_SUBSCRIBED);
-                            add(NSAPI_IN_USE);
-                            add(ONLY_IPV4_ALLOWED);
-                            add(ONLY_IPV6_ALLOWED);
-                            add(PROTOCOL_ERRORS);
-                            add(RADIO_POWER_OFF);
-                            add(TETHERED_CALL_ACTIVE);
-                            add(RADIO_NOT_AVAILABLE);
-                            add(UNACCEPTABLE_NETWORK_PARAMETER);
-                            add(SIGNAL_LOST);
-                        }
-                    };
-                }
-
-                sPermanentFailureCache.put(subId, permanentFailureSet);
-            }
-
-            return permanentFailureSet.contains(this);
-        }
-    }
-
-    public boolean isEventLoggable() {
-        return (this == OPERATOR_BARRED) || (this == INSUFFICIENT_RESOURCES) ||
-                (this == UNKNOWN_PDP_ADDRESS_TYPE) || (this == USER_AUTHENTICATION) ||
-                (this == ACTIVATION_REJECT_GGSN) || (this == ACTIVATION_REJECT_UNSPECIFIED) ||
-                (this == SERVICE_OPTION_NOT_SUBSCRIBED) ||
-                (this == SERVICE_OPTION_NOT_SUPPORTED) ||
-                (this == SERVICE_OPTION_OUT_OF_ORDER) || (this == NSAPI_IN_USE) ||
-                (this == ONLY_IPV4_ALLOWED) || (this == ONLY_IPV6_ALLOWED) ||
-                (this == PROTOCOL_ERRORS) || (this == SIGNAL_LOST) ||
-                (this == RADIO_POWER_OFF) || (this == TETHERED_CALL_ACTIVE) ||
-                (this == UNACCEPTABLE_NETWORK_PARAMETER);
-    }
-
-    public static DcFailCause fromInt(int errorCode) {
-        DcFailCause fc = sErrorCodeToFailCauseMap.get(errorCode);
-        if (fc == null) {
-            fc = UNKNOWN;
-        }
-        return fc;
-    }
-}
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java b/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java
index dede71e..4013454 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java
@@ -22,6 +22,7 @@
 import android.content.IntentFilter;
 import android.os.Build;
 import android.os.Handler;
+import android.telephony.DataFailCause;
 import android.telephony.Rlog;
 
 import com.android.internal.telephony.Phone;
@@ -35,7 +36,7 @@
  * Also you can add a suggested retry time if desired:
  *     --ei suggested_retry_time 5000
  *
- * The fail_cause is one of {@link DcFailCause}
+ * The fail_cause is one of {@link DataFailCause}
  */
 public class DcTesterFailBringUpAll {
     private static final String LOG_TAG = "DcTesterFailBrinupAll";
@@ -61,12 +62,12 @@
                 // Counter is MAX, bringUp/retry will always fail
                 log("simulate detaching");
                 mFailBringUp.saveParameters(Integer.MAX_VALUE,
-                        DcFailCause.LOST_CONNECTION.getErrorCode(),
+                        DataFailCause.LOST_CONNECTION,
                         DcFailBringUp.DEFAULT_SUGGESTED_RETRY_TIME);
             } else if (action.equals(mPhone.getActionAttached())) {
                 // Counter is 0 next bringUp/retry will succeed
                 log("simulate attaching");
-                mFailBringUp.saveParameters(0, DcFailCause.NONE.getErrorCode(),
+                mFailBringUp.saveParameters(0, DataFailCause.NONE,
                         DcFailBringUp.DEFAULT_SUGGESTED_RETRY_TIME);
             } else {
                 if (DBG) log("onReceive: unknown action=" + action);
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index 88dc2c0..6929ed4 100755
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -62,6 +62,7 @@
 import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.CarrierConfigManager;
 import android.telephony.CellLocation;
+import android.telephony.DataFailCause;
 import android.telephony.PcoData;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
@@ -80,7 +81,6 @@
 import android.view.WindowManager;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.CarrierActionAgent;
 import com.android.internal.telephony.DctConstants;
 import com.android.internal.telephony.EventLogTags;
 import com.android.internal.telephony.GsmCdmaPhone;
@@ -93,6 +93,7 @@
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataAllowedReasonType;
 import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType;
+import com.android.internal.telephony.dataconnection.DataEnabledSettings.DataEnabledChangedReason;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.telephony.uicc.IccRecords;
 import com.android.internal.telephony.uicc.UiccController;
@@ -324,12 +325,6 @@
         mSettingsObserver.observe(
                 Settings.Global.getUriFor(Settings.Global.DATA_ROAMING + simSuffix),
                 DctConstants.EVENT_ROAMING_SETTING_CHANGE);
-        mSettingsObserver.observe(
-                Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
-                DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE);
-        mSettingsObserver.observe(
-                Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED),
-                DctConstants.EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE);
     }
 
     /**
@@ -465,12 +460,6 @@
         sendMessage(msg);
     }
 
-    /**
-     * List of messages that are waiting to be posted, when data call disconnect
-     * is complete
-     */
-    private ArrayList<Message> mDisconnectAllCompleteMsgList = new ArrayList<Message>();
-
     private RegistrantList mAllDataDisconnectedRegistrants = new RegistrantList();
 
     // member variables
@@ -517,10 +506,6 @@
     //        really a lower power mode")
     private boolean mIsScreenOn = true;
 
-    // Indicates if we found mvno-specific APNs in the full APN list.
-    // used to determine if we can accept mno-specific APN for tethering.
-    private boolean mMvnoMatched = false;
-
     /** Allows the generation of unique Id's for DataConnection objects */
     private AtomicInteger mUniqueIdGenerator = new AtomicInteger(0);
 
@@ -619,7 +604,10 @@
         filter.addAction(INTENT_PROVISIONING_APN_ALARM);
         filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
 
-        mDataEnabledSettings = new DataEnabledSettings(phone);
+        mDataEnabledSettings = mPhone.getDataEnabledSettings();
+
+        mDataEnabledSettings.registerForDataEnabledChanged(this,
+                DctConstants.EVENT_DATA_ENABLED_CHANGED, null);
 
         mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
 
@@ -719,9 +707,6 @@
         mPhone.getCallTracker().registerForVoiceCallStarted(this,
                 DctConstants.EVENT_VOICE_CALL_STARTED, null);
         registerServiceStateTrackerEvents();
-        mPhone.getCarrierActionAgent().registerForCarrierAction(
-                CarrierActionAgent.CARRIER_ACTION_SET_METERED_APNS_ENABLED, this,
-                DctConstants.EVENT_SET_CARRIER_DATA_ENABLED, null, false);
         mDataServiceManager.registerForServiceBindingChanged(this,
                 DctConstants.EVENT_DATA_SERVICE_BINDING_CHANGED, null);
     }
@@ -738,7 +723,7 @@
             mProvisioningSpinner = null;
         }
 
-        cleanUpAllConnections(true, null);
+        cleanUpAllConnectionsInternal(true, null);
 
         mIsDisposed = true;
         mPhone.getContext().unregisterReceiver(mIntentReceiver);
@@ -775,46 +760,10 @@
         mPhone.getCallTracker().unregisterForVoiceCallEnded(this);
         mPhone.getCallTracker().unregisterForVoiceCallStarted(this);
         unregisterServiceStateTrackerEvents();
-        mPhone.getCarrierActionAgent().unregisterForCarrierAction(this,
-                CarrierActionAgent.CARRIER_ACTION_SET_METERED_APNS_ENABLED);
         mDataServiceManager.unregisterForServiceBindingChanged(this);
     }
 
     /**
-     * Modify {@link android.provider.Settings.Global#MOBILE_DATA} value.
-     */
-    public void setUserDataEnabled(boolean enable) {
-        Message msg = obtainMessage(DctConstants.CMD_SET_USER_DATA_ENABLE);
-        msg.arg1 = enable ? 1 : 0;
-        if (DBG) log("setDataEnabled: sendMessage: enable=" + enable);
-        sendMessage(msg);
-    }
-
-    private void onSetUserDataEnabled(boolean enabled) {
-        if (mDataEnabledSettings.isUserDataEnabled() != enabled) {
-            mDataEnabledSettings.setUserDataEnabled(enabled);
-            if (!getDataRoamingEnabled() && mPhone.getServiceState().getDataRoaming()) {
-                if (enabled) {
-                    notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON);
-                } else {
-                    notifyOffApnsOfAvailability(Phone.REASON_DATA_DISABLED);
-                }
-            }
-
-            mPhone.notifyUserMobileDataStateChanged(enabled);
-
-            // TODO: We should register for DataEnabledSetting's data enabled/disabled event and
-            // handle the rest from there.
-            if (enabled) {
-                reevaluateDataConnections();
-                onTrySetupData(Phone.REASON_DATA_ENABLED);
-            } else {
-                onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
-            }
-        }
-    }
-
-    /**
      * Reevaluate existing data connections when conditions change.
      *
      * For example, handle reverting restricted networks back to unrestricted. If we're changing
@@ -832,30 +781,6 @@
         }
     }
 
-    private void onDeviceProvisionedChange() {
-        mDataEnabledSettings.updateProvisionedChanged();
-        // TODO: We should register for DataEnabledSetting's data enabled/disabled event and
-        // handle the rest from there.
-        if (isDataEnabled()) {
-            reevaluateDataConnections();
-            onTrySetupData(Phone.REASON_DATA_ENABLED);
-        } else {
-            onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
-        }
-    }
-
-    private void onDeviceProvisioningDataChange() {
-        mDataEnabledSettings.updateProvisioningDataEnabled();
-        // TODO: We should register for DataEnabledSetting's data enabled/disabled event and
-        // handle the rest from there.
-        if (isDataEnabled()) {
-            reevaluateDataConnections();
-            onTrySetupData(Phone.REASON_DATA_ENABLED);
-        } else {
-            onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
-        }
-    }
-
     public long getSubId() {
         return mPhone.getSubId();
     }
@@ -877,11 +802,15 @@
         if (apnContext != null) apnContext.requestNetwork(networkRequest, log);
     }
 
-    public void releaseNetwork(NetworkRequest networkRequest, LocalLog log) {
+    public void releaseNetwork(NetworkRequest networkRequest, LocalLog log,
+            boolean cleanUpConnection) {
         final int apnType = ApnContext.getApnTypeFromNetworkRequest(networkRequest);
         final ApnContext apnContext = mApnContextsByType.get(apnType);
         log.log("DcTracker.releaseNetwork for " + networkRequest + " found " + apnContext);
-        if (apnContext != null) apnContext.releaseNetwork(networkRequest, log);
+        if (apnContext != null) {
+            apnContext.releaseNetwork(networkRequest, log);
+            if (cleanUpConnection) cleanUpConnectionInternal(true, apnContext);
+        }
     }
 
     // Turn telephony radio on or off.
@@ -1110,22 +1039,21 @@
             if (apnContext.isEnabled()) {
                 isAnyEnabled = true;
                 switch (apnContext.getState()) {
-                case CONNECTED:
-                case DISCONNECTING:
-                    if (VDBG) log("overall state is CONNECTED");
-                    return DctConstants.State.CONNECTED;
-                case RETRYING:
-                case CONNECTING:
-                    isConnecting = true;
-                    isFailed = false;
-                    break;
-                case IDLE:
-                case SCANNING:
-                    isFailed = false;
-                    break;
-                default:
-                    isAnyEnabled = true;
-                    break;
+                    case CONNECTED:
+                    case DISCONNECTING:
+                        if (VDBG) log("overall state is CONNECTED");
+                        return DctConstants.State.CONNECTED;
+                    case CONNECTING:
+                        isConnecting = true;
+                        isFailed = false;
+                        break;
+                    case IDLE:
+                    case RETRYING:
+                        isFailed = false;
+                        break;
+                    default:
+                        isAnyEnabled = true;
+                        break;
                 }
             }
         }
@@ -1147,15 +1075,6 @@
         }
     }
 
-    /**
-     * Whether data is enabled. This does not only check isUserDataEnabled(), but also
-     * others like CarrierDataEnabled and internalDataEnabled.
-     */
-    @VisibleForTesting
-    public boolean isDataEnabled() {
-        return mDataEnabledSettings.isDataEnabled();
-    }
-
     //****** Called from ServiceStateTracker
     /**
      * Invoked when ServiceStateTracker observes a transition from GPRS
@@ -1169,7 +1088,7 @@
         if (DBG) log ("onDataConnectionDetached: stop polling and notify detached");
         stopNetStatPoll();
         stopDataStallAlarm();
-        notifyDataConnection(Phone.REASON_DATA_DETACHED);
+        notifyDataConnection();
         mAttached.set(false);
     }
 
@@ -1180,15 +1099,15 @@
             if (DBG) log("onDataConnectionAttached: start polling notify attached");
             startNetStatPoll();
             startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
-            notifyDataConnection(Phone.REASON_DATA_ATTACHED);
+            notifyDataConnection();
         } else {
             // update APN availability so that APN can be enabled.
-            notifyOffApnsOfAvailability(Phone.REASON_DATA_ATTACHED);
+            notifyOffApnsOfAvailability();
         }
         if (mAutoAttachOnCreationConfig) {
             mAutoAttachOnCreation.set(true);
         }
-        setupDataOnConnectableApns(Phone.REASON_DATA_ATTACHED);
+        setupDataOnConnectableApns(Phone.REASON_DATA_ATTACHED, RetryFailures.ALWAYS);
     }
 
     /**
@@ -1368,10 +1287,6 @@
         ONLY_ON_CHANGE
     };
 
-    private void setupDataOnConnectableApns(String reason) {
-        setupDataOnConnectableApns(reason, RetryFailures.ALWAYS);
-    }
-
     private void setupDataOnConnectableApns(String reason, RetryFailures retryFailures) {
         if (VDBG) log("setupDataOnConnectableApns: " + reason);
 
@@ -1392,7 +1307,7 @@
             if (VDBG) log("setupDataOnConnectableApns: apnContext " + apnContext);
 
             if (apnContext.getState() == DctConstants.State.FAILED
-                    || apnContext.getState() == DctConstants.State.SCANNING) {
+                    || apnContext.getState() == DctConstants.State.RETRYING) {
                 if (retryFailures == RetryFailures.ALWAYS) {
                     apnContext.releaseDataConnection(reason);
                 } else if (apnContext.isConcurrentVoiceAndDataAllowed() == false &&
@@ -1421,7 +1336,7 @@
             // Assume data is connected on the simulator
             // FIXME  this can be improved
             apnContext.setState(DctConstants.State.CONNECTED);
-            mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
+            mPhone.notifyDataConnection(apnContext.getApnType());
 
             log("trySetupData: X We're on the simulator; assuming connected retValue=true");
             return true;
@@ -1447,8 +1362,8 @@
                 ArrayList<ApnSetting> waitingApns =
                         buildWaitingApns(apnContext.getApnType(), radioTech);
                 if (waitingApns.isEmpty()) {
-                    notifyNoData(DcFailCause.MISSING_UNKNOWN_APN, apnContext);
-                    notifyOffApnsOfAvailability(apnContext.getReason());
+                    notifyNoData(DataFailCause.MISSING_UNKNOWN_APN, apnContext);
+                    notifyOffApnsOfAvailability();
                     String str = "trySetupData: X No APN found retValue=false";
                     if (DBG) log(str);
                     apnContext.requestLog(str);
@@ -1463,16 +1378,16 @@
             }
 
             boolean retValue = setupData(apnContext, radioTech);
-            notifyOffApnsOfAvailability(apnContext.getReason());
+            notifyOffApnsOfAvailability();
 
             if (DBG) log("trySetupData: X retValue=" + retValue);
             return retValue;
         } else {
             if (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)
                     && apnContext.isConnectable()) {
-                mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType());
+                mPhone.notifyDataConnectionFailed(apnContext.getApnType());
             }
-            notifyOffApnsOfAvailability(apnContext.getReason());
+            notifyOffApnsOfAvailability();
 
             StringBuilder str = new StringBuilder();
 
@@ -1486,8 +1401,8 @@
             }
 
             // If this is a data retry, we should set the APN state to FAILED so it won't stay
-            // in SCANNING forever.
-            if (apnContext.getState() == DctConstants.State.SCANNING) {
+            // in RETRYING forever.
+            if (apnContext.getState() == DctConstants.State.RETRYING) {
                 apnContext.setState(DctConstants.State.FAILED);
                 str.append(" Stop retrying.");
             }
@@ -1499,12 +1414,11 @@
     }
 
     // Disabled apn's still need avail/unavail notifications - send them out
-    private void notifyOffApnsOfAvailability(String reason) {
+    private void notifyOffApnsOfAvailability() {
         for (ApnContext apnContext : mApnContexts.values()) {
             if (!mAttached.get() || !apnContext.isReady()) {
-                if (VDBG) log("notifyOffApnOfAvailability type:" + apnContext.getApnType());
-                mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
-                                            apnContext.getApnType(),
+                if (DBG) log("notifyOffApnOfAvailability type:" + apnContext.getApnType());
+                mPhone.notifyDataConnection(apnContext.getApnType(),
                                             PhoneConstants.DataState.DISCONNECTED);
             } else {
                 if (VDBG) {
@@ -1516,17 +1430,33 @@
     }
 
     /**
-     * If tearDown is true, this only tears down a CONNECTED session. Presently,
-     * there is no mechanism for abandoning an CONNECTING session,
-     * but would likely involve cancelling pending async requests or
-     * setting a flag or new state to ignore them when they came in
-     * @param tearDown true if the underlying DataConnection should be
-     * disconnected.
+     * Clean up all data connections. Note this is just detach the APN context from the data
+     * connection. After all APN contexts are detached from the data connection, the data
+     * connection will be torn down.
+     *
+     * @param reason Reason for the clean up.
+     */
+    public void cleanUpAllConnections(String reason) {
+        log("cleanUpAllConnections");
+        Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS);
+        msg.obj = reason;
+        sendMessage(msg);
+    }
+
+    /**
+     * Clean up all data connections by detaching the APN contexts from the data connections, which
+     * eventually tearing down all data connections after all APN contexts are detached from the
+     * data connections.
+     *
+     * @param tearDown True if the underlying data connection should be disconnected when no
+     * APN context attached to the data connection. False if we only want to reset the data
+     * connection's state machine without requesting modem to tearing down the data connections.
+     *
      * @param reason reason for the clean up.
      * @return boolean - true if we did cleanup any connections, false if they
      *                   were already all disconnected.
      */
-    private boolean cleanUpAllConnections(boolean tearDown, String reason) {
+    private boolean cleanUpAllConnectionsInternal(boolean tearDown, String reason) {
         if (DBG) log("cleanUpAllConnections: tearDown=" + tearDown + " reason=" + reason);
         boolean didDisconnect = false;
         boolean disableMeteredOnly = false;
@@ -1548,7 +1478,7 @@
                     if (apnContext.isDisconnected() == false) didDisconnect = true;
                     if (DBG) log("clean up metered ApnContext Type: " + apnContext.getApnType());
                     apnContext.setReason(reason);
-                    cleanUpConnection(tearDown, apnContext);
+                    cleanUpConnectionInternal(tearDown, apnContext);
                 }
             } else {
                 // Exclude the IMS APN from single DataConenction case.
@@ -1559,7 +1489,7 @@
                 // TODO - only do cleanup if not disconnected
                 if (apnContext.isDisconnected() == false) didDisconnect = true;
                 apnContext.setReason(reason);
-                cleanUpConnection(tearDown, apnContext);
+                cleanUpConnectionInternal(tearDown, apnContext);
             }
         }
 
@@ -1569,9 +1499,8 @@
         // TODO: Do we need mRequestedApnType?
         mRequestedApnType = ApnSetting.TYPE_DEFAULT;
 
-        log("cleanUpConnection: mDisconnectPendingCount = " + mDisconnectPendingCount);
+        log("cleanUpConnectionInternal: mDisconnectPendingCount = " + mDisconnectPendingCount);
         if (tearDown && mDisconnectPendingCount == 0) {
-            notifyDataDisconnectComplete();
             notifyAllDataDisconnected();
         }
 
@@ -1579,36 +1508,36 @@
     }
 
     /**
-     * Cleanup all connections.
+     * Detach the APN context from the associated data connection. This data connection might be
+     * torn down if no other APN context is attached to it.
      *
-     * TODO: Cleanup only a specified connection passed as a parameter.
-     *       Also, make sure when you clean up a conn, if it is last apply
-     *       logic as though it is cleanupAllConnections
-     *
-     * @param cause for the clean up.
+     * @param apnContext The APN context to be detached
      */
-    private void onCleanUpAllConnections(String cause) {
-        cleanUpAllConnections(true, cause);
-    }
-
-    void sendCleanUpConnection(boolean tearDown, ApnContext apnContext) {
-        if (DBG) log("sendCleanUpConnection: tearDown=" + tearDown + " apnContext=" + apnContext);
+    void cleanUpConnection(ApnContext apnContext) {
+        if (DBG) log("cleanUpConnection: apnContext=" + apnContext);
         Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_CONNECTION);
-        msg.arg1 = tearDown ? 1 : 0;
         msg.arg2 = 0;
         msg.obj = apnContext;
         sendMessage(msg);
     }
 
-    private void cleanUpConnection(boolean tearDown, ApnContext apnContext) {
+    /**
+     * Detach the APN context from the associated data connection. This data connection might be
+     * torn down if no other APN context is attached to it.
+     *
+     * @param tearDown True if tearing down data connection when no other APN context attached.
+     * False to only reset the data connection's state machine.
+     * @param apnContext The APN context to be detached
+     */
+    private void cleanUpConnectionInternal(boolean tearDown, ApnContext apnContext) {
         if (apnContext == null) {
-            if (DBG) log("cleanUpConnection: apn context is null");
+            if (DBG) log("cleanUpConnectionInternal: apn context is null");
             return;
         }
 
         DataConnection dataConnection = apnContext.getDataConnection();
-        String str = "cleanUpConnection: tearDown=" + tearDown + " reason=" +
-                apnContext.getReason();
+        String str = "cleanUpConnectionInternal: tearDown=" + tearDown + " reason="
+                + apnContext.getReason();
         if (VDBG) log(str + " apnContext=" + apnContext);
         apnContext.requestLog(str);
         if (tearDown) {
@@ -1618,7 +1547,7 @@
                 apnContext.setState(DctConstants.State.IDLE);
                 if (!apnContext.isReady()) {
                     if (dataConnection != null) {
-                        str = "cleanUpConnection: teardown, disconnected, !ready";
+                        str = "cleanUpConnectionInternal: teardown, disconnected, !ready";
                         if (DBG) log(str + " apnContext=" + apnContext);
                         apnContext.requestLog(str);
                         dataConnection.tearDown(apnContext, "", null);
@@ -1635,7 +1564,7 @@
                             // if (PhoneConstants.APN_TYPE_DUN.equals(PhoneConstants.APN_TYPE_DEFAULT)) {
                             if (teardownForDun()) {
                                 if (DBG) {
-                                    log("cleanUpConnection: disconnectAll DUN connection");
+                                    log("cleanUpConnectionInternal: disconnectAll DUN connection");
                                 }
                                 // we need to tear it down - we brought it up just for dun and
                                 // other people are camped on it and now dun is done.  We need
@@ -1645,12 +1574,11 @@
                             }
                         }
                         final int generation = apnContext.getConnectionGeneration();
-                        str = "cleanUpConnection: tearing down" + (disconnectAll ? " all" : "") +
-                                " using gen#" + generation;
+                        str = "cleanUpConnectionInternal: tearing down"
+                                + (disconnectAll ? " all" : "") + " using gen#" + generation;
                         if (DBG) log(str + "apnContext=" + apnContext);
                         apnContext.requestLog(str);
-                        Pair<ApnContext, Integer> pair =
-                                new Pair<ApnContext, Integer>(apnContext, generation);
+                        Pair<ApnContext, Integer> pair = new Pair<>(apnContext, generation);
                         Message msg = obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, pair);
 
                         if (disconnectAll) {
@@ -1666,16 +1594,15 @@
                     // apn is connected but no reference to the data connection.
                     // Should not be happen, but reset the state in case.
                     apnContext.setState(DctConstants.State.IDLE);
-                    apnContext.requestLog("cleanUpConnection: connected, bug no dc");
-                    mPhone.notifyDataConnection(apnContext.getReason(),
-                                                apnContext.getApnType());
+                    apnContext.requestLog("cleanUpConnectionInternal: connected, bug no dc");
+                    mPhone.notifyDataConnection(apnContext.getApnType());
                 }
             }
         } else {
             // force clean up the data connection.
             if (dataConnection != null) dataConnection.reset();
             apnContext.setState(DctConstants.State.IDLE);
-            mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
+            mPhone.notifyDataConnection(apnContext.getApnType());
             apnContext.setDataConnection(null);
         }
 
@@ -1684,7 +1611,8 @@
         if (dataConnection != null) {
             cancelReconnectAlarm(apnContext);
         }
-        str = "cleanUpConnection: X tearDown=" + tearDown + " reason=" + apnContext.getReason();
+        str = "cleanUpConnectionInternal: X tearDown=" + tearDown + " reason="
+                + apnContext.getReason();
         if (DBG) log(str + " apnContext=" + apnContext + " dc=" + apnContext.getDataConnection());
         apnContext.requestLog(str);
     }
@@ -1700,8 +1628,6 @@
             return new ArrayList<ApnSetting>(0);
         }
         int bearer = mPhone.getServiceState().getRilDataRadioTechnology();
-        IccRecords r = mIccRecords.get();
-        String operator = (r != null) ? r.getOperatorNumeric() : "";
         ArrayList<ApnSetting> dunCandidates = new ArrayList<ApnSetting>();
         ArrayList<ApnSetting> retDunSettings = new ArrayList<ApnSetting>();
 
@@ -1729,16 +1655,7 @@
                     ServiceState.rilRadioTechnologyToNetworkType(bearer))) {
                 continue;
             }
-            if (dunSetting.getOperatorNumeric().equals(operator)) {
-                if (dunSetting.hasMvnoParams()) {
-                    if (r != null && ApnSettingUtils.mvnoMatches(r, dunSetting.getMvnoType(),
-                            dunSetting.getMvnoMatchData())) {
-                        retDunSettings.add(dunSetting);
-                    }
-                } else if (mMvnoMatched == false) {
-                    retDunSettings.add(dunSetting);
-                }
-            }
+            retDunSettings.add(dunSetting);
         }
 
         if (VDBG) log("fetchDunApns: dunSettings=" + retDunSettings);
@@ -1752,13 +1669,13 @@
                         new String[] {Telephony.Carriers.APN_SET_ID}, null, null, null);
         if (c == null) {
             loge("getPreferredApnSetId: cursor is null");
-            return Telephony.Carriers.NO_SET_SET;
+            return Telephony.Carriers.NO_APN_SET_ID;
         }
 
         int setId;
         if (c.getCount() < 1) {
             loge("getPreferredApnSetId: no APNs found");
-            setId = Telephony.Carriers.NO_SET_SET;
+            setId = Telephony.Carriers.NO_APN_SET_ID;
         } else {
             c.moveToFirst();
             setId = c.getInt(0 /* index of Telephony.Carriers.APN_SET_ID */);
@@ -1777,6 +1694,13 @@
     }
 
     /**
+     * @return the {@link DataConnection} with the given context id {@code cid}.
+     */
+    public DataConnection getDataConnectionByContextId(int cid) {
+        return mDcc.getActiveDcByCid(cid);
+    }
+
+    /**
      * Determine if DUN connection is special and we need to teardown on start/stop
      */
     private boolean teardownForDun() {
@@ -1806,44 +1730,10 @@
         }
     }
 
-    boolean isPermanentFailure(DcFailCause dcFailCause) {
-        return (dcFailCause.isPermanentFailure(mPhone.getContext(), mPhone.getSubId()) &&
-                (mAttached.get() == false || dcFailCause != DcFailCause.SIGNAL_LOST));
-    }
-
-    private ArrayList<ApnSetting> createApnList(Cursor cursor) {
-        ArrayList<ApnSetting> mnoApns = new ArrayList<ApnSetting>();
-        ArrayList<ApnSetting> mvnoApns = new ArrayList<ApnSetting>();
-        IccRecords r = mIccRecords.get();
-
-        if (cursor.moveToFirst()) {
-            do {
-                ApnSetting apn = ApnSetting.makeApnSetting(cursor);
-                if (apn == null) {
-                    continue;
-                }
-
-                if (apn.hasMvnoParams()) {
-                    if (r != null && ApnSettingUtils.mvnoMatches(r, apn.getMvnoType(),
-                            apn.getMvnoMatchData())) {
-                        mvnoApns.add(apn);
-                    }
-                } else {
-                    mnoApns.add(apn);
-                }
-            } while (cursor.moveToNext());
-        }
-
-        ArrayList<ApnSetting> result;
-        if (mvnoApns.isEmpty()) {
-            result = mnoApns;
-            mMvnoMatched = false;
-        } else {
-            result = mvnoApns;
-            mMvnoMatched = true;
-        }
-        if (DBG) log("createApnList: X result=" + result);
-        return result;
+    boolean isPermanentFailure(@DataFailCause.FailCause int dcFailCause) {
+        return (DataFailCause.isPermanentFailure(mPhone.getContext(), dcFailCause,
+                mPhone.getSubId())
+                && (mAttached.get() == false || dcFailCause != DataFailCause.SIGNAL_LOST));
     }
 
     private DataConnection findFreeDataConnection() {
@@ -1924,7 +1814,7 @@
                     // Only lower priority calls left.  Disconnect them all in this single PDP case
                     // so that we can bring up the requested higher priority call (once we receive
                     // response for deactivate request for the calls we are about to disconnect
-                    if (cleanUpAllConnections(true, Phone.REASON_SINGLE_PDN_ARBITRATION)) {
+                    if (cleanUpAllConnectionsInternal(true, Phone.REASON_SINGLE_PDN_ARBITRATION)) {
                         // If any call actually requested to be disconnected, means we can't
                         // bring up this connection yet as we need to wait for those data calls
                         // to be disconnected.
@@ -1958,7 +1848,7 @@
         apnContext.setDataConnection(dataConnection);
         apnContext.setApnSetting(apnSetting);
         apnContext.setState(DctConstants.State.CONNECTING);
-        mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
+        mPhone.notifyDataConnection(apnContext.getApnType());
 
         Message msg = obtainMessage();
         msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE;
@@ -2053,7 +1943,7 @@
 
         // FIXME: See bug 17426028 maybe no conditional is needed.
         if (mPhone.getSubId() == SubscriptionManager.getDefaultDataSubscriptionId()) {
-            setupDataOnConnectableApns(Phone.REASON_APN_CHANGED);
+            setupDataOnConnectableApns(Phone.REASON_APN_CHANGED, RetryFailures.ALWAYS);
         }
     }
 
@@ -2123,8 +2013,8 @@
 
     private void restartRadio() {
         if (DBG) log("restartRadio: ************TURN OFF RADIO**************");
-        cleanUpAllConnections(true, Phone.REASON_RADIO_TURNED_OFF);
-        mPhone.getServiceStateTracker().powerOffRadioSafely(this);
+        cleanUpAllConnectionsInternal(true, Phone.REASON_RADIO_TURNED_OFF);
+        mPhone.getServiceStateTracker().powerOffRadioSafely();
         /* Note: no need to call setRadioPower(true).  Assuming the desired
          * radio power state is still ON (as tracked by ServiceStateTracker),
          * ServiceStateTracker will call setRadioPower when it receives the
@@ -2183,12 +2073,12 @@
                 SystemClock.elapsedRealtime() + delay, alarmIntent);
     }
 
-    private void notifyNoData(DcFailCause lastFailCauseCode,
+    private void notifyNoData(@DataFailCause.FailCause int lastFailCauseCode,
                               ApnContext apnContext) {
         if (DBG) log( "notifyNoData: type=" + apnContext.getApnType());
         if (isPermanentFailure(lastFailCauseCode)
             && (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT))) {
-            mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType());
+            mPhone.notifyDataConnectionFailed(apnContext.getApnType());
         }
     }
 
@@ -2206,48 +2096,15 @@
         setInitialAttachApn();
         if (mPhone.mCi.getRadioState() == TelephonyManager.RADIO_POWER_ON) {
             if (DBG) log("onRecordsLoadedOrSubIdChanged: notifying data availability");
-            notifyOffApnsOfAvailability(Phone.REASON_SIM_LOADED);
+            notifyOffApnsOfAvailability();
         }
-        setupDataOnConnectableApns(Phone.REASON_SIM_LOADED);
-    }
-
-    /**
-     * Action set from carrier signalling broadcast receivers to enable/disable metered apns.
-     */
-    private void onSetCarrierDataEnabled(AsyncResult ar) {
-        if (ar.exception != null) {
-            loge("CarrierDataEnable exception: " + ar.exception);
-            return;
-        }
-        boolean enabled = (boolean) ar.result;
-        if (enabled != mDataEnabledSettings.isCarrierDataEnabled()) {
-            if (DBG) {
-                log("carrier Action: set metered apns enabled: " + enabled);
-            }
-
-            // Disable/enable all metered apns
-            mDataEnabledSettings.setCarrierDataEnabled(enabled);
-
-            if (!enabled) {
-                // Send otasp_sim_unprovisioned so that SuW is able to proceed and notify users
-                mPhone.notifyOtaspChanged(TelephonyManager.OTASP_SIM_UNPROVISIONED);
-                // Tear down all metered apns
-                cleanUpAllConnections(true, Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN);
-            } else {
-                // Re-evaluate Otasp state
-                int otaspState = mPhone.getServiceStateTracker().getOtasp();
-                mPhone.notifyOtaspChanged(otaspState);
-
-                reevaluateDataConnections();
-                setupDataOnConnectableApns(Phone.REASON_DATA_ENABLED);
-            }
-        }
+        setupDataOnConnectableApns(Phone.REASON_SIM_LOADED, RetryFailures.ALWAYS);
     }
 
     private void onSimNotReady() {
         if (DBG) log("onSimNotReady");
 
-        cleanUpAllConnections(true, Phone.REASON_SIM_NOT_READY);
+        cleanUpAllConnectionsInternal(true, Phone.REASON_SIM_NOT_READY);
         mAllApnSettings.clear();
         mAutoAttachOnCreationConfig = false;
         // Clear auto attach as modem is expected to do a new attach once SIM is ready
@@ -2259,30 +2116,6 @@
         setDataProfilesAsNeeded();
     }
 
-    public void setPolicyDataEnabled(boolean enabled) {
-        if (DBG) log("setPolicyDataEnabled: " + enabled);
-        Message msg = obtainMessage(DctConstants.CMD_SET_POLICY_DATA_ENABLE);
-        msg.arg1 = (enabled ? DctConstants.ENABLED : DctConstants.DISABLED);
-        sendMessage(msg);
-    }
-
-    private void onSetPolicyDataEnabled(boolean enabled) {
-        final boolean prevEnabled = isDataEnabled();
-        if (mDataEnabledSettings.isPolicyDataEnabled() != enabled) {
-            mDataEnabledSettings.setPolicyDataEnabled(enabled);
-            // TODO: We should register for DataEnabledSetting's data enabled/disabled event and
-            // handle the rest from there.
-            if (prevEnabled != isDataEnabled()) {
-                if (!prevEnabled) {
-                    reevaluateDataConnections();
-                    onTrySetupData(Phone.REASON_DATA_ENABLED);
-                } else {
-                    onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
-                }
-            }
-        }
-    }
-
     private void applyNewState(ApnContext apnContext, boolean enabled, boolean met) {
         boolean cleanup = false;
         boolean trySetup = false;
@@ -2307,17 +2140,15 @@
                     case IDLE:
                         // fall through: this is unexpected but if it happens cleanup and try setup
                     case FAILED:
-                    case SCANNING:
-                    case RETRYING: {
+                    case RETRYING:
                         // We're "READY" but not active so disconnect (cleanup = true) and
                         // connect (trySetup = true) to be sure we retry the connection.
                         trySetup = true;
                         apnContext.setReason(Phone.REASON_DATA_ENABLED);
                         break;
-                    }
                 }
             } else if (met) {
-                apnContext.setReason(Phone.REASON_DATA_DISABLED);
+                apnContext.setReason(Phone.REASON_DATA_DISABLED_INTERNAL);
                 // If ConnectivityService has disabled this network, stop trying to bring
                 // it up, but do not tear it down - ConnectivityService will do that
                 // directly by talking with the DataConnection.
@@ -2355,7 +2186,7 @@
         }
         apnContext.setEnabled(enabled);
         apnContext.setDependencyMet(met);
-        if (cleanup) cleanUpConnection(true, apnContext);
+        if (cleanup) cleanUpConnectionInternal(true, apnContext);
         if (trySetup) {
             apnContext.resetErrorCodeRetries();
             trySetupData(apnContext);
@@ -2391,7 +2222,6 @@
                                                 + " curApnCtx=" + curApnCtx);
                                     }
                                     return curDc;
-                                case RETRYING:
                                 case CONNECTING:
                                     potentialDc = curDc;
                                     potentialApnCtx = curApnCtx;
@@ -2411,7 +2241,6 @@
                                         + " curApnCtx=" + curApnCtx);
                             }
                             return curDc;
-                        case RETRYING:
                         case CONNECTING:
                             potentialDc = curDc;
                             potentialApnCtx = curApnCtx;
@@ -2463,32 +2292,7 @@
             if(DBG) log("onEnableApn: isOnlySingleDcAllowed true & higher priority APN disabled");
             // If the highest priority APN is disabled and only single
             // data call is allowed, try to setup data call on other connectable APN.
-            setupDataOnConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION);
-        }
-    }
-
-    // TODO: We shouldnt need this.
-    private boolean onTrySetupData(String reason) {
-        if (DBG) log("onTrySetupData: reason=" + reason);
-        setupDataOnConnectableApns(reason);
-        return true;
-    }
-
-    private boolean onTrySetupData(ApnContext apnContext) {
-        if (DBG) log("onTrySetupData: apnContext=" + apnContext);
-        return trySetupData(apnContext);
-    }
-
-    /**
-     * Whether data is enabled by user. Unlike isDataEnabled, this only
-     * checks user setting stored in {@link android.provider.Settings.Global#MOBILE_DATA}
-     * if not provisioning, or isProvisioningDataEnabled if provisioning.
-     */
-    public boolean isUserDataEnabled() {
-        if (mDataEnabledSettings.isProvisioning()) {
-            return mDataEnabledSettings.isProvisioningDataEnabled();
-        } else {
-            return mDataEnabledSettings.isUserDataEnabled();
+            setupDataOnConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION, RetryFailures.ALWAYS);
         }
     }
 
@@ -2629,10 +2433,10 @@
             // If the user did not enable data roaming, now when we transit from roaming to
             // non-roaming, we should try to reestablish the data connection.
 
-            notifyOffApnsOfAvailability(Phone.REASON_ROAMING_OFF);
-            setupDataOnConnectableApns(Phone.REASON_ROAMING_OFF);
+            notifyOffApnsOfAvailability();
+            setupDataOnConnectableApns(Phone.REASON_ROAMING_OFF, RetryFailures.ALWAYS);
         } else {
-            notifyDataConnection(Phone.REASON_ROAMING_OFF);
+            notifyDataConnection();
         }
     }
 
@@ -2662,15 +2466,15 @@
 
             if (DBG) log("onDataRoamingOnOrSettingsChanged: setup data on roaming");
 
-            setupDataOnConnectableApns(Phone.REASON_ROAMING_ON);
-            notifyDataConnection(Phone.REASON_ROAMING_ON);
+            setupDataOnConnectableApns(Phone.REASON_ROAMING_ON, RetryFailures.ALWAYS);
+            notifyDataConnection();
         } else {
             // If the user does not turn on data roaming, when we transit from non-roaming to
             // roaming, we need to tear down the data connection otherwise the user might be
             // charged for data roaming usage.
             if (DBG) log("onDataRoamingOnOrSettingsChanged: Tear down data connection on roaming.");
-            cleanUpAllConnections(true, Phone.REASON_ROAMING_ON);
-            notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON);
+            cleanUpAllConnectionsInternal(true, Phone.REASON_ROAMING_ON);
+            notifyOffApnsOfAvailability();
         }
     }
 
@@ -2696,18 +2500,18 @@
             // Assume data is connected on the simulator
             // FIXME  this can be improved
             // setState(DctConstants.State.CONNECTED);
-            notifyDataConnection(null);
+            notifyDataConnection();
 
             log("onRadioAvailable: We're on the simulator; assuming data is connected");
         }
 
         IccRecords r = mIccRecords.get();
         if (r != null && r.getRecordsLoaded()) {
-            notifyOffApnsOfAvailability(null);
+            notifyOffApnsOfAvailability();
         }
 
         if (getOverallState() != DctConstants.State.IDLE) {
-            cleanUpConnection(true, null);
+            cleanUpConnectionInternal(true, null);
         }
     }
 
@@ -2726,9 +2530,9 @@
             log("We're on the simulator; assuming radio off is meaningless");
         } else {
             if (DBG) log("onRadioOffOrNotAvailable: is off and clean up all connections");
-            cleanUpAllConnections(false, Phone.REASON_RADIO_TURNED_OFF);
+            cleanUpAllConnectionsInternal(false, Phone.REASON_RADIO_TURNED_OFF);
         }
-        notifyOffApnsOfAvailability(null);
+        notifyOffApnsOfAvailability();
     }
 
     private void completeConnection(ApnContext apnContext) {
@@ -2758,7 +2562,7 @@
                     mProvisioningSpinner));
         }
 
-        mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
+        mPhone.notifyDataConnection(apnContext.getApnType());
         startNetStatPoll();
         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
     }
@@ -2767,15 +2571,8 @@
      * A SETUP (aka bringUp) has completed, possibly with an error. If
      * there is an error this method will call {@link #onDataSetupCompleteError}.
      */
-    private void onDataSetupComplete(AsyncResult ar) {
-
-        DcFailCause cause = DcFailCause.UNKNOWN;
-        boolean handleError = false;
-        ApnContext apnContext = getValidApnContext(ar, "onDataSetupComplete");
-
-        if (apnContext == null) return;
-
-        if (ar.exception == null) {
+    private void onDataSetupComplete(ApnContext apnContext, boolean success, int cause) {
+        if (success) {
             DataConnection dataConnection = apnContext.getDataConnection();
 
             if (RADIO_TESTS) {
@@ -2798,8 +2595,7 @@
             }
             if (dataConnection == null) {
                 log("onDataSetupComplete: no connection to DC, handle as error");
-                cause = DcFailCause.CONNECTION_TO_DATACONNECTIONAC_BROKEN;
-                handleError = true;
+                onDataSetupCompleteError(apnContext);
             } else {
                 ApnSetting apn = apnContext.getApnSetting();
                 if (DBG) {
@@ -2910,32 +2706,31 @@
                 }
             }
         } else {
-            cause = (DcFailCause) (ar.result);
             if (DBG) {
                 ApnSetting apn = apnContext.getApnSetting();
                 log(String.format("onDataSetupComplete: error apn=%s cause=%s",
                         (apn == null ? "unknown" : apn.getApnName()), cause));
             }
-            if (cause.isEventLoggable()) {
+            if (DataFailCause.isEventLoggable(cause)) {
                 // Log this failure to the Event Logs.
                 int cid = getCellLocationId();
                 EventLog.writeEvent(EventLogTags.PDP_SETUP_FAIL,
-                        cause.ordinal(), cid, mTelephonyManager.getNetworkType());
+                        cause, cid, mTelephonyManager.getNetworkType());
             }
             ApnSetting apn = apnContext.getApnSetting();
-            mPhone.notifyPreciseDataConnectionFailed(apnContext.getReason(),
+            mPhone.notifyPreciseDataConnectionFailed(
                     apnContext.getApnType(), apn != null ? apn.getApnName()
-                    : "unknown", cause.toString());
+                    : "unknown", cause);
 
             // Compose broadcast intent send to the specific carrier signaling receivers
             Intent intent = new Intent(TelephonyIntents
                     .ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED);
-            intent.putExtra(TelephonyIntents.EXTRA_ERROR_CODE_KEY, cause.getErrorCode());
+            intent.putExtra(TelephonyIntents.EXTRA_ERROR_CODE_KEY, cause);
             intent.putExtra(TelephonyIntents.EXTRA_APN_TYPE_KEY, apnContext.getApnType());
             mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent);
 
-            if (cause.isRadioRestartFailure(mPhone.getContext(), mPhone.getSubId())
-                    || apnContext.restartOnError(cause.getErrorCode())) {
+            if (DataFailCause.isRadioRestartFailure(mPhone.getContext(), cause, mPhone.getSubId())
+                    || apnContext.restartOnError(cause)) {
                 if (DBG) log("Modem restarted.");
                 sendRestartRadio();
             }
@@ -2946,45 +2741,8 @@
                 log("cause = " + cause + ", mark apn as permanent failed. apn = " + apn);
                 apnContext.markApnPermanentFailed(apn);
             }
-
-            handleError = true;
+            onDataSetupCompleteError(apnContext);
         }
-
-        if (handleError) {
-            onDataSetupCompleteError(ar);
-        }
-
-        /* If flag is set to false after SETUP_DATA_CALL is invoked, we need
-         * to clean data connections.
-         */
-        if (!mDataEnabledSettings.isInternalDataEnabled()) {
-            cleanUpAllConnections(Phone.REASON_DATA_DISABLED);
-        }
-
-    }
-
-    /**
-     * check for obsolete messages.  Return ApnContext if valid, null if not
-     */
-    private ApnContext getValidApnContext(AsyncResult ar, String logString) {
-        if (ar != null && ar.userObj instanceof Pair) {
-            Pair<ApnContext, Integer>pair = (Pair<ApnContext, Integer>)ar.userObj;
-            ApnContext apnContext = pair.first;
-            if (apnContext != null) {
-                final int generation = apnContext.getConnectionGeneration();
-                if (DBG) {
-                    log("getValidApnContext (" + logString + ") on " + apnContext + " got " +
-                            generation + " vs " + pair.second);
-                }
-                if (generation == pair.second) {
-                    return apnContext;
-                } else {
-                    log("ignoring obsolete " + logString);
-                    return null;
-                }
-            }
-        }
-        throw new RuntimeException(logString + ": No apnContext");
     }
 
     /**
@@ -2993,18 +2751,13 @@
      * beginning if the list is empty. Between each SETUP request there will
      * be a delay defined by {@link #getApnDelay()}.
      */
-    private void onDataSetupCompleteError(AsyncResult ar) {
-
-        ApnContext apnContext = getValidApnContext(ar, "onDataSetupCompleteError");
-
-        if (apnContext == null) return;
-
+    private void onDataSetupCompleteError(ApnContext apnContext) {
         long delay = apnContext.getDelayForNextApn(mFailFast);
 
         // Check if we need to retry or not.
         if (delay >= 0) {
             if (DBG) log("onDataSetupCompleteError: Try next APN. delay = " + delay);
-            apnContext.setState(DctConstants.State.SCANNING);
+            apnContext.setState(DctConstants.State.RETRYING);
             // Wait a bit before trying the next APN, so that
             // we're not tying up the RIL command channel
             startAlarmForReconnect(delay, apnContext);
@@ -3012,7 +2765,7 @@
             // If we are not going to retry any APN, set this APN context to failed state.
             // This would be the final state of a data connection.
             apnContext.setState(DctConstants.State.FAILED);
-            mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType());
+            mPhone.notifyDataConnection(apnContext.getApnType());
             apnContext.setDataConnection(null);
             log("onDataSetupCompleteError: Stop retrying APNs.");
         }
@@ -3033,14 +2786,11 @@
     /**
      * Called when EVENT_DISCONNECT_DONE is received.
      */
-    private void onDisconnectDone(AsyncResult ar) {
-        ApnContext apnContext = getValidApnContext(ar, "onDisconnectDone");
-        if (apnContext == null) return;
-
+    private void onDisconnectDone(ApnContext apnContext) {
         if(DBG) log("onDisconnectDone: EVENT_DISCONNECT_DONE apnContext=" + apnContext);
         apnContext.setState(DctConstants.State.IDLE);
 
-        mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
+        mPhone.notifyDataConnection(apnContext.getApnType());
 
         // if all data connection are gone, check whether Airplane mode request was
         // pending.
@@ -3058,7 +2808,6 @@
                 }
 
                 if (mDisconnectPendingCount == 0) {
-                    notifyDataDisconnectComplete();
                     notifyAllDataDisconnected();
                 }
                 return;
@@ -3093,7 +2842,8 @@
             apnContext.setDataConnection(null);
             if (isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology())) {
                 if(DBG) log("onDisconnectDone: isOnlySigneDcAllowed true so setup single apn");
-                setupDataOnConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION);
+                setupDataOnConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION,
+                        RetryFailures.ALWAYS);
             } else {
                 if(DBG) log("onDisconnectDone: not retrying");
             }
@@ -3105,26 +2855,11 @@
         if (mDisconnectPendingCount == 0) {
             apnContext.setConcurrentVoiceAndDataAllowed(
                     mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed());
-            notifyDataDisconnectComplete();
             notifyAllDataDisconnected();
         }
 
     }
 
-    /**
-     * Called when EVENT_DISCONNECT_DC_RETRYING is received.
-     */
-    private void onDisconnectDcRetrying(AsyncResult ar) {
-        // We could just do this in DC!!!
-        ApnContext apnContext = getValidApnContext(ar, "onDisconnectDcRetrying");
-        if (apnContext == null) return;
-
-        apnContext.setState(DctConstants.State.RETRYING);
-        if(DBG) log("onDisconnectDcRetrying: apnContext=" + apnContext);
-
-        mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
-    }
-
     private void onVoiceCallStarted() {
         if (DBG) log("onVoiceCallStarted");
         mInVoiceCall = true;
@@ -3132,7 +2867,7 @@
             if (DBG) log("onVoiceCallStarted stop polling");
             stopNetStatPoll();
             stopDataStallAlarm();
-            notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED);
+            notifyDataConnection();
         }
     }
 
@@ -3143,23 +2878,14 @@
             if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
                 startNetStatPoll();
                 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
-                notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED);
+                notifyDataConnection();
             } else {
                 // clean slate after call end.
                 resetPollStats();
             }
         }
         // reset reconnect timer
-        setupDataOnConnectableApns(Phone.REASON_VOICE_CALL_ENDED);
-    }
-
-    private void onCleanUpConnection(boolean tearDown, int apnType, String reason) {
-        if (DBG) log("onCleanUpConnection");
-        ApnContext apnContext = mApnContextsByType.get(apnType);
-        if (apnContext != null) {
-            apnContext.setReason(reason);
-            cleanUpConnection(tearDown, apnContext);
-        }
+        setupDataOnConnectableApns(Phone.REASON_VOICE_CALL_ENDED, RetryFailures.ALWAYS);
     }
 
     private boolean isConnected() {
@@ -3184,16 +2910,14 @@
         return true;
     }
 
-    private void notifyDataConnection(String reason) {
-        if (DBG) log("notifyDataConnection: reason=" + reason);
+    private void notifyDataConnection() {
         for (ApnContext apnContext : mApnContexts.values()) {
             if (mAttached.get() && apnContext.isReady()) {
                 if (DBG) log("notifyDataConnection: type:" + apnContext.getApnType());
-                mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
-                        apnContext.getApnType());
+                mPhone.notifyDataConnection(apnContext.getApnType());
             }
         }
-        notifyOffApnsOfAvailability(reason);
+        notifyOffApnsOfAvailability();
     }
 
     private void setDataProfilesAsNeeded() {
@@ -3224,34 +2948,28 @@
      * Data Connections and setup the preferredApn.
      */
     private void createAllApnList() {
-        mMvnoMatched = false;
         mAllApnSettings.clear();
         IccRecords r = mIccRecords.get();
         String operator = (r != null) ? r.getOperatorNumeric() : "";
-        if (operator != null) {
-            String selection = Telephony.Carriers.NUMERIC + " = '" + operator + "'";
-            // query only enabled apn.
-            // carrier_enabled : 1 means enabled apn, 0 disabled apn.
-            // selection += " and carrier_enabled = 1";
-            if (DBG) log("createAllApnList: selection=" + selection);
 
-            // ORDER BY Telephony.Carriers._ID ("_id")
-            Cursor cursor = mPhone.getContext().getContentResolver().query(
-                    Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "filtered"),
-                    null, selection, null, Telephony.Carriers._ID);
+        // ORDER BY Telephony.Carriers._ID ("_id")
+        Cursor cursor = mPhone.getContext().getContentResolver().query(
+                Uri.withAppendedPath(Telephony.Carriers.SIM_APN_URI, "filtered/subId/"
+                        + mPhone.getSubId()), null, null, null, Telephony.Carriers._ID);
 
-            if (cursor != null) {
-                if (cursor.getCount() > 0) {
-                    mAllApnSettings = createApnList(cursor);
-                } else {
-                    if (DBG) log("createAllApnList: cursor count is 0");
-                    mApnSettingsInitializationLog.log("no APN in db for carrier: " + operator);
+        if (cursor != null) {
+            while (cursor.moveToNext()) {
+                ApnSetting apn = ApnSetting.makeApnSetting(cursor);
+                if (apn == null) {
+                    continue;
                 }
-                cursor.close();
-            } else {
-                if (DBG) log("createAllApnList: cursor is null");
-                mApnSettingsInitializationLog.log("cursor is null for carrier: " + operator);
+                mAllApnSettings.add(apn);
             }
+            cursor.close();
+        } else {
+            if (DBG) log("createAllApnList: cursor is null");
+            mApnSettingsInitializationLog.log("cursor is null for carrier, operator: "
+                    + operator);
         }
 
         addEmergencyApnSetting();
@@ -3259,8 +2977,9 @@
         dedupeApnSettings();
 
         if (mAllApnSettings.isEmpty()) {
-            if (DBG) log("createAllApnList: No APN found for carrier: " + operator);
-            mApnSettingsInitializationLog.log("no APN found for carrier: " + operator);
+            log("createAllApnList: No APN found for carrier, operator: " + operator);
+            mApnSettingsInitializationLog.log("no APN found for carrier, operator: "
+                    + operator);
             mPreferredApn = null;
             // TODO: What is the right behavior?
             //notifyNoData(DataConnection.FailCause.MISSING_UNKNOWN_APN);
@@ -3466,7 +3185,7 @@
     public ArrayList<ApnSetting> sortApnListByPreferred(ArrayList<ApnSetting> list) {
         if (list == null || list.size() <= 1) return list;
         int preferredApnSetId = getPreferredApnSetId();
-        if (preferredApnSetId != Telephony.Carriers.NO_SET_SET) {
+        if (preferredApnSetId != Telephony.Carriers.NO_APN_SET_ID) {
             list.sort(new Comparator<ApnSetting>() {
                 @Override
                 public int compare(ApnSetting apn1, ApnSetting apn2) {
@@ -3559,6 +3278,10 @@
     public void handleMessage (Message msg) {
         if (VDBG) log("handleMessage msg=" + msg);
 
+        AsyncResult ar;
+        Pair<ApnContext, Integer> pair;
+        ApnContext apnContext;
+        int generation;
         switch (msg.what) {
             case DctConstants.EVENT_RECORDS_LOADED:
                 // If onRecordsLoadedOrSubIdChanged() is not called here, it should be called on
@@ -3613,10 +3336,10 @@
                 } else {
                     // TODO: Should all PDN states be checked to fail?
                     if (mState == DctConstants.State.FAILED) {
-                        cleanUpAllConnections(false, Phone.REASON_PS_RESTRICT_ENABLED);
+                        cleanUpAllConnectionsInternal(false, Phone.REASON_PS_RESTRICT_ENABLED);
                         mReregisterOnReconnectFailure = false;
                     }
-                    ApnContext apnContext = mApnContextsByType.get(ApnSetting.TYPE_DEFAULT);
+                    apnContext = mApnContextsByType.get(ApnSetting.TYPE_DEFAULT);
                     if (apnContext != null) {
                         apnContext.setReason(Phone.REASON_PS_RESTRICT_ENABLED);
                         trySetupData(apnContext);
@@ -3631,33 +3354,21 @@
 
             case DctConstants.EVENT_TRY_SETUP_DATA:
                 if (msg.obj instanceof ApnContext) {
-                    onTrySetupData((ApnContext)msg.obj);
-                } else if (msg.obj instanceof String) {
-                    onTrySetupData((String)msg.obj);
+                    trySetupData((ApnContext) msg.obj);
                 } else {
                     loge("EVENT_TRY_SETUP request w/o apnContext or String");
                 }
                 break;
 
             case DctConstants.EVENT_CLEAN_UP_CONNECTION:
-                boolean tearDown = (msg.arg1 == 0) ? false : true;
-                if (DBG) log("EVENT_CLEAN_UP_CONNECTION tearDown=" + tearDown);
-                if (msg.obj instanceof ApnContext) {
-                    cleanUpConnection(tearDown, (ApnContext)msg.obj);
-                } else {
-                    onCleanUpConnection(tearDown, msg.arg2, (String) msg.obj);
-                }
+                if (DBG) log("EVENT_CLEAN_UP_CONNECTION");
+                cleanUpConnectionInternal(true, (ApnContext) msg.obj);
                 break;
-            case DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE: {
-                final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
-                onSetInternalDataEnabled(enabled, (Message) msg.obj);
-                break;
-            }
             case DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS:
                 if ((msg.obj != null) && (msg.obj instanceof String == false)) {
                     msg.obj = null;
                 }
-                onCleanUpAllConnections((String) msg.obj);
+                cleanUpAllConnectionsInternal(true, (String) msg.obj);
                 break;
 
             case DctConstants.EVENT_DATA_RAT_CHANGED:
@@ -3698,15 +3409,6 @@
             case DctConstants.EVENT_ROAMING_SETTING_CHANGE:
                 onDataRoamingOnOrSettingsChanged(msg.what);
                 break;
-
-            case DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE:
-                onDeviceProvisionedChange();
-                break;
-
-            case DctConstants.EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE:
-                onDeviceProvisioningDataChange();
-                break;
-
             case DctConstants.EVENT_REDIRECTION_DETECTED:
                 String url = (String) msg.obj;
                 log("dataConnectionTracker.handleMessage: EVENT_REDIRECTION_DETECTED=" + url);
@@ -3722,21 +3424,49 @@
                 break;
 
             case DctConstants.EVENT_DATA_SETUP_COMPLETE:
-                onDataSetupComplete((AsyncResult) msg.obj);
+                ar = (AsyncResult) msg.obj;
+                pair = (Pair<ApnContext, Integer>) ar.userObj;
+                apnContext = pair.first;
+                generation = pair.second;
+                if (apnContext.getConnectionGeneration() == generation) {
+                    boolean success = true;
+                    int cause = DataFailCause.UNKNOWN;
+                    if (ar.exception != null) {
+                        success = false;
+                        cause = (int) ar.result;
+                    }
+                    onDataSetupComplete(apnContext, success, cause);
+                } else {
+                    loge("EVENT_DATA_SETUP_COMPLETE: Dropped the event because generation "
+                            + "did not match.");
+                }
                 break;
 
             case DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR:
-                onDataSetupCompleteError((AsyncResult) msg.obj);
+                ar = (AsyncResult) msg.obj;
+                pair = (Pair<ApnContext, Integer>) ar.userObj;
+                apnContext = pair.first;
+                generation = pair.second;
+                if (apnContext.getConnectionGeneration() == generation) {
+                    onDataSetupCompleteError(apnContext);
+                } else {
+                    loge("EVENT_DATA_SETUP_COMPLETE_ERROR: Dropped the event because generation "
+                            + "did not match.");
+                }
                 break;
 
             case DctConstants.EVENT_DISCONNECT_DONE:
-                log("DataConnectionTracker.handleMessage: EVENT_DISCONNECT_DONE msg=" + msg);
-                onDisconnectDone((AsyncResult) msg.obj);
-                break;
-
-            case DctConstants.EVENT_DISCONNECT_DC_RETRYING:
-                log("DataConnectionTracker.handleMessage: EVENT_DISCONNECT_DC_RETRYING msg=" + msg);
-                onDisconnectDcRetrying((AsyncResult) msg.obj);
+                log("EVENT_DISCONNECT_DONE msg=" + msg);
+                ar = (AsyncResult) msg.obj;
+                pair = (Pair<ApnContext, Integer>) ar.userObj;
+                apnContext = pair.first;
+                generation = pair.second;
+                if (apnContext.getConnectionGeneration() == generation) {
+                    onDisconnectDone(apnContext);
+                } else {
+                    loge("EVENT_DISCONNECT_DONE: Dropped the event because generation "
+                            + "did not match.");
+                }
                 break;
 
             case DctConstants.EVENT_VOICE_CALL_STARTED:
@@ -3746,17 +3476,6 @@
             case DctConstants.EVENT_VOICE_CALL_ENDED:
                 onVoiceCallEnded();
                 break;
-            case DctConstants.CMD_SET_USER_DATA_ENABLE: {
-                final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
-                if (DBG) log("CMD_SET_USER_DATA_ENABLE enabled=" + enabled);
-                onSetUserDataEnabled(enabled);
-                break;
-            }
-            case DctConstants.CMD_SET_POLICY_DATA_ENABLE: {
-                final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
-                onSetPolicyDataEnabled(enabled);
-                break;
-            }
             case DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: {
                 sEnableFailFastRefCounter += (msg.arg1 == DctConstants.ENABLED) ? 1 : -1;
                 if (DBG) {
@@ -3824,7 +3543,7 @@
                         mIsProvisioning = false;
                         mProvisioningUrl = null;
                         stopProvisioningApnAlarm();
-                        sendCleanUpConnection(true, apnCtx);
+                        cleanUpConnectionInternal(true, apnCtx);
                     } else {
                         if (DBG) {
                             log("EVENT_PROVISIONING_APN_ALARM: ignore stale tag,"
@@ -3881,15 +3600,21 @@
                 handlePcoData((AsyncResult)msg.obj);
                 break;
             }
-            case DctConstants.EVENT_SET_CARRIER_DATA_ENABLED:
-                onSetCarrierDataEnabled((AsyncResult) msg.obj);
-                break;
             case DctConstants.EVENT_DATA_RECONNECT:
                 onDataReconnect(msg.getData());
                 break;
             case DctConstants.EVENT_DATA_SERVICE_BINDING_CHANGED:
                 onDataServiceBindingChanged((Boolean) ((AsyncResult) msg.obj).result);
                 break;
+            case DctConstants.EVENT_DATA_ENABLED_CHANGED:
+                ar = (AsyncResult) msg.obj;
+                if (ar.result instanceof Pair) {
+                    Pair<Boolean, Integer> p = (Pair<Boolean, Integer>) ar.result;
+                    boolean enabled = p.first;
+                    int reason = p.second;
+                    onDataEnabledChanged(enabled, reason);
+                }
+                break;
             default:
                 Rlog.e("DcTracker", "Unhandled event=" + msg);
                 break;
@@ -3959,6 +3684,11 @@
         }
     }
 
+    /**
+     * Update DcTracker.
+     *
+     * TODO: This should be cleaned up. DcTracker should listen to those events.
+     */
     public void update() {
         log("update sub = " + mPhone.getSubId());
         log("update(): Active DDS, register for all events now!");
@@ -3966,45 +3696,17 @@
 
         mAutoAttachOnCreation.set(false);
 
-        ((GsmCdmaPhone)mPhone).updateCurrentCarrierInProvider();
+        mPhone.updateCurrentCarrierInProvider();
     }
 
-    public void cleanUpAllConnections(String cause) {
-        cleanUpAllConnections(cause, null);
-    }
-
-    public void updateRecords() {
-        onUpdateIcc();
-    }
-
-    public void cleanUpAllConnections(String cause, Message disconnectAllCompleteMsg) {
-        log("cleanUpAllConnections");
-        if (disconnectAllCompleteMsg != null) {
-            mDisconnectAllCompleteMsgList.add(disconnectAllCompleteMsg);
-        }
-
-        Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS);
-        msg.obj = cause;
-        sendMessage(msg);
-    }
-
-    private void notifyDataDisconnectComplete() {
-        log("notifyDataDisconnectComplete");
-        for (Message m: mDisconnectAllCompleteMsgList) {
-            m.sendToTarget();
-        }
-        mDisconnectAllCompleteMsgList.clear();
-    }
-
-
     private void notifyAllDataDisconnected() {
         sEnableFailFastRefCounter = 0;
         mFailFast = false;
         mAllDataDisconnectedRegistrants.notifyRegistrants();
     }
 
-    public void registerForAllDataDisconnected(Handler h, int what, Object obj) {
-        mAllDataDisconnectedRegistrants.addUnique(h, what, obj);
+    public void registerForAllDataDisconnected(Handler h, int what) {
+        mAllDataDisconnectedRegistrants.addUnique(h, what, null);
 
         if (isDisconnected()) {
             log("notify All Data Disconnected");
@@ -4016,48 +3718,38 @@
         mAllDataDisconnectedRegistrants.remove(h);
     }
 
-    public void registerForDataEnabledChanged(Handler h, int what, Object obj) {
-        mDataEnabledSettings.registerForDataEnabledChanged(h, what, obj);
-    }
+    private void onDataEnabledChanged(boolean enable,
+                                      @DataEnabledChangedReason int enabledChangedReason) {
+        if (DBG) {
+            log("onDataEnabledChanged: enable=" + enable + ", enabledChangedReason="
+                    + enabledChangedReason);
+        }
 
-    public void unregisterForDataEnabledChanged(Handler h) {
-        mDataEnabledSettings.unregisterForDataEnabledChanged(h);
-    }
-
-    private void onSetInternalDataEnabled(boolean enabled, Message onCompleteMsg) {
-        if (DBG) log("onSetInternalDataEnabled: enabled=" + enabled);
-        boolean sendOnComplete = true;
-
-        mDataEnabledSettings.setInternalDataEnabled(enabled);
-        if (enabled) {
-            log("onSetInternalDataEnabled: changed to enabled, try to setup data call");
-            onTrySetupData(Phone.REASON_DATA_ENABLED);
+        if (enable) {
+            reevaluateDataConnections();
+            setupDataOnConnectableApns(Phone.REASON_DATA_ENABLED, RetryFailures.ALWAYS);
         } else {
-            sendOnComplete = false;
-            log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections");
-            cleanUpAllConnections(Phone.REASON_DATA_DISABLED, onCompleteMsg);
-        }
+            String cleanupReason;
+            switch (enabledChangedReason) {
+                case DataEnabledSettings.REASON_INTERNAL_DATA_ENABLED:
+                    cleanupReason = Phone.REASON_DATA_DISABLED_INTERNAL;
+                    break;
+                case DataEnabledSettings.REASON_DATA_ENABLED_BY_CARRIER:
+                    cleanupReason = Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN;
+                    break;
+                case DataEnabledSettings.REASON_USER_DATA_ENABLED:
+                case DataEnabledSettings.REASON_POLICY_DATA_ENABLED:
+                case DataEnabledSettings.REASON_PROVISIONED_CHANGED:
+                case DataEnabledSettings.REASON_PROVISIONING_DATA_ENABLED_CHANGED:
+                default:
+                    cleanupReason = Phone.REASON_DATA_SPECIFIC_DISABLED;
+                    break;
 
-        if (sendOnComplete) {
-            if (onCompleteMsg != null) {
-                onCompleteMsg.sendToTarget();
             }
+            cleanUpAllConnectionsInternal(true, cleanupReason);
         }
     }
 
-    public boolean setInternalDataEnabled(boolean enable) {
-        return setInternalDataEnabled(enable, null);
-    }
-
-    public boolean setInternalDataEnabled(boolean enable, Message onCompleteMsg) {
-        if (DBG) log("setInternalDataEnabled(" + enable + ")");
-
-        Message msg = obtainMessage(DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE, onCompleteMsg);
-        msg.arg1 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED);
-        sendMessage(msg);
-        return true;
-    }
-
     private void log(String s) {
         Rlog.d(mLogTag, s);
     }
@@ -4238,7 +3930,10 @@
 
             // If all of the APN settings cannot handle emergency, we add the emergency APN to the
             // list explicitly.
-            mAllApnSettings.add(mEmergencyApn);
+            if (!mAllApnSettings.contains(mEmergencyApn)) {
+                mAllApnSettings.add(mEmergencyApn);
+                log("Adding emergency APN : " + mEmergencyApn);
+            }
         }
     }
 
@@ -4262,7 +3957,7 @@
     private void cleanUpConnectionsOnUpdatedApns(boolean tearDown, String reason) {
         if (DBG) log("cleanUpConnectionsOnUpdatedApns: tearDown=" + tearDown);
         if (mAllApnSettings.isEmpty()) {
-            cleanUpAllConnections(tearDown, Phone.REASON_APN_CHANGED);
+            cleanUpAllConnectionsInternal(tearDown, Phone.REASON_APN_CHANGED);
         } else {
             int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
             if (radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
@@ -4288,7 +3983,7 @@
                     if (!apnContext.isDisconnected()) {
                         if (VDBG) log("cleanUpConnectionsOnUpdatedApns for " + apnContext);
                         apnContext.setReason(reason);
-                        cleanUpConnection(true, apnContext);
+                        cleanUpConnectionInternal(true, apnContext);
                     }
                 }
             }
@@ -4303,7 +3998,6 @@
 
         if (DBG) log("mDisconnectPendingCount = " + mDisconnectPendingCount);
         if (tearDown && mDisconnectPendingCount == 0) {
-            notifyDataDisconnectComplete();
             notifyAllDataDisconnected();
         }
     }
@@ -4523,7 +4217,7 @@
                     EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_CLEANUP,
                             mSentSinceLastRecv);
                     if (DBG) log("doRecovery() cleanup all connections");
-                    cleanUpAllConnections(Phone.REASON_PDP_RESET);
+                    cleanUpAllConnectionsInternal(true, Phone.REASON_PDP_RESET);
                     putRecoveryAction(RecoveryAction.REREGISTER);
                     break;
                 case RecoveryAction.REREGISTER:
diff --git a/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java b/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java
index ad9b6e0..a606ad6 100644
--- a/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java
+++ b/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java
@@ -18,7 +18,6 @@
 
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
-import android.content.Context;
 import android.net.NetworkCapabilities;
 import android.net.NetworkFactory;
 import android.net.NetworkRequest;
@@ -26,9 +25,11 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.Rlog;
 import android.util.LocalLog;
 
+import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneSwitcher;
 import com.android.internal.telephony.SubscriptionController;
 import com.android.internal.telephony.SubscriptionMonitor;
@@ -42,22 +43,22 @@
     public final String LOG_TAG;
     protected static final boolean DBG = true;
 
+    private static final int REQUEST_LOG_SIZE = 40;
+
+    private static final int ACTION_NO_OP   = 0;
+    private static final int ACTION_REQUEST = 1;
+    private static final int ACTION_RELEASE = 2;
+
     private final PhoneSwitcher mPhoneSwitcher;
     private final SubscriptionController mSubscriptionController;
     private final SubscriptionMonitor mSubscriptionMonitor;
     private final DcTracker mDcTracker;
+    private final LocalLog mLocalLog = new LocalLog(REQUEST_LOG_SIZE);
 
-    private final HashMap<NetworkRequest, LocalLog> mDefaultRequests =
-            new HashMap<NetworkRequest, LocalLog>();
-    private final HashMap<NetworkRequest, LocalLog> mSpecificRequests =
-            new HashMap<NetworkRequest, LocalLog>();
+    // Key: network request. Value: whether it's applied to DcTracker.
+    private final HashMap<NetworkRequest, Boolean> mNetworkRequests = new HashMap();
 
-    private final int mPhoneId;
-    // Only when this network factory is active, it will apply any network requests.
-    private boolean mIsActive;
-    // Whether this network factory is active and should handle default network requests.
-    // Default network requests are those that don't specify subscription ID.
-    private boolean mIsActiveForDefault;
+    private final Phone mPhone;
     private int mSubscriptionId;
 
     private final static int TELEPHONY_NETWORK_SCORE = 50;
@@ -68,32 +69,32 @@
     private static final int EVENT_NETWORK_REQUEST              = 3;
     private static final int EVENT_NETWORK_RELEASE              = 4;
 
-    public TelephonyNetworkFactory(PhoneSwitcher phoneSwitcher,
-            SubscriptionController subscriptionController, SubscriptionMonitor subscriptionMonitor,
-            Looper looper, Context context, int phoneId, DcTracker dcTracker) {
-        super(looper, context, "TelephonyNetworkFactory[" + phoneId + "]", null);
+    public TelephonyNetworkFactory(SubscriptionMonitor subscriptionMonitor, Looper looper,
+                                   Phone phone) {
+        super(looper, phone.getContext(), "TelephonyNetworkFactory[" + phone.getPhoneId()
+                + "]", null);
+        mPhone = phone;
         mInternalHandler = new InternalHandler(looper);
 
-        setCapabilityFilter(makeNetworkFilter(subscriptionController, phoneId));
+        mSubscriptionController = SubscriptionController.getInstance();
+
+        setCapabilityFilter(makeNetworkFilter(mSubscriptionController, mPhone.getPhoneId()));
         setScoreFilter(TELEPHONY_NETWORK_SCORE);
 
-        mPhoneSwitcher = phoneSwitcher;
-        mSubscriptionController = subscriptionController;
+        mPhoneSwitcher = PhoneSwitcher.getInstance();
         mSubscriptionMonitor = subscriptionMonitor;
-        mPhoneId = phoneId;
-        LOG_TAG = "TelephonyNetworkFactory[" + phoneId + "]";
-        mDcTracker = dcTracker;
+        LOG_TAG = "TelephonyNetworkFactory[" + mPhone.getPhoneId() + "]";
+        // TODO: Will need to dynamically route network requests to the corresponding DcTracker in
+        // the future. For now we route everything to WWAN.
+        mDcTracker = mPhone.getDcTracker(TransportType.WWAN);
 
-        mIsActive = false;
         mPhoneSwitcher.registerForActivePhoneSwitch(mInternalHandler, EVENT_ACTIVE_PHONE_SWITCH,
                 null);
 
         mSubscriptionId = INVALID_SUBSCRIPTION_ID;
-        mSubscriptionMonitor.registerForSubscriptionChanged(mPhoneId, mInternalHandler,
+        mSubscriptionMonitor.registerForSubscriptionChanged(mPhone.getPhoneId(), mInternalHandler,
                 EVENT_SUBSCRIPTION_CHANGED, null);
 
-        mIsActiveForDefault = false;
-
         register();
     }
 
@@ -150,24 +151,17 @@
         }
     }
 
-    private static final int REQUEST_LOG_SIZE = 40;
-
-    private static final int ACTION_NO_OP   = 0;
-    private static final int ACTION_REQUEST = 1;
-    private static final int ACTION_RELEASE = 2;
-
-    private void applyRequests(HashMap<NetworkRequest, LocalLog> requestMap,
-            int action, String logStr) {
+    private void applyRequestsOnActivePhoneSwitch(NetworkRequest networkRequest,
+            boolean cleanUpOnRelease, int action) {
         if (action == ACTION_NO_OP) return;
 
-        for (NetworkRequest networkRequest : requestMap.keySet()) {
-            LocalLog localLog = requestMap.get(networkRequest);
-            localLog.log(logStr);
-            if (action == ACTION_REQUEST) {
-                mDcTracker.requestNetwork(networkRequest, localLog);
-            } else if (action == ACTION_RELEASE) {
-                mDcTracker.releaseNetwork(networkRequest, localLog);
-            }
+        String logStr = "onActivePhoneSwitch: " + ((action == ACTION_REQUEST)
+                ? "Requesting" : "Releasing") + " network request " + networkRequest;
+        mLocalLog.log(logStr);
+        if (action == ACTION_REQUEST) {
+            mDcTracker.requestNetwork(networkRequest, mLocalLog);
+        } else if (action == ACTION_RELEASE) {
+            mDcTracker.releaseNetwork(networkRequest, mLocalLog, cleanUpOnRelease);
         }
     }
 
@@ -183,26 +177,24 @@
 
     // apply or revoke requests if our active-ness changes
     private void onActivePhoneSwitch() {
-        final boolean newIsActive = mPhoneSwitcher.shouldApplySpecifiedRequests(mPhoneId);
-        final boolean newIsActiveForDefault =
-                mPhoneSwitcher.shouldApplyUnspecifiedRequests(mPhoneId);
+        for (HashMap.Entry<NetworkRequest, Boolean> entry : mNetworkRequests.entrySet()) {
+            NetworkRequest networkRequest = entry.getKey();
+            boolean applied = entry.getValue();
 
-        String logString = "onActivePhoneSwitch(newIsActive " + newIsActive + ", "
-                + "newIsActiveForDefault " + newIsActiveForDefault + ")";
-        if (DBG) log(logString);
+            boolean shouldApply = mPhoneSwitcher.shouldApplyNetworkRequest(
+                    networkRequest, mPhone.getPhoneId());
 
-        applyRequests(mSpecificRequests, getAction(mIsActive, newIsActive), logString);
-        applyRequests(mDefaultRequests, getAction(mIsActiveForDefault, newIsActiveForDefault),
-                logString);
-
-        mIsActive = newIsActive;
-        mIsActiveForDefault = newIsActiveForDefault;
+            applyRequestsOnActivePhoneSwitch(networkRequest, true,
+                    getAction(applied, shouldApply));
+            mNetworkRequests.put(networkRequest, shouldApply);
+        }
     }
 
     // watch for phone->subId changes, reapply new filter and let
     // that flow through to apply/revoke of requests
     private void onSubIdChange() {
-        final int newSubscriptionId = mSubscriptionController.getSubIdUsingPhoneId(mPhoneId);
+        final int newSubscriptionId = mSubscriptionController.getSubIdUsingPhoneId(
+                mPhone.getPhoneId());
         if (mSubscriptionId != newSubscriptionId) {
             if (DBG) log("onSubIdChange " + mSubscriptionId + "->" + newSubscriptionId);
             mSubscriptionId = newSubscriptionId;
@@ -219,34 +211,17 @@
 
     private void onNeedNetworkFor(Message msg) {
         NetworkRequest networkRequest = (NetworkRequest)msg.obj;
-        boolean isApplicable = false;
-        LocalLog localLog = null;
-        if (networkRequest.networkCapabilities.getNetworkSpecifier() == null) {
-            // request only for the default network
-            localLog = mDefaultRequests.get(networkRequest);
-            if (localLog == null) {
-                localLog = new LocalLog(REQUEST_LOG_SIZE);
-                localLog.log("created for " + networkRequest);
-                mDefaultRequests.put(networkRequest, localLog);
-                isApplicable = mIsActiveForDefault;
-            }
-        } else {
-            localLog = mSpecificRequests.get(networkRequest);
-            if (localLog == null) {
-                localLog = new LocalLog(REQUEST_LOG_SIZE);
-                mSpecificRequests.put(networkRequest, localLog);
-                isApplicable = mIsActive;
-            }
-        }
-        if (isApplicable) {
-            String s = "onNeedNetworkFor";
-            localLog.log(s);
-            log(s + " " + networkRequest);
-            mDcTracker.requestNetwork(networkRequest, localLog);
-        } else {
-            String s = "not acting - isApplicable=" + isApplicable + ", mIsActive=" + mIsActive;
-            localLog.log(s);
-            log(s + " " + networkRequest);
+        boolean shouldApply = mPhoneSwitcher.shouldApplyNetworkRequest(
+                networkRequest, mPhone.getPhoneId());
+
+        mNetworkRequests.put(networkRequest, shouldApply);
+
+        String s = "onNeedNetworkFor " + networkRequest + " shouldApply " + shouldApply;
+        log(s);
+        mLocalLog.log(s);
+
+        if (shouldApply) {
+            mDcTracker.requestNetwork(networkRequest, mLocalLog);
         }
     }
 
@@ -259,25 +234,17 @@
 
     private void onReleaseNetworkFor(Message msg) {
         NetworkRequest networkRequest = (NetworkRequest)msg.obj;
-        LocalLog localLog = null;
-        boolean isApplicable = false;
-        if (networkRequest.networkCapabilities.getNetworkSpecifier() == null) {
-            // request only for the default network
-            isApplicable = mDefaultRequests.containsKey(networkRequest) && mIsActiveForDefault;
-            localLog = mDefaultRequests.remove(networkRequest);
-        } else {
-            isApplicable = mSpecificRequests.containsKey(networkRequest) && mIsActive;
-            localLog = mSpecificRequests.remove(networkRequest);
-        }
-        if (isApplicable) {
-            String s = "onReleaseNetworkFor";
-            localLog.log(s);
-            log(s + " " + networkRequest);
-            mDcTracker.releaseNetwork(networkRequest, localLog);
-        } else {
-            String s = "not releasing - isApplicable=" + isApplicable + ", mIsActive=" + mIsActive;
-            localLog.log(s);
-            log(s + " " + networkRequest);
+        boolean applied = mNetworkRequests.get(networkRequest);
+
+        mNetworkRequests.remove(networkRequest);
+
+        String s = "onReleaseNetworkFor " + networkRequest + " applied " + applied;
+        log(s);
+        mLocalLog.log(s);
+
+
+        if (applied) {
+            mDcTracker.releaseNetwork(networkRequest, mLocalLog, false);
         }
     }
 
@@ -287,16 +254,14 @@
 
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
-        pw.println(LOG_TAG + " mSubId=" + mSubscriptionId + " mIsActive=" +
-                mIsActive + " mIsActiveForDefault=" + mIsActiveForDefault);
-        pw.println("Default Requests:");
+        pw.println("Network Requests:");
         pw.increaseIndent();
-        for (NetworkRequest nr : mDefaultRequests.keySet()) {
-            pw.println(nr);
-            pw.increaseIndent();
-            mDefaultRequests.get(nr).dump(fd, pw, args);
-            pw.decreaseIndent();
+        for (HashMap.Entry<NetworkRequest, Boolean> entry : mNetworkRequests.entrySet()) {
+            NetworkRequest nr = entry.getKey();
+            boolean applied = entry.getValue();
+            pw.println((applied ? "Applied: " : "Not applied: ") + nr);
         }
+        mLocalLog.dump(fd, pw, args);
         pw.decreaseIndent();
     }
 }
diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java
new file mode 100644
index 0000000..64e12d1
--- /dev/null
+++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.emergency;
+
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemProperties;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.Rlog;
+import android.telephony.emergency.EmergencyNumber;
+import android.text.TextUtils;
+import android.util.LocalLog;
+
+import com.android.i18n.phonenumbers.ShortNumberInfo;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.LocaleTracker;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.ServiceStateTracker;
+import com.android.internal.telephony.SubscriptionController;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.phone.ecc.nano.ProtobufEccData;
+import com.android.phone.ecc.nano.ProtobufEccData.EccInfo;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.zip.GZIPInputStream;
+
+import libcore.io.IoUtils;
+
+/**
+ * Emergency Number Tracker that handles update of emergency number list from RIL and emergency
+ * number database. This is multi-sim based and each Phone has a EmergencyNumberTracker.
+ */
+public class EmergencyNumberTracker extends Handler {
+    private static final String TAG = EmergencyNumberTracker.class.getSimpleName();
+
+    /** @hide */
+    public static boolean DBG = false;
+
+    private final CommandsInterface mCi;
+    private final Phone mPhone;
+    private String mCountryIso;
+
+    private static final String EMERGENCY_NUMBER_DB_ASSETS_FILE = "eccdata";
+
+    private List<EmergencyNumber> mEmergencyNumberListFromDatabase = new ArrayList<>();
+    private List<EmergencyNumber> mEmergencyNumberListFromRadio = new ArrayList<>();
+    private List<EmergencyNumber> mEmergencyNumberList = new ArrayList<>();
+
+    private final LocalLog mEmergencyNumberListDatabaseLocalLog = new LocalLog(20);
+    private final LocalLog mEmergencyNumberListRadioLocalLog = new LocalLog(20);
+    private final LocalLog mEmergencyNumberListLocalLog = new LocalLog(20);
+
+    /** Event indicating the update for the emergency number list from the radio. */
+    private static final int EVENT_UNSOL_EMERGENCY_NUMBER_LIST = 1;
+    /**
+     * Event indicating the update for the emergency number list from the database due to the
+     * change of country code.
+     **/
+    private static final int EVENT_UPDATE_DB_COUNTRY_ISO_CHANGED = 2;
+
+    public EmergencyNumberTracker(Phone phone, CommandsInterface ci) {
+        mPhone = phone;
+        mCi = ci;
+        initializeDatabaseEmergencyNumberList();
+        mCi.registerForEmergencyNumberList(this, EVENT_UNSOL_EMERGENCY_NUMBER_LIST, null);
+    }
+
+    /**
+     * Message handler for updating emergency number list from RIL, updating emergency number list
+     * from database if the country ISO is changed, and notifying the change of emergency number
+     * list.
+     *
+     * @param msg The message
+     */
+    @Override
+    public void handleMessage(Message msg) {
+        switch (msg.what) {
+            case EVENT_UNSOL_EMERGENCY_NUMBER_LIST:
+                AsyncResult ar = (AsyncResult) msg.obj;
+                if (ar.result == null) {
+                    loge("EVENT_UNSOL_EMERGENCY_NUMBER_LIST: Result from RIL is null.");
+                } else if ((ar.result != null) && (ar.exception == null)) {
+                    updateRadioEmergencyNumberListAndNotify((List<EmergencyNumber>) ar.result);
+                } else {
+                    loge("EVENT_UNSOL_EMERGENCY_NUMBER_LIST: Exception from RIL : "
+                            + ar.exception);
+                }
+                break;
+            case EVENT_UPDATE_DB_COUNTRY_ISO_CHANGED:
+                if (msg.obj == null) {
+                    loge("EVENT_UPDATE_DB_COUNTRY_ISO_CHANGED: Result from UpdateCountryIso is"
+                            + " null.");
+                } else {
+                    updateEmergencyNumberListDatabaseAndNotify((String) msg.obj);
+                }
+                break;
+        }
+    }
+
+    private void initializeDatabaseEmergencyNumberList() {
+        mCountryIso = getInitialCountryIso().toLowerCase();
+        cacheEmergencyDatabaseByCountry(mCountryIso);
+    }
+
+    private String getInitialCountryIso() {
+        if (mPhone != null) {
+            ServiceStateTracker sst = mPhone.getServiceStateTracker();
+            if (sst != null) {
+                LocaleTracker lt = sst.getLocaleTracker();
+                if (lt != null) {
+                    return lt.getCurrentCountry();
+                }
+            }
+        }
+        return "";
+    }
+
+    /**
+     * Update Emergency Number database based on changed Country ISO.
+     *
+     * @param countryIso
+     *
+     * @hide
+     */
+    public void updateEmergencyNumberDatabaseCountryChange(String countryIso) {
+        this.obtainMessage(EVENT_UPDATE_DB_COUNTRY_ISO_CHANGED, countryIso).sendToTarget();
+    }
+
+    private EmergencyNumber convertEmergencyNumberFromEccInfo(EccInfo eccInfo, String countryIso) {
+        String phoneNumber = eccInfo.phoneNumber.trim();
+        if (phoneNumber.isEmpty()) {
+            loge("EccInfo has empty phone number.");
+            return null;
+        }
+        int emergencyServiceCategoryBitmask = 0;
+        for (int typeData : eccInfo.types) {
+            switch (typeData) {
+                case EccInfo.Type.POLICE:
+                    emergencyServiceCategoryBitmask = emergencyServiceCategoryBitmask == 0
+                            ? EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE
+                            : emergencyServiceCategoryBitmask
+                            | EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE;
+                    break;
+                case EccInfo.Type.AMBULANCE:
+                    emergencyServiceCategoryBitmask = emergencyServiceCategoryBitmask == 0
+                            ? EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE
+                            : emergencyServiceCategoryBitmask
+                            | EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE;
+                    break;
+                case EccInfo.Type.FIRE:
+                    emergencyServiceCategoryBitmask = emergencyServiceCategoryBitmask == 0
+                            ? EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE
+                            : emergencyServiceCategoryBitmask
+                            | EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE;
+                    break;
+                default:
+                    // Ignores unknown types.
+            }
+        }
+        return new EmergencyNumber(phoneNumber, countryIso, "", emergencyServiceCategoryBitmask,
+                EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE);
+    }
+
+    private void cacheEmergencyDatabaseByCountry(String countryIso) {
+        BufferedInputStream inputStream = null;
+        ProtobufEccData.AllInfo allEccMessages = null;
+        List<EmergencyNumber> updatedEmergencyNumberList = new ArrayList<>();
+        try {
+            inputStream = new BufferedInputStream(
+                    mPhone.getContext().getAssets().open(EMERGENCY_NUMBER_DB_ASSETS_FILE));
+            allEccMessages = ProtobufEccData.AllInfo.parseFrom(readInputStreamToByteArray(
+                    new GZIPInputStream(inputStream)));
+            logd("Emergency database is loaded. ");
+            for (ProtobufEccData.CountryInfo countryEccInfo : allEccMessages.countries) {
+                if (countryEccInfo.isoCode.equals(countryIso.toUpperCase())) {
+                    for (ProtobufEccData.EccInfo eccInfo : countryEccInfo.eccs) {
+                        updatedEmergencyNumberList.add(convertEmergencyNumberFromEccInfo(
+                                eccInfo, countryIso));
+                    }
+                }
+            }
+            EmergencyNumber.mergeSameNumbersInEmergencyNumberList(updatedEmergencyNumberList);
+            mEmergencyNumberListFromDatabase = updatedEmergencyNumberList;
+        } catch (IOException ex) {
+            loge("Cache emergency database failure: " + ex);
+        } finally {
+            IoUtils.closeQuietly(inputStream);
+        }
+    }
+
+    /**
+     * Util function to convert inputStream to byte array before parsing proto data.
+     */
+    private static byte[] readInputStreamToByteArray(InputStream inputStream) throws IOException {
+        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+        int nRead;
+        int size = 16 * 1024; // Read 16k chunks
+        byte[] data = new byte[size];
+        while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
+            buffer.write(data, 0, nRead);
+        }
+        buffer.flush();
+        return buffer.toByteArray();
+    }
+
+    private void updateRadioEmergencyNumberListAndNotify(
+            List<EmergencyNumber> emergencyNumberListRadio) {
+        Collections.sort(emergencyNumberListRadio);
+        logd("updateRadioEmergencyNumberListAndNotify(): receiving " + emergencyNumberListRadio);
+
+        if (!emergencyNumberListRadio.equals(mEmergencyNumberListFromRadio)) {
+            try {
+                EmergencyNumber.mergeSameNumbersInEmergencyNumberList(emergencyNumberListRadio);
+                mEmergencyNumberListFromRadio = emergencyNumberListRadio;
+                if (!DBG) {
+                    mEmergencyNumberListRadioLocalLog.log("updateRadioEmergencyNumberList:"
+                            + emergencyNumberListRadio);
+                }
+                mergeRadioAndDatabaseList();
+                if (!DBG) {
+                    mEmergencyNumberListLocalLog.log("updateRadioEmergencyNumberListAndNotify:"
+                            + mEmergencyNumberList);
+                }
+                notifyEmergencyNumberList();
+            } catch (NullPointerException ex) {
+                loge("updateRadioEmergencyNumberListAndNotify() Phone already destroyed: " + ex
+                        + " EmergencyNumberList not notified");
+            }
+        }
+    }
+
+    private void updateEmergencyNumberListDatabaseAndNotify(String countryIso) {
+        logd("updateEmergencyNumberListDatabaseAndNotify(): receiving countryIso: "
+                + countryIso);
+
+        mCountryIso = countryIso.toLowerCase();
+        cacheEmergencyDatabaseByCountry(countryIso);
+        if (!DBG) {
+            mEmergencyNumberListDatabaseLocalLog.log(
+                    "updateEmergencyNumberListDatabaseAndNotify:"
+                            + mEmergencyNumberListFromDatabase);
+        }
+        mergeRadioAndDatabaseList();
+        if (!DBG) {
+            mEmergencyNumberListLocalLog.log("updateEmergencyNumberListDatabaseAndNotify:"
+                    + mEmergencyNumberList);
+        }
+        notifyEmergencyNumberList();
+    }
+
+    private void notifyEmergencyNumberList() {
+        try {
+            if (getEmergencyNumberList() != null) {
+                mPhone.notifyEmergencyNumberList();
+                logd("notifyEmergencyNumberList(): notified");
+            }
+        } catch (NullPointerException ex) {
+            loge("notifyEmergencyNumberList(): failure: Phone already destroyed: " + ex);
+        }
+    }
+
+    /**
+     * Merge emergency numbers from the radio and database list, if they are the same emergency
+     * numbers.
+     */
+    private void mergeRadioAndDatabaseList() {
+        List<EmergencyNumber> mergedEmergencyNumberList =
+                new ArrayList<>(mEmergencyNumberListFromDatabase);
+        mergedEmergencyNumberList.addAll(mEmergencyNumberListFromRadio);
+        EmergencyNumber.mergeSameNumbersInEmergencyNumberList(mergedEmergencyNumberList);
+        Collections.sort(mergedEmergencyNumberList);
+        mEmergencyNumberList = mergedEmergencyNumberList;
+    }
+
+    /**
+     * Get the emergency number list.
+     *
+     * @return the emergency number list based on radio indication or ril.ecclist if radio
+     *         indication not support from the HAL.
+     */
+    public List<EmergencyNumber> getEmergencyNumberList() {
+        if (!mEmergencyNumberListFromRadio.isEmpty()) {
+            return new ArrayList<>(mEmergencyNumberList);
+        } else {
+            return getEmergencyNumberListFromEccList();
+        }
+    }
+
+    /**
+     * Checks if the number is an emergency number in the current Phone.
+     *
+     * @return {@code true} if it is; {@code false} otherwise.
+     */
+    public boolean isEmergencyNumber(String number, boolean exactMatch) {
+        if (!mEmergencyNumberListFromRadio.isEmpty()) {
+            for (EmergencyNumber num : mEmergencyNumberList) {
+                // According to com.android.i18n.phonenumbers.ShortNumberInfo, in
+                // these countries, if extra digits are added to an emergency number,
+                // it no longer connects to the emergency service.
+                Set<String> countriesRequiredForExactMatch = new HashSet<>();
+                countriesRequiredForExactMatch.add("br");
+                countriesRequiredForExactMatch.add("cl");
+                countriesRequiredForExactMatch.add("ni");
+                if (exactMatch || countriesRequiredForExactMatch.contains(mCountryIso)) {
+                    if (num.getNumber().equals(number)) {
+                        return true;
+                    }
+                } else {
+                    if (number.startsWith(num.getNumber())) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        } else {
+            return isEmergencyNumberFromEccList(number, exactMatch);
+        }
+    }
+
+    /**
+     * Get Emergency number list based on EccList. This util is used for solving backward
+     * compatibility if device does not support the 1.4 IRadioIndication HAL that reports
+     * emergency number list.
+     */
+    private List<EmergencyNumber> getEmergencyNumberListFromEccList() {
+        List<EmergencyNumber> emergencyNumberList = new ArrayList<>();
+        int slotId = SubscriptionController.getInstance().getSlotIndex(mPhone.getSubId());
+
+        String ecclist = (slotId <= 0) ? "ril.ecclist" : ("ril.ecclist" + slotId);
+        String emergencyNumbers = SystemProperties.get(ecclist, "");
+        if (TextUtils.isEmpty(emergencyNumbers)) {
+            // then read-only ecclist property since old RIL only uses this
+            emergencyNumbers = SystemProperties.get("ro.ril.ecclist");
+        }
+        if (!TextUtils.isEmpty(emergencyNumbers)) {
+            // searches through the comma-separated list for a match,
+            // return true if one is found.
+            for (String emergencyNum : emergencyNumbers.split(",")) {
+                emergencyNumberList.add(new EmergencyNumber(emergencyNum, "", "",
+                        EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED, 0));
+            }
+        }
+        emergencyNumbers = ((slotId < 0) ? "112,911,000,08,110,118,119,999" : "112,911");
+        for (String emergencyNum : emergencyNumbers.split(",")) {
+            emergencyNumberList.add(new EmergencyNumber(emergencyNum, "", "",
+                    EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED, 0));
+        }
+        EmergencyNumber.mergeSameNumbersInEmergencyNumberList(emergencyNumberList);
+        return emergencyNumberList;
+    }
+
+    /**
+     * Back-up old logics for {@link PhoneNumberUtils#isEmergencyNumberInternal} for legacy
+     * and deprecate purpose.
+     */
+    private boolean isEmergencyNumberFromEccList(String number, boolean useExactMatch) {
+        // If the number passed in is null, just return false:
+        if (number == null) return false;
+
+        // If the number passed in is a SIP address, return false, since the
+        // concept of "emergency numbers" is only meaningful for calls placed
+        // over the cell network.
+        // (Be sure to do this check *before* calling extractNetworkPortionAlt(),
+        // since the whole point of extractNetworkPortionAlt() is to filter out
+        // any non-dialable characters (which would turn 'abc911def@example.com'
+        // into '911', for example.))
+        if (PhoneNumberUtils.isUriNumber(number)) {
+            return false;
+        }
+
+        // Strip the separators from the number before comparing it
+        // to the list.
+        number = PhoneNumberUtils.extractNetworkPortionAlt(number);
+
+        String emergencyNumbers = "";
+        int slotId = SubscriptionController.getInstance().getSlotIndex(mPhone.getSubId());
+
+        // retrieve the list of emergency numbers
+        // check read-write ecclist property first
+        String ecclist = (slotId <= 0) ? "ril.ecclist" : ("ril.ecclist" + slotId);
+
+        emergencyNumbers = SystemProperties.get(ecclist, "");
+
+        logd("slotId:" + slotId + " country:" + mCountryIso + " emergencyNumbers: "
+                +  emergencyNumbers);
+
+        if (TextUtils.isEmpty(emergencyNumbers)) {
+            // then read-only ecclist property since old RIL only uses this
+            emergencyNumbers = SystemProperties.get("ro.ril.ecclist");
+        }
+
+        if (!TextUtils.isEmpty(emergencyNumbers)) {
+            // searches through the comma-separated list for a match,
+            // return true if one is found.
+            for (String emergencyNum : emergencyNumbers.split(",")) {
+                // It is not possible to append additional digits to an emergency number to dial
+                // the number in Brazil - it won't connect.
+                if (useExactMatch || "br".equalsIgnoreCase(mCountryIso)) {
+                    if (number.equals(emergencyNum)) {
+                        return true;
+                    }
+                } else {
+                    if (number.startsWith(emergencyNum)) {
+                        return true;
+                    }
+                }
+            }
+            // no matches found against the list!
+            return false;
+        }
+
+        logd("System property doesn't provide any emergency numbers."
+                + " Use embedded logic for determining ones.");
+
+        // If slot id is invalid, means that there is no sim card.
+        // According spec 3GPP TS22.101, the following numbers should be
+        // ECC numbers when SIM/USIM is not present.
+        emergencyNumbers = ((slotId < 0) ? "112,911,000,08,110,118,119,999" : "112,911");
+
+        for (String emergencyNum : emergencyNumbers.split(",")) {
+            if (useExactMatch) {
+                if (number.equals(emergencyNum)) {
+                    return true;
+                }
+            } else {
+                if (number.startsWith(emergencyNum)) {
+                    return true;
+                }
+            }
+        }
+
+        // No ecclist system property, so use our own list.
+        if (mCountryIso != null) {
+            ShortNumberInfo info = ShortNumberInfo.getInstance();
+            if (useExactMatch) {
+                return info.isEmergencyNumber(number, mCountryIso.toUpperCase());
+            } else {
+                return info.connectsToEmergencyNumber(number, mCountryIso.toUpperCase());
+            }
+        }
+
+        return false;
+    }
+
+
+    @VisibleForTesting
+    public List<EmergencyNumber> getRadioEmergencyNumberList() {
+        return new ArrayList<>(mEmergencyNumberListFromRadio);
+    }
+
+    private static void logd(String str) {
+        Rlog.d(TAG, str);
+    }
+
+    private static void loge(String str) {
+        Rlog.e(TAG, str);
+    }
+
+    /**
+     * Dump Emergency Number List info in the tracking
+     *
+     * @param fd FileDescriptor
+     * @param pw PrintWriter
+     * @param args args
+     */
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
+        ipw.println("mEmergencyNumberListDatabaseLocalLog:");
+        ipw.increaseIndent();
+        mEmergencyNumberListDatabaseLocalLog.dump(fd, pw, args);
+        ipw.decreaseIndent();
+        ipw.println("   -   -   -   -   -   -   -   -");
+
+        ipw.println("mEmergencyNumberListRadioLocalLog:");
+        ipw.increaseIndent();
+        mEmergencyNumberListRadioLocalLog.dump(fd, pw, args);
+        ipw.decreaseIndent();
+        ipw.println("   -   -   -   -   -   -   -   -");
+
+        ipw.println("mEmergencyNumberListLocalLog:");
+        ipw.increaseIndent();
+        mEmergencyNumberListLocalLog.dump(fd, pw, args);
+        ipw.decreaseIndent();
+
+        ipw.flush();
+    }
+}
diff --git a/src/java/com/android/internal/telephony/ims/RcsMessageStoreController.java b/src/java/com/android/internal/telephony/ims/RcsMessageStoreController.java
new file mode 100644
index 0000000..0e0add5
--- /dev/null
+++ b/src/java/com/android/internal/telephony/ims/RcsMessageStoreController.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.ims;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.ServiceManager;
+import android.provider.BaseColumns;
+import android.provider.Telephony;
+import android.telephony.Rlog;
+import android.telephony.ims.Rcs1To1Thread;
+import android.telephony.ims.RcsMessageStore;
+import android.telephony.ims.RcsParticipant;
+import android.telephony.ims.RcsThread;
+import android.telephony.ims.RcsThreadQueryContinuationToken;
+import android.telephony.ims.RcsThreadQueryParameters;
+import android.telephony.ims.RcsThreadQueryResult;
+import android.telephony.ims.aidl.IRcs;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/** Backing implementation of {@link RcsMessageStore}. */
+public class RcsMessageStoreController extends IRcs.Stub {
+    public static final String PARTICIPANT_ADDRESS_KEY = "participant_address";
+    private static final String TAG = "RcsMessageStoreController";
+    private static final String RCS_SERVICE_NAME = "ircs";
+
+    private static RcsMessageStoreController sInstance;
+
+    private final ContentResolver mContentResolver;
+
+    /** Initialize the instance. Should only be called once. */
+    public static RcsMessageStoreController init(Context context) {
+        synchronized (RcsMessageStoreController.class) {
+            if (sInstance == null) {
+                sInstance = new RcsMessageStoreController(context.getContentResolver());
+            } else {
+                Rlog.e(TAG, "init() called multiple times! sInstance = " + sInstance);
+            }
+        }
+        return sInstance;
+    }
+
+    private RcsMessageStoreController(ContentResolver contentResolver) {
+        mContentResolver = contentResolver;
+        if (ServiceManager.getService(RCS_SERVICE_NAME) == null) {
+            ServiceManager.addService(RCS_SERVICE_NAME, this);
+        }
+    }
+
+    @VisibleForTesting
+    public RcsMessageStoreController(ContentResolver contentResolver, Void unused) {
+        mContentResolver = contentResolver;
+    }
+
+    @Override
+    public void deleteThread(int threadId) {
+        // TODO - add implementation
+    }
+
+    @Override
+    public int getMessageCount(int rcsThreadId) {
+        // TODO - add implementation. Return a magic number for now to test the RPC calls
+        return 1018;
+    }
+
+    @Override
+    public RcsThreadQueryResult getRcsThreads(RcsThreadQueryParameters queryParameters) {
+        // TODO - refine implementation to include tokens for the next query
+        Cursor rcsThreadsCursor = mContentResolver.query(
+                RcsThreadQueryHelper.THREADS_URI,
+                RcsThreadQueryHelper.THREAD_PROJECTION,
+                RcsThreadQueryHelper.buildWhereClause(queryParameters),
+                null,
+                queryParameters.isAscending()
+                        ? RcsThreadQueryHelper.ASCENDING : RcsThreadQueryHelper.DESCENDING);
+
+        List<RcsThread> rcsThreadList = new ArrayList<>();
+
+        // TODO - currently this only creates 1 to 1 threads - fix this
+        while (rcsThreadsCursor != null && rcsThreadsCursor.moveToNext()) {
+            Rcs1To1Thread rcs1To1Thread = new Rcs1To1Thread(rcsThreadsCursor.getInt(0));
+            rcsThreadList.add(rcs1To1Thread);
+        }
+
+        return new RcsThreadQueryResult(null, rcsThreadList);
+    }
+
+    @Override
+    public RcsThreadQueryResult getRcsThreadsWithToken(
+            RcsThreadQueryContinuationToken continuationToken) {
+        // TODO - implement
+        return null;
+    }
+
+    @Override
+    public Rcs1To1Thread createRcs1To1Thread(RcsParticipant recipient) {
+        // TODO - use recipient to add a thread
+        ContentValues contentValues = new ContentValues(0);
+        mContentResolver.insert(RcsThreadQueryHelper.THREADS_URI, contentValues);
+
+        return null;
+    }
+
+    @Override
+    public RcsParticipant createRcsParticipant(String canonicalAddress) {
+        // Lookup the participant in RcsProvider to get the canonical row id in MmsSmsProvider
+        int rowInCanonicalAddressesTable = Integer.MIN_VALUE;
+        try (Cursor cursor = mContentResolver.query(
+                RcsParticipantQueryHelper.CANONICAL_ADDRESSES_URI,
+                new String[]{BaseColumns._ID}, Telephony.CanonicalAddressesColumns.ADDRESS + "=?",
+                new String[] {canonicalAddress}, null)) {
+            if (cursor != null && cursor.getCount() == 1 && cursor.moveToNext()) {
+                rowInCanonicalAddressesTable = cursor.getInt(0);
+            }
+        }
+
+        ContentValues contentValues = new ContentValues();
+        contentValues.put(Telephony.CanonicalAddressesColumns.ADDRESS, canonicalAddress);
+
+        if (rowInCanonicalAddressesTable == Integer.MIN_VALUE) {
+            // We couldn't find any existing canonical addresses. Add a new one.
+            Uri newCanonicalAddress = mContentResolver.insert(
+                    RcsParticipantQueryHelper.CANONICAL_ADDRESSES_URI, contentValues);
+            if (newCanonicalAddress != null) {
+                try {
+                    rowInCanonicalAddressesTable = Integer.parseInt(
+                            newCanonicalAddress.getLastPathSegment());
+                } catch (NumberFormatException e) {
+                    Rlog.e(TAG, "Uri returned after canonical address insertion is malformed: "
+                            + newCanonicalAddress, e);
+                    return null;
+                }
+            }
+        }
+
+        // Now we have a row in canonical_addresses table, and its value is in
+        // rowInCanonicalAddressesTable. Put this row id in RCS participants table.
+        contentValues.clear();
+        contentValues.put(RcsParticipantQueryHelper.RCS_CANONICAL_ADDRESS_ID,
+                rowInCanonicalAddressesTable);
+
+        Uri newParticipantUri = mContentResolver.insert(RcsParticipantQueryHelper.PARTICIPANTS_URI,
+                contentValues);
+        int newParticipantRowId;
+
+        try {
+            if (newParticipantUri != null) {
+                newParticipantRowId = Integer.parseInt(newParticipantUri.getLastPathSegment());
+            } else {
+                Rlog.e(TAG, "Error inserting new participant into RcsProvider");
+                return null;
+            }
+        } catch (NumberFormatException e) {
+            Rlog.e(TAG,
+                    "Uri returned after creating a participant is malformed: " + newParticipantUri);
+            return null;
+        }
+
+        return new RcsParticipant(newParticipantRowId, canonicalAddress);
+    }
+
+    /**
+     * TODO(sahinc) Instead of sending the update query directly to RcsProvider, this function
+     * orchestrates between RcsProvider and MmsSmsProvider. This is because we are not fully decided
+     * on whether we should have RCS storage in a separate database file.
+     */
+    @Override
+    public void updateRcsParticipantCanonicalAddress(int id, String canonicalAddress) {
+        // TODO - implement
+    }
+
+    @Override
+    public void updateRcsParticipantAlias(int id, String alias) {
+        ContentValues contentValues = new ContentValues(1);
+        contentValues.put(RcsParticipantQueryHelper.RCS_ALIAS_COLUMN, alias);
+
+        mContentResolver.update(RcsParticipantQueryHelper.PARTICIPANTS_URI, contentValues,
+                BaseColumns._ID + "=?", new String[] {Integer.toString(id)});
+    }
+}
diff --git a/src/java/com/android/internal/telephony/ims/RcsParticipantQueryHelper.java b/src/java/com/android/internal/telephony/ims/RcsParticipantQueryHelper.java
new file mode 100644
index 0000000..82c37d0
--- /dev/null
+++ b/src/java/com/android/internal/telephony/ims/RcsParticipantQueryHelper.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.telephony.ims;
+
+import android.net.Uri;
+
+class RcsParticipantQueryHelper {
+    // Note: row Id needs to be appended to this URI to modify the canonical address
+    static final String INDIVIDUAL_CANONICAL_ADDRESS_URI_AS_STRING =
+            "content://mms-sms/canonical-address/";
+    static final Uri CANONICAL_ADDRESSES_URI = Uri.parse("content://mms-sms/canonical-addresses");
+
+    static final Uri PARTICIPANTS_URI = Uri.parse("content://rcs/participant");
+    static final String RCS_ALIAS_COLUMN = "rcs_alias";
+    static final String RCS_CANONICAL_ADDRESS_ID = "canonical_address_id";
+}
diff --git a/src/java/com/android/internal/telephony/ims/RcsThreadQueryHelper.java b/src/java/com/android/internal/telephony/ims/RcsThreadQueryHelper.java
new file mode 100644
index 0000000..9f84f59
--- /dev/null
+++ b/src/java/com/android/internal/telephony/ims/RcsThreadQueryHelper.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.telephony.ims;
+
+import android.net.Uri;
+import android.telephony.ims.RcsThreadQueryParameters;
+
+/**
+ * A helper class focused on querying RCS threads from the
+ * {@link com.android.providers.telephony.RcsProvider}
+ */
+class RcsThreadQueryHelper {
+    static final String ASCENDING = "ASCENDING";
+    static final String DESCENDING = "DESCENDING";
+    static final String THREAD_ID = "_id";
+
+    static final Uri THREADS_URI = Uri.parse("content://rcs/thread");
+    static final Uri PARTICIPANTS_URI = Uri.parse("content://rcs/participant");
+    static final String[] THREAD_PROJECTION = new String[]{THREAD_ID};
+
+    static String buildWhereClause(RcsThreadQueryParameters queryParameters) {
+        // TODO - implement
+        return null;
+    }
+}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
index ea5f671..ab39212 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
@@ -256,8 +256,11 @@
         // setting the multiendpoint listener on the external call tracker.  So we need to ensure
         // the external call tracker is available first to avoid potential timing issues.
         mExternalCallTracker =
-                TelephonyComponentFactory.getInstance().makeImsExternalCallTracker(this);
-        mCT = TelephonyComponentFactory.getInstance().makeImsPhoneCallTracker(this);
+                TelephonyComponentFactory.getInstance()
+                        .inject(ImsExternalCallTracker.class.getName())
+                        .makeImsExternalCallTracker(this);
+        mCT = TelephonyComponentFactory.getInstance().inject(ImsPhoneCallTracker.class.getName())
+                .makeImsPhoneCallTracker(this);
         mCT.registerPhoneStateListener(mExternalCallTracker);
         mExternalCallTracker.setCallPuller(mCT);
 
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java
index 714343d..c54643b 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java
@@ -207,8 +207,6 @@
 
     public void notifyDisconnect(Connection cn) {
         mDisconnectRegistrants.notifyResult(cn);
-
-        mNotifier.notifyDisconnectCause(cn.getDisconnectCause(), cn.getPreciseDisconnectCause());
     }
 
     void notifyUnknownConnection() {
@@ -460,16 +458,6 @@
         return false;
     }
 
-    @Override
-    public boolean isDataEnabled() {
-        return false;
-    }
-
-    @Override
-    public void setUserDataEnabled(boolean enable) {
-    }
-
-
     public boolean enableDataConnectivity() {
         return false;
     }
@@ -479,7 +467,7 @@
     }
 
     @Override
-    public boolean isDataAllowed() {
+    public boolean isDataAllowed(int apnType) {
         return false;
     }
 
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index 9bd3099..99fce41 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -49,12 +49,11 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.PreciseDisconnectCause;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
-import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
 import android.telephony.TelephonyManager;
+import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.ImsCallProfile;
 import android.telephony.ims.ImsMmTelManager;
 import android.telephony.ims.ImsReasonInfo;
@@ -68,7 +67,6 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Pair;
-import android.util.SparseIntArray;
 
 import com.android.ims.ImsCall;
 import com.android.ims.ImsConfig;
@@ -96,6 +94,7 @@
 import com.android.internal.telephony.SubscriptionController;
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.dataconnection.DataEnabledSettings;
+import com.android.internal.telephony.dataconnection.DataEnabledSettings.DataEnabledChangedReason;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState;
@@ -406,237 +405,6 @@
     private boolean mSupportDowngradeVtToAudio = false;
 
     /**
-     * Stores the mapping of {@code ImsReasonInfo#CODE_*} to {@code PreciseDisconnectCause#*}
-     */
-    private static final SparseIntArray PRECISE_CAUSE_MAP = new SparseIntArray();
-    static {
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT,
-                PreciseDisconnectCause.LOCAL_ILLEGAL_ARGUMENT);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_ILLEGAL_STATE,
-                PreciseDisconnectCause.LOCAL_ILLEGAL_STATE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_INTERNAL_ERROR,
-                PreciseDisconnectCause.LOCAL_INTERNAL_ERROR);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN,
-                PreciseDisconnectCause.LOCAL_IMS_SERVICE_DOWN);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_NO_PENDING_CALL,
-                PreciseDisconnectCause.LOCAL_NO_PENDING_CALL);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_ENDED_BY_CONFERENCE_MERGE,
-                PreciseDisconnectCause.NORMAL);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_POWER_OFF,
-                PreciseDisconnectCause.LOCAL_POWER_OFF);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_LOW_BATTERY,
-                PreciseDisconnectCause.LOCAL_LOW_BATTERY);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_NETWORK_NO_SERVICE,
-                PreciseDisconnectCause.LOCAL_NETWORK_NO_SERVICE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_NETWORK_NO_LTE_COVERAGE,
-                PreciseDisconnectCause.LOCAL_NETWORK_NO_LTE_COVERAGE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_NETWORK_ROAMING,
-                PreciseDisconnectCause.LOCAL_NETWORK_ROAMING);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_NETWORK_IP_CHANGED,
-                PreciseDisconnectCause.LOCAL_NETWORK_IP_CHANGED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE,
-                PreciseDisconnectCause.LOCAL_SERVICE_UNAVAILABLE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED,
-                PreciseDisconnectCause.LOCAL_NOT_REGISTERED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_CALL_EXCEEDED,
-                PreciseDisconnectCause.LOCAL_MAX_CALL_EXCEEDED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_CALL_DECLINE,
-                PreciseDisconnectCause.LOCAL_CALL_DECLINE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_CALL_VCC_ON_PROGRESSING,
-                PreciseDisconnectCause.LOCAL_CALL_VCC_ON_PROGRESSING);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_CALL_RESOURCE_RESERVATION_FAILED,
-                PreciseDisconnectCause.LOCAL_CALL_RESOURCE_RESERVATION_FAILED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED,
-                PreciseDisconnectCause.LOCAL_CALL_CS_RETRY_REQUIRED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_CALL_VOLTE_RETRY_REQUIRED,
-                PreciseDisconnectCause.LOCAL_CALL_VOLTE_RETRY_REQUIRED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_CALL_TERMINATED,
-                PreciseDisconnectCause.LOCAL_CALL_TERMINATED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_HO_NOT_FEASIBLE,
-                PreciseDisconnectCause.LOCAL_HO_NOT_FEASIBLE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_TIMEOUT_1XX_WAITING,
-                PreciseDisconnectCause.TIMEOUT_1XX_WAITING);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_TIMEOUT_NO_ANSWER,
-                PreciseDisconnectCause.TIMEOUT_NO_ANSWER);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_TIMEOUT_NO_ANSWER_CALL_UPDATE,
-                PreciseDisconnectCause.TIMEOUT_NO_ANSWER_CALL_UPDATE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_FDN_BLOCKED,
-                PreciseDisconnectCause.FDN_BLOCKED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_REDIRECTED,
-                PreciseDisconnectCause.SIP_REDIRECTED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_BAD_REQUEST,
-                PreciseDisconnectCause.SIP_BAD_REQUEST);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_FORBIDDEN,
-                PreciseDisconnectCause.SIP_FORBIDDEN);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_NOT_FOUND,
-                PreciseDisconnectCause.SIP_NOT_FOUND);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_NOT_SUPPORTED,
-                PreciseDisconnectCause.SIP_NOT_SUPPORTED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_REQUEST_TIMEOUT,
-                PreciseDisconnectCause.SIP_REQUEST_TIMEOUT);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_TEMPRARILY_UNAVAILABLE,
-                PreciseDisconnectCause.SIP_TEMPRARILY_UNAVAILABLE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_BAD_ADDRESS,
-                PreciseDisconnectCause.SIP_BAD_ADDRESS);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_BUSY,
-                PreciseDisconnectCause.SIP_BUSY);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_REQUEST_CANCELLED,
-                PreciseDisconnectCause.SIP_REQUEST_CANCELLED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_NOT_ACCEPTABLE,
-                PreciseDisconnectCause.SIP_NOT_ACCEPTABLE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_NOT_REACHABLE,
-                PreciseDisconnectCause.SIP_NOT_REACHABLE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_CLIENT_ERROR,
-                PreciseDisconnectCause.SIP_CLIENT_ERROR);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_TRANSACTION_DOES_NOT_EXIST,
-                PreciseDisconnectCause.SIP_TRANSACTION_DOES_NOT_EXIST);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_SERVER_INTERNAL_ERROR,
-                PreciseDisconnectCause.SIP_SERVER_INTERNAL_ERROR);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_SERVICE_UNAVAILABLE,
-                PreciseDisconnectCause.SIP_SERVICE_UNAVAILABLE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_SERVER_TIMEOUT,
-                PreciseDisconnectCause.SIP_SERVER_TIMEOUT);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_SERVER_ERROR,
-                PreciseDisconnectCause.SIP_SERVER_ERROR);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_USER_REJECTED,
-                PreciseDisconnectCause.SIP_USER_REJECTED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SIP_GLOBAL_ERROR,
-                PreciseDisconnectCause.SIP_GLOBAL_ERROR);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_EMERGENCY_TEMP_FAILURE,
-                PreciseDisconnectCause.EMERGENCY_TEMP_FAILURE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_EMERGENCY_PERM_FAILURE,
-                PreciseDisconnectCause.EMERGENCY_PERM_FAILURE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_MEDIA_INIT_FAILED,
-                PreciseDisconnectCause.MEDIA_INIT_FAILED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_MEDIA_NO_DATA,
-                PreciseDisconnectCause.MEDIA_NO_DATA);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_MEDIA_NOT_ACCEPTABLE,
-                PreciseDisconnectCause.MEDIA_NOT_ACCEPTABLE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_MEDIA_UNSPECIFIED,
-                PreciseDisconnectCause.MEDIA_UNSPECIFIED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_USER_TERMINATED,
-                PreciseDisconnectCause.USER_TERMINATED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_USER_NOANSWER,
-                PreciseDisconnectCause.USER_NOANSWER);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_USER_IGNORE,
-                PreciseDisconnectCause.USER_IGNORE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_USER_DECLINE,
-                PreciseDisconnectCause.USER_DECLINE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOW_BATTERY,
-                PreciseDisconnectCause.LOW_BATTERY);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_BLACKLISTED_CALL_ID,
-                PreciseDisconnectCause.BLACKLISTED_CALL_ID);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_USER_TERMINATED_BY_REMOTE,
-                PreciseDisconnectCause.USER_TERMINATED_BY_REMOTE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_UT_NOT_SUPPORTED,
-                PreciseDisconnectCause.UT_NOT_SUPPORTED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE,
-                PreciseDisconnectCause.UT_SERVICE_UNAVAILABLE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_UT_OPERATION_NOT_ALLOWED,
-                PreciseDisconnectCause.UT_OPERATION_NOT_ALLOWED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_UT_NETWORK_ERROR,
-                PreciseDisconnectCause.UT_NETWORK_ERROR);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_UT_CB_PASSWORD_MISMATCH,
-                PreciseDisconnectCause.UT_CB_PASSWORD_MISMATCH);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_ECBM_NOT_SUPPORTED,
-                PreciseDisconnectCause.ECBM_NOT_SUPPORTED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_MULTIENDPOINT_NOT_SUPPORTED,
-                PreciseDisconnectCause.MULTIENDPOINT_NOT_SUPPORTED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE,
-                PreciseDisconnectCause.CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_ANSWERED_ELSEWHERE,
-                PreciseDisconnectCause.ANSWERED_ELSEWHERE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_CALL_PULL_OUT_OF_SYNC,
-                PreciseDisconnectCause.CALL_PULL_OUT_OF_SYNC);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_CALL_END_CAUSE_CALL_PULL,
-                PreciseDisconnectCause.CALL_PULLED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SUPP_SVC_FAILED,
-                PreciseDisconnectCause.SUPP_SVC_FAILED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SUPP_SVC_CANCELLED,
-                PreciseDisconnectCause.SUPP_SVC_CANCELLED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_SUPP_SVC_REINVITE_COLLISION,
-                PreciseDisconnectCause.SUPP_SVC_REINVITE_COLLISION);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_IWLAN_DPD_FAILURE,
-                PreciseDisconnectCause.IWLAN_DPD_FAILURE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_EPDG_TUNNEL_ESTABLISH_FAILURE,
-                PreciseDisconnectCause.EPDG_TUNNEL_ESTABLISH_FAILURE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_EPDG_TUNNEL_REKEY_FAILURE,
-                PreciseDisconnectCause.EPDG_TUNNEL_REKEY_FAILURE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_EPDG_TUNNEL_LOST_CONNECTION,
-                PreciseDisconnectCause.EPDG_TUNNEL_LOST_CONNECTION);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_MAXIMUM_NUMBER_OF_CALLS_REACHED,
-                PreciseDisconnectCause.MAXIMUM_NUMBER_OF_CALLS_REACHED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_REMOTE_CALL_DECLINE,
-                PreciseDisconnectCause.REMOTE_CALL_DECLINE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_DATA_LIMIT_REACHED,
-                PreciseDisconnectCause.DATA_LIMIT_REACHED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_DATA_DISABLED,
-                PreciseDisconnectCause.DATA_DISABLED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_WIFI_LOST,
-                PreciseDisconnectCause.WIFI_LOST);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_RADIO_OFF,
-                PreciseDisconnectCause.RADIO_OFF);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_NO_VALID_SIM,
-                PreciseDisconnectCause.NO_VALID_SIM);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_RADIO_INTERNAL_ERROR,
-                PreciseDisconnectCause.RADIO_INTERNAL_ERROR);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_NETWORK_RESP_TIMEOUT,
-                PreciseDisconnectCause.NETWORK_RESP_TIMEOUT);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_NETWORK_REJECT,
-                PreciseDisconnectCause.NETWORK_REJECT);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_RADIO_ACCESS_FAILURE,
-                PreciseDisconnectCause.RADIO_ACCESS_FAILURE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_RADIO_LINK_FAILURE,
-                PreciseDisconnectCause.RADIO_LINK_FAILURE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_RADIO_LINK_LOST,
-                PreciseDisconnectCause.RADIO_LINK_LOST);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_RADIO_UPLINK_FAILURE,
-                PreciseDisconnectCause.RADIO_UPLINK_FAILURE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_RADIO_SETUP_FAILURE,
-                PreciseDisconnectCause.RADIO_SETUP_FAILURE);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_RADIO_RELEASE_NORMAL,
-                PreciseDisconnectCause.RADIO_RELEASE_NORMAL);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_RADIO_RELEASE_ABNORMAL,
-                PreciseDisconnectCause.RADIO_RELEASE_ABNORMAL);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_ACCESS_CLASS_BLOCKED,
-                PreciseDisconnectCause.ACCESS_CLASS_BLOCKED);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_NETWORK_DETACH,
-                PreciseDisconnectCause.NETWORK_DETACH);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_UNOBTAINABLE_NUMBER,
-                PreciseDisconnectCause.UNOBTAINABLE_NUMBER);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_1,
-                PreciseDisconnectCause.OEM_CAUSE_1);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_2,
-                PreciseDisconnectCause.OEM_CAUSE_2);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_3,
-                PreciseDisconnectCause.OEM_CAUSE_3);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_4,
-                PreciseDisconnectCause.OEM_CAUSE_4);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_5,
-                PreciseDisconnectCause.OEM_CAUSE_5);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_6,
-                PreciseDisconnectCause.OEM_CAUSE_6);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_7,
-                PreciseDisconnectCause.OEM_CAUSE_7);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_8,
-                PreciseDisconnectCause.OEM_CAUSE_8);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_9,
-                PreciseDisconnectCause.OEM_CAUSE_9);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_10,
-                PreciseDisconnectCause.OEM_CAUSE_10);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_11,
-                PreciseDisconnectCause.OEM_CAUSE_11);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_12,
-                PreciseDisconnectCause.OEM_CAUSE_12);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_13,
-                PreciseDisconnectCause.OEM_CAUSE_13);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_14,
-                PreciseDisconnectCause.OEM_CAUSE_14);
-        PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_OEM_CAUSE_15,
-                PreciseDisconnectCause.OEM_CAUSE_15);
-    }
-
-    /**
      * Carrier configuration option which determines whether the carrier wants to inform the user
      * when a video call is handed over from WIFI to LTE.
      * See {@link CarrierConfigManager#KEY_NOTIFY_HANDOVER_VIDEO_FROM_WIFI_TO_LTE_BOOL} for more
@@ -721,7 +489,7 @@
         mPhone.getContext().registerReceiver(mReceiver, intentfilter);
         cacheCarrierConfiguration(mPhone.getSubId());
 
-        mPhone.getDefaultPhone().registerForDataEnabledChanged(
+        mPhone.getDefaultPhone().getDataEnabledSettings().registerForDataEnabledChanged(
                 this, EVENT_DATA_ENABLED_CHANGED, null);
 
         final TelecomManager telecomManager =
@@ -858,7 +626,7 @@
             mUtInterface.unregisterForSuppServiceIndication(this);
         }
         mPhone.getContext().unregisterReceiver(mReceiver);
-        mPhone.getDefaultPhone().unregisterForDataEnabledChanged(this);
+        mPhone.getDefaultPhone().getDataEnabledSettings().unregisterForDataEnabledChanged(this);
         mImsManagerConnector.disconnect();
     }
 
@@ -1200,8 +968,9 @@
 
         // Always unmute when initiating a new call
         setMute(false);
-        int serviceType = mPhoneNumberUtilsProxy.isEmergencyNumber(conn.getAddress()) ?
-                ImsCallProfile.SERVICE_TYPE_EMERGENCY : ImsCallProfile.SERVICE_TYPE_NORMAL;
+        boolean isEmergencyCall = mPhoneNumberUtilsProxy.isEmergencyNumber(conn.getAddress());
+        int serviceType = isEmergencyCall
+                ? ImsCallProfile.SERVICE_TYPE_EMERGENCY : ImsCallProfile.SERVICE_TYPE_NORMAL;
         int callType = ImsCallProfile.getCallTypeFromVideoState(videoState);
         //TODO(vt): Is this sufficient?  At what point do we know the video state of the call?
         conn.setVideoState(videoState);
@@ -1211,6 +980,28 @@
             ImsCallProfile profile = mImsManager.createCallProfile(serviceType, callType);
             profile.setCallExtraInt(ImsCallProfile.EXTRA_OIR, clirMode);
 
+            if (isEmergencyCall) {
+                // Set emergency service categories in ImsCallProfile
+                int emergencyServiceCategories =
+                        EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED;
+                TelephonyManager tm = (TelephonyManager) mPhone.getContext().getSystemService(
+                        Context.TELEPHONY_SERVICE);
+                if (tm.getCurrentEmergencyNumberList() != null) {
+                    for (List<EmergencyNumber> emergencyNumberList :
+                            tm.getCurrentEmergencyNumberList().values()) {
+                        if (emergencyNumberList != null) {
+                            for (EmergencyNumber num : emergencyNumberList) {
+                                if (num.getNumber().equals(conn.getAddress())) {
+                                    emergencyServiceCategories =
+                                            num.getEmergencyServiceCategoryBitmask();
+                                }
+                            }
+                        }
+                    }
+                }
+                profile.setEmergencyServiceCategories(emergencyServiceCategories);
+            }
+
             // Translate call subject intent-extra from Telecom-specific extra key to the
             // ImsCallProfile key.
             if (intentExtras != null) {
@@ -2201,11 +1992,6 @@
         return cause;
     }
 
-    private int getPreciseDisconnectCauseFromReasonInfo(ImsReasonInfo reasonInfo) {
-        return PRECISE_CAUSE_MAP.get(maybeRemapReasonCode(reasonInfo),
-                PreciseDisconnectCause.ERROR_UNSPECIFIED);
-    }
-
     /**
      * @return true if the phone is in Emergency Callback mode, otherwise false
      */
@@ -2404,10 +2190,6 @@
             mMetrics.writeOnImsCallTerminated(mPhone.getPhoneId(), imsCall.getCallSession(),
                     reasonInfo);
 
-            if(conn != null) {
-                conn.setPreciseDisconnectCause(getPreciseDisconnectCauseFromReasonInfo(reasonInfo));
-            }
-
             if (reasonInfo.getCode() == ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL
                     && mAutoRetryFailedWifiEmergencyCall) {
                 Pair<ImsCall, ImsReasonInfo> callInfo = new Pair<>(imsCall, reasonInfo);
@@ -2566,7 +2348,7 @@
                         dialPendingMO();
                     }
                     mHoldSwitchingState = HoldSwapState.INACTIVE;
-                } else if (mPendingMO.isEmergency()) {
+                } else if (mPendingMO != null && mPendingMO.isEmergency()) {
                     // If mPendingMO is an emergency call, disconnect the call that we tried to
                     // hold.
                     mBackgroundCall.getImsCall().terminate(ImsReasonInfo.CODE_UNSPECIFIED);
@@ -2803,7 +2585,9 @@
             // Check with the DCTracker to see if data is enabled; there may be a case when
             // ImsPhoneCallTracker isn't being informed of the right data enabled state via its
             // registration, so we'll refresh now.
-            boolean isDataEnabled = mPhone.getDefaultPhone().mDcTracker.isDataEnabled();
+            boolean isDataEnabled = mPhone.getDefaultPhone().getDataEnabledSettings()
+                    .isDataEnabled();
+
             if (DBG) {
                 log("onCallHandover ::  srcAccessTech=" + srcAccessTech + ", targetAccessTech="
                         + targetAccessTech + ", reasonInfo=" + reasonInfo + ", dataEnabled="
@@ -3155,11 +2939,6 @@
         }
         int cause = getDisconnectCauseFromReasonInfo(reasonInfo, callState);
 
-        if (conn != null) {
-            conn.setPreciseDisconnectCause(
-                    getPreciseDisconnectCauseFromReasonInfo(reasonInfo));
-        }
-
         processCallStateChange(imsCall, ImsPhoneCall.State.DISCONNECTED, cause);
     }
 
@@ -3850,10 +3629,9 @@
     /**
      * Handler of data enabled changed event
      * @param enabled True if data is enabled, otherwise disabled.
-     * @param reason Reason for data enabled/disabled (see {@code REASON_*} in
-     *      {@link DataEnabledSettings}.
+     * @param reason Reason for data enabled/disabled. See {@link DataEnabledChangedReason}.
      */
-    private void onDataEnabledChanged(boolean enabled, int reason) {
+    private void onDataEnabledChanged(boolean enabled, @DataEnabledChangedReason int reason) {
 
         log("onDataEnabledChanged: enabled=" + enabled + ", reason=" + reason);
 
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
index 2d024d1..3f96b59 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
@@ -102,12 +102,13 @@
     }
 
     @Override
-    public void dial(String address, int clirMode, Message result) {
+    public void dial(String address, boolean isEmergencyCall, int emergencyServiceCategories,
+               int clirMode, Message result) {
     }
 
     @Override
-    public void dial(String address, int clirMode, UUSInfo uusInfo,
-            Message result) {
+    public void dial(String address, boolean isEmergencyCall, int emergencyServiceCategories,
+              int clirMode, UUSInfo uusInfo, Message result) {
     }
 
     @Override
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
index 4d4d186..8dc9143 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
@@ -46,6 +46,7 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.UUSInfo;
+import com.android.internal.telephony.metrics.TelephonyMetrics;
 
 import java.util.Objects;
 
@@ -64,6 +65,7 @@
     private ImsPhoneCall mParent;
     private ImsCall mImsCall;
     private Bundle mExtras = new Bundle();
+    private TelephonyMetrics mMetrics = TelephonyMetrics.getInstance();
 
     private boolean mDisconnected;
 
@@ -123,6 +125,9 @@
      */
     private boolean mIsLocalVideoCapable = true;
 
+    // Store the current audio codec
+    private int mAudioCodec = ImsStreamMediaProfile.AUDIO_QUALITY_NONE;
+
     //***** Event Constants
     private static final int EVENT_DTMF_DONE = 1;
     private static final int EVENT_PAUSE_DONE = 2;
@@ -964,6 +969,13 @@
                 }
             }
 
+            // Metrics for audio codec
+            if (localCallProfile != null
+                    && localCallProfile.mMediaProfile.mAudioQuality != mAudioCodec) {
+                mAudioCodec = localCallProfile.mMediaProfile.mAudioQuality;
+                mMetrics.writeAudioCodecIms(mOwner.mPhone.getPhoneId(), imsCall.getCallSession());
+            }
+
             int newAudioQuality =
                     getAudioQualityFromCallProfile(localCallProfile, remoteCallProfile);
             if (getAudioQuality() != newAudioQuality) {
diff --git a/src/java/com/android/internal/telephony/metrics/CallSessionEventBuilder.java b/src/java/com/android/internal/telephony/metrics/CallSessionEventBuilder.java
index a8221b4..b4a5e6e 100644
--- a/src/java/com/android/internal/telephony/metrics/CallSessionEventBuilder.java
+++ b/src/java/com/android/internal/telephony/metrics/CallSessionEventBuilder.java
@@ -130,4 +130,10 @@
         mEvent.calls = rilCalls;
         return this;
     }
+
+    /** Set the audio codec. */
+    public CallSessionEventBuilder setAudioCodec(int audioCodec) {
+        mEvent.audioCodec = audioCodec;
+        return this;
+    }
 }
diff --git a/src/java/com/android/internal/telephony/metrics/ModemPowerMetrics.java b/src/java/com/android/internal/telephony/metrics/ModemPowerMetrics.java
index 8001eb6..f8d519c 100644
--- a/src/java/com/android/internal/telephony/metrics/ModemPowerMetrics.java
+++ b/src/java/com/android/internal/telephony/metrics/ModemPowerMetrics.java
@@ -60,9 +60,16 @@
             m.rxTimeMs = stats.getRxTimeMs();
             long[] t = stats.getTxTimeMs();
             m.txTimeMs = new long[t.length];
-            for (int i = 0; i < t.length; i++) {
-                m.txTimeMs[i] = t[i];
-            }
+            System.arraycopy(t, 0, m.txTimeMs, 0, t.length);
+            m.numBytesTx = stats.getNumBytesTx();
+            m.numPacketsRx = stats.getNumPacketsRx();
+            m.numBytesRx = stats.getNumBytesRx();
+            long[] tr = stats.getTimeInRatMs();
+            m.timeInRatMs = new long[tr.length];
+            System.arraycopy(tr, 0, m.timeInRatMs, 0, tr.length);
+            long[] trx = stats.getTimeInRxSignalStrengthLevelMs();
+            m.timeInRxSignalStrengthLevelMs = new long[trx.length];
+            System.arraycopy(trx, 0, m.timeInRxSignalStrengthLevelMs, 0, trx.length);
         }
         return m;
     }
diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
index e06a5c0..ac219ea 100644
--- a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
+++ b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
@@ -38,6 +38,7 @@
 import android.hardware.radio.V1_0.SetupDataCallResult;
 import android.os.Build;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SmsManager;
@@ -46,8 +47,10 @@
 import android.telephony.TelephonyManager;
 import android.telephony.data.DataCallResponse;
 import android.telephony.data.DataService;
+import android.telephony.ims.ImsCallProfile;
 import android.telephony.ims.ImsCallSession;
 import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.ImsStreamMediaProfile;
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.telephony.ims.stub.ImsSmsImplBase;
@@ -55,6 +58,7 @@
 import android.util.Base64;
 import android.util.SparseArray;
 
+import com.android.internal.telephony.DriverCall;
 import com.android.internal.telephony.GsmCdmaConnection;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.RIL;
@@ -161,6 +165,11 @@
      */
     private final SparseArray<TelephonySettings> mLastSettings = new SparseArray<>();
 
+    /**
+     * Last carrier id matching.
+     */
+    private final SparseArray<CarrierIdMatching> mLastCarrierId = new SparseArray<>();
+
     /** The start system time of the TelephonyLog in milliseconds*/
     private long mStartSystemTimeMs;
 
@@ -299,6 +308,8 @@
                 return "PHONE_STATE_CHANGED";
             case TelephonyCallSession.Event.Type.NITZ_TIME:
                 return "NITZ_TIME";
+            case TelephonyCallSession.Event.Type.AUDIO_CODEC:
+                return "AUDIO_CODEC";
             default:
                 return Integer.toString(event);
         }
@@ -388,6 +399,9 @@
                                 + " isMultiparty = " + call.isMultiparty);
                     }
                     pw.decreaseIndent();
+                } else if (event.type == TelephonyCallSession.Event.Type.AUDIO_CODEC) {
+                    pw.println(callSessionEventToString(event.type)
+                            + "(" + event.audioCodec + ")");
                 } else {
                     pw.println(callSessionEventToString(event.type));
                 }
@@ -414,6 +428,19 @@
                 pw.print(event.delay);
                 pw.print(" T=");
                 pw.println(smsSessionEventToString(event.type));
+                // Only show more info for tx/rx sms
+                if (event.type == SmsSession.Event.Type.SMS_SEND
+                        || event.type == SmsSession.Event.Type.SMS_RECEIVED
+                        || event.type == SmsSession.Event.Type.SMS_SEND_RESULT) {
+                    pw.print(" ReqId=");
+                    pw.println(event.rilRequestId);
+                    pw.print(" E=");
+                    pw.println(event.errorCode);
+                    pw.print(" RilE=");
+                    pw.println(event.error);
+                    pw.print(" ImsE=");
+                    pw.println(event.imsError);
+                }
             }
             pw.decreaseIndent();
         }
@@ -425,15 +452,24 @@
         pw.println("Power log duration (battery time) (ms): " + s.loggingDurationMs);
         pw.println("Energy consumed by modem (mAh): " + s.energyConsumedMah);
         pw.println("Number of packets sent (tx): " + s.numPacketsTx);
-        pw.println("Amount of time kernel is active because of cellular data (ms): " +
-            s.cellularKernelActiveTimeMs);
-        pw.println("Amount of time spent in very poor rx signal level (ms): " +
-            s.timeInVeryPoorRxSignalLevelMs);
+        pw.println("Number of bytes sent (tx): " + s.numBytesTx);
+        pw.println("Number of packets received (rx): " + s.numPacketsRx);
+        pw.println("Number of bytes received (rx): " + s.numBytesRx);
+        pw.println("Amount of time kernel is active because of cellular data (ms): "
+                + s.cellularKernelActiveTimeMs);
+        pw.println("Amount of time spent in very poor rx signal level (ms): "
+                + s.timeInVeryPoorRxSignalLevelMs);
         pw.println("Amount of time modem is in sleep (ms): " + s.sleepTimeMs);
         pw.println("Amount of time modem is in idle (ms): " + s.idleTimeMs);
         pw.println("Amount of time modem is in rx (ms): " + s.rxTimeMs);
         pw.println("Amount of time modem is in tx (ms): " + Arrays.toString(s.txTimeMs));
+        pw.println("Amount of time phone spent in various Radio Access Technologies (ms): "
+                + Arrays.toString(s.timeInRatMs));
+        pw.println("Amount of time phone spent in various cellular "
+                + "rx signal strength levels (ms): "
+                + Arrays.toString(s.timeInRxSignalStrengthLevelMs));
         pw.decreaseIndent();
+        pw.println("Hardware Version: " + SystemProperties.get("ro.boot.revision", ""));
     }
 
     /**
@@ -485,6 +521,13 @@
                     .setImsConnectionState(mLastImsConnectionState.get(key)).build();
             addTelephonyEvent(event);
         }
+
+        for (int i = 0; i < mLastCarrierId.size(); i++) {
+            final int key = mLastCarrierId.keyAt(i);
+            TelephonyEvent event = new TelephonyEventBuilder(mStartElapsedTimeMs, key)
+                    .setCarrierIdMatching(mLastCarrierId.get(key)).build();
+            addTelephonyEvent(event);
+        }
     }
 
     /**
@@ -530,6 +573,9 @@
         // Build modem power metrics
         log.modemPowerStats = new ModemPowerMetrics().buildProto();
 
+        // Log the hardware revision
+        log.hardwareRevision = SystemProperties.get("ro.boot.revision", "");
+
         // Log the starting system time
         log.startTime = new TelephonyProto.Time();
         log.startTime.systemTimestampMillis = mStartSystemTimeMs;
@@ -1468,7 +1514,7 @@
         } else {
 
             smsSession.addEvent(new SmsSessionEventBuilder(
-                    SmsSession.Event.Type.SMS_SEND_RESULT_IMS_SERVICE)
+                    SmsSession.Event.Type.SMS_SEND_RESULT)
                     .setImsServiceErrno(resultCode)
                     .setErrorCode(errorReason)
             );
@@ -1768,9 +1814,12 @@
      *
      * @param phoneId Phone id
      * @param format SMS format. Either {@link SmsMessage#FORMAT_3GPP} or
-     * {@link SmsMessage#FORMAT_3GPP2}.
+     *         {@link SmsMessage#FORMAT_3GPP2}.
+     * @param resultCode The result of sending the new SMS to the vendor layer to be sent to the
+     *         carrier network.
      */
-    public synchronized void writeImsServiceSendSms(int phoneId, String format) {
+    public synchronized void writeImsServiceSendSms(int phoneId, String format,
+            @ImsSmsImplBase.SendStatusResult int resultCode) {
         InProgressSmsSession smsSession = startNewSmsSessionIfNeeded(phoneId);
         int formatCode = SmsSession.Event.Format.SMS_FORMAT_UNKNOWN;
         switch (format) {
@@ -1783,8 +1832,9 @@
                 break;
             }
         }
-        smsSession.addEvent(new SmsSessionEventBuilder(SmsSession.Event.Type.SMS_SEND_IMS_SERVICE)
+        smsSession.addEvent(new SmsSessionEventBuilder(SmsSession.Event.Type.SMS_SEND)
                 .setTech(SmsSession.Event.Tech.SMS_IMS)
+                .setImsServiceErrno(resultCode)
                 .setFormat(formatCode)
         );
 
@@ -1815,8 +1865,10 @@
      * @param phoneId Phone id
      * @param format SMS format. Either {@link SmsMessage#FORMAT_3GPP} or
      * {@link SmsMessage#FORMAT_3GPP2}.
+     * @param result The result of processing the the newly received SMS message.
      */
-    public synchronized void writeImsServiceNewSms(int phoneId, String format) {
+    public synchronized void writeImsServiceNewSms(int phoneId, String format,
+            @ImsSmsImplBase.DeliverStatusResult int result) {
         InProgressSmsSession smsSession = startNewSmsSessionIfNeeded(phoneId);
         int formatCode = SmsSession.Event.Format.SMS_FORMAT_UNKNOWN;
         switch (format) {
@@ -1829,10 +1881,31 @@
                 break;
             }
         }
+        int smsError = SmsManager.RESULT_ERROR_GENERIC_FAILURE;
+        switch (result) {
+            case ImsSmsImplBase.DELIVER_STATUS_OK: {
+                smsError = SmsManager.RESULT_ERROR_NONE;
+                break;
+            }
+            case ImsSmsImplBase.DELIVER_STATUS_ERROR_NO_MEMORY: {
+                smsError = SmsManager.RESULT_NO_MEMORY;
+                break;
+            }
+            case ImsSmsImplBase.DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED: {
+                smsError = SmsManager.RESULT_REQUEST_NOT_SUPPORTED;
+                break;
+            }
+            case ImsSmsImplBase.DELIVER_STATUS_ERROR_GENERIC: {
+                smsError = SmsManager.RESULT_ERROR_GENERIC_FAILURE;
+                break;
+            }
+        }
         smsSession.addEvent(new SmsSessionEventBuilder(
-                SmsSession.Event.Type.SMS_RECEIVED_IMS_SERVICE)
+                SmsSession.Event.Type.SMS_RECEIVED)
                 .setTech(SmsSession.Event.Tech.SMS_IMS)
                 .setFormat(formatCode)
+                .setErrorCode(smsError)
+                .setImsServiceErrno(TelephonyProto.ImsServiceErrno.IMS_E_SUCCESS)
         );
 
         finishSmsSessionIfNeeded(smsSession);
@@ -1847,9 +1920,12 @@
      * @param isCMAS true if msg is CMAS
      * @param isETWS true if msg is ETWS
      * @param serviceCategory Service category of CB msg
+     * @param serialNumber Serial number of the message
+     * @param deliveredTimestamp Message's delivered timestamp
      */
     public synchronized void writeNewCBSms(int phoneId, int format, int priority, boolean isCMAS,
-                                           boolean isETWS, int serviceCategory) {
+                                           boolean isETWS, int serviceCategory, int serialNumber,
+                                           long deliveredTimestamp) {
         InProgressSmsSession smsSession = startNewSmsSessionIfNeeded(phoneId);
 
         int type;
@@ -1866,6 +1942,8 @@
         cbm.msgPriority = priority + 1;
         cbm.msgType = type;
         cbm.serviceCategory = serviceCategory;
+        cbm.serialNumber = serialNumber;
+        cbm.deliveredTimestampMillis = deliveredTimestamp;
 
         smsSession.addEvent(new SmsSessionEventBuilder(SmsSession.Event.Type.CB_SMS_RECEIVED)
                 .setCellBroadcastMessage(cbm)
@@ -1940,9 +2018,140 @@
 
         TelephonyEvent event = new TelephonyEventBuilder(phoneId).setCarrierIdMatching(
                 carrierIdMatching).build();
+        mLastCarrierId.put(phoneId, carrierIdMatching);
         addTelephonyEvent(event);
     }
 
+    /**
+     * Convert IMS audio codec into proto defined value
+     *
+     * @param c IMS codec value
+     * @return Codec value defined in call session proto
+     */
+    private int convertImsCodec(int c) {
+        switch (c) {
+            case ImsStreamMediaProfile.AUDIO_QUALITY_AMR:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_AMR;
+            case ImsStreamMediaProfile.AUDIO_QUALITY_AMR_WB:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_AMR_WB;
+            case ImsStreamMediaProfile.AUDIO_QUALITY_QCELP13K:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_QCELP13K;
+            case ImsStreamMediaProfile.AUDIO_QUALITY_EVRC:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC;
+            case ImsStreamMediaProfile.AUDIO_QUALITY_EVRC_B:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC_B;
+            case ImsStreamMediaProfile.AUDIO_QUALITY_EVRC_WB:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC_WB;
+            case ImsStreamMediaProfile.AUDIO_QUALITY_EVRC_NW:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC_NW;
+            case ImsStreamMediaProfile.AUDIO_QUALITY_GSM_EFR:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_GSM_EFR;
+            case ImsStreamMediaProfile.AUDIO_QUALITY_GSM_FR:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_GSM_FR;
+            case ImsStreamMediaProfile.AUDIO_QUALITY_GSM_HR:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_GSM_HR;
+            case ImsStreamMediaProfile.AUDIO_QUALITY_G711U:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_G711U;
+            case ImsStreamMediaProfile.AUDIO_QUALITY_G723:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_G723;
+            case ImsStreamMediaProfile.AUDIO_QUALITY_G711A:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_G711A;
+            case ImsStreamMediaProfile.AUDIO_QUALITY_G722:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_G722;
+            case ImsStreamMediaProfile.AUDIO_QUALITY_G711AB:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_G711AB;
+            case ImsStreamMediaProfile.AUDIO_QUALITY_G729:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_G729;
+            case ImsStreamMediaProfile.AUDIO_QUALITY_EVS_NB:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVS_NB;
+            case ImsStreamMediaProfile.AUDIO_QUALITY_EVS_WB:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVS_WB;
+            case ImsStreamMediaProfile.AUDIO_QUALITY_EVS_SWB:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVS_SWB;
+            case ImsStreamMediaProfile.AUDIO_QUALITY_EVS_FB:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVS_FB;
+            default:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_UNKNOWN;
+        }
+    }
+
+    /**
+     * Convert GSM/CDMA audio codec into proto defined value
+     *
+     * @param c GSM/CDMA codec value
+     * @return Codec value defined in call session proto
+     */
+    private int convertGsmCdmaCodec(int c) {
+        switch (c) {
+            case DriverCall.AUDIO_QUALITY_AMR:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_AMR;
+            case DriverCall.AUDIO_QUALITY_AMR_WB:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_AMR_WB;
+            case DriverCall.AUDIO_QUALITY_GSM_EFR:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_GSM_EFR;
+            case DriverCall.AUDIO_QUALITY_GSM_FR:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_GSM_FR;
+            case DriverCall.AUDIO_QUALITY_GSM_HR:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_GSM_HR;
+            case DriverCall.AUDIO_QUALITY_EVRC:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC;
+            case DriverCall.AUDIO_QUALITY_EVRC_B:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC_B;
+            case DriverCall.AUDIO_QUALITY_EVRC_WB:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC_WB;
+            case DriverCall.AUDIO_QUALITY_EVRC_NW:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_EVRC_NW;
+            default:
+                return TelephonyCallSession.Event.AudioCodec.AUDIO_CODEC_UNKNOWN;
+        }
+    }
+
+    /**
+     * Write audio codec event
+     *
+     * @param phoneId Phone id
+     * @param session IMS call session
+     */
+    public void writeAudioCodecIms(int phoneId, ImsCallSession session) {
+        InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
+        if (callSession == null) {
+            Rlog.e(TAG, "Call session is missing");
+            return;
+        }
+
+        ImsCallProfile localCallProfile = session.getLocalCallProfile();
+        if (localCallProfile != null) {
+            int codec = convertImsCodec(localCallProfile.mMediaProfile.mAudioQuality);
+            callSession.addEvent(new CallSessionEventBuilder(
+                    TelephonyCallSession.Event.Type.AUDIO_CODEC)
+                    .setCallIndex(getCallId(session))
+                    .setAudioCodec(codec));
+
+            if (VDBG) Rlog.v(TAG, "Logged Audio Codec event. Value: " + codec);
+        }
+    }
+
+    /**
+     * Write audio codec event
+     *
+     * @param phoneId Phone id
+     * @param audioQuality Audio quality value
+     */
+    public void writeAudioCodecGsmCdma(int phoneId, int audioQuality) {
+        InProgressCallSession callSession = mInProgressCallSessions.get(phoneId);
+        if (callSession == null) {
+            Rlog.e(TAG, "Call session is missing");
+            return;
+        }
+
+        int codec = convertGsmCdmaCodec(audioQuality);
+        callSession.addEvent(new CallSessionEventBuilder(
+                TelephonyCallSession.Event.Type.AUDIO_CODEC)
+                .setAudioCodec(codec));
+
+        if (VDBG) Rlog.v(TAG, "Logged Audio Codec event. Value: " + codec);
+    }
+
     //TODO: Expand the proto in the future
     public void writeOnImsCallProgressing(int phoneId, ImsCallSession session) {}
     public void writeOnImsCallStarted(int phoneId, ImsCallSession session) {}
diff --git a/src/java/com/android/internal/telephony/sip/SipCommandInterface.java b/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
index 83a5ff9..a8d3438 100644
--- a/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
+++ b/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
@@ -101,12 +101,13 @@
     }
 
     @Override
-    public void dial(String address, int clirMode, Message result) {
+    public void dial(String address, boolean isEmergencyCall, int emergencyServiceCategories,
+                     int clirMode, Message result) {
     }
 
     @Override
-    public void dial(String address, int clirMode, UUSInfo uusInfo,
-            Message result) {
+    public void dial(String address, boolean isEmergencyCall, int emergencyServiceCategories,
+                     int clirMode, UUSInfo uusInfo, Message result) {
     }
 
     @Override
diff --git a/src/java/com/android/internal/telephony/sip/SipPhoneBase.java b/src/java/com/android/internal/telephony/sip/SipPhoneBase.java
index 03167bc..ee89638 100755
--- a/src/java/com/android/internal/telephony/sip/SipPhoneBase.java
+++ b/src/java/com/android/internal/telephony/sip/SipPhoneBase.java
@@ -423,15 +423,6 @@
         return false;
     }
 
-    @Override
-    public boolean isDataEnabled() {
-        return false;
-    }
-
-    @Override
-    public void setUserDataEnabled(boolean enable) {
-    }
-
     public boolean enableDataConnectivity() {
         return false;
     }
@@ -441,7 +432,7 @@
     }
 
     @Override
-    public boolean isDataAllowed() {
+    public boolean isDataAllowed(int apnType) {
         return false;
     }
 
diff --git a/src/java/com/android/internal/telephony/test/SimulatedCommands.java b/src/java/com/android/internal/telephony/test/SimulatedCommands.java
index 9a87d01..8e0b730 100644
--- a/src/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/src/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -32,6 +32,11 @@
 import android.service.carrier.CarrierIdentifier;
 import android.telephony.CellInfo;
 import android.telephony.CellInfoGsm;
+import android.telephony.CellSignalStrengthCdma;
+import android.telephony.CellSignalStrengthGsm;
+import android.telephony.CellSignalStrengthLte;
+import android.telephony.CellSignalStrengthTdscdma;
+import android.telephony.CellSignalStrengthWcdma;
 import android.telephony.IccOpenLogicalChannelResponse;
 import android.telephony.ImsiEncryptionInfo;
 import android.telephony.NetworkRegistrationState;
@@ -549,8 +554,10 @@
      * CLIR_INVOCATION  == on "CLIR invocation" (restrict CLI presentation)
      */
     @Override
-    public void dial (String address, int clirMode, Message result) {
-        SimulatedCommandsVerifier.getInstance().dial(address, clirMode, result);
+    public void dial(String address, boolean isEmergencyCall, int emergencyServiceCategories,
+                      int clirMode, Message result) {
+        SimulatedCommandsVerifier.getInstance().dial(address, isEmergencyCall,
+                emergencyServiceCategories, clirMode, result);
         simulatedCallState.onDial(address);
 
         resultSuccess(result, null);
@@ -568,8 +575,10 @@
      * CLIR_INVOCATION  == on "CLIR invocation" (restrict CLI presentation)
      */
     @Override
-    public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
-        SimulatedCommandsVerifier.getInstance().dial(address, clirMode, uusInfo, result);
+    public void dial(String address, boolean isEmergencyCall, int emergencyServiceCategories,
+                     int clirMode, UUSInfo uusInfo, Message result) {
+        SimulatedCommandsVerifier.getInstance().dial(address, isEmergencyCall,
+                emergencyServiceCategories, clirMode, uusInfo, result);
         simulatedCallState.onDial(address);
 
         resultSuccess(result, null);
@@ -858,25 +867,14 @@
 
     @Override
     public void getSignalStrength (Message result) {
-
         if (mSignalStrength == null) {
             mSignalStrength = new SignalStrength(
-                20, // gsmSignalStrength
-                0,  // gsmBitErrorRate
-                -1, // cdmaDbm
-                -1, // cdmaEcio
-                -1, // evdoDbm
-                -1, // evdoEcio
-                -1, // evdoSnr
-                99, // lteSignalStrength
-                SignalStrength.INVALID,     // lteRsrp
-                SignalStrength.INVALID,     // lteRsrq
-                SignalStrength.INVALID,     // lteRssnr
-                SignalStrength.INVALID,     // lteCqi
-                SignalStrength.INVALID      // tdScdmaRscp
-            );
+                    new CellSignalStrengthCdma(),
+                    new CellSignalStrengthGsm(20, 0, CellInfo.UNAVAILABLE),
+                    new CellSignalStrengthWcdma(),
+                    new CellSignalStrengthTdscdma(),
+                    new CellSignalStrengthLte());
         }
-
         resultSuccess(result, mSignalStrength);
     }
 
@@ -2151,20 +2149,11 @@
     public void notifySignalStrength() {
         if (mSignalStrength == null) {
             mSignalStrength = new SignalStrength(
-                    20, // gsmSignalStrength
-                    0,  // gsmBitErrorRate
-                    -1, // cdmaDbm
-                    -1, // cdmaEcio
-                    -1, // evdoDbm
-                    -1, // evdoEcio
-                    -1, // evdoSnr
-                    99, // lteSignalStrength
-                    SignalStrength.INVALID,     // lteRsrp
-                    SignalStrength.INVALID,     // lteRsrq
-                    SignalStrength.INVALID,     // lteRssnr
-                    SignalStrength.INVALID,     // lteCqi
-                    SignalStrength.INVALID      // tdScdmaRscp
-            );
+                    new CellSignalStrengthCdma(),
+                    new CellSignalStrengthGsm(20, 0, CellInfo.UNAVAILABLE),
+                    new CellSignalStrengthWcdma(),
+                    new CellSignalStrengthTdscdma(),
+                    new CellSignalStrengthLte());
         }
 
         if (mSignalStrengthRegistrant != null) {
diff --git a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java b/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
index 4460489..22e670b 100644
--- a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
+++ b/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
@@ -672,13 +672,13 @@
     }
 
     @Override
-    public void dial(String address, int clirMode, Message result) {
-
+    public void dial(String address, boolean isEmergencyCall, int emergencyServiceCategories,
+                     int clirMode, Message result) {
     }
 
     @Override
-    public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
-
+    public void dial(String address, boolean isEmergencyCall, int emergencyServiceCategories,
+                     int clirMode, UUSInfo uusInfo, Message result) {
     }
 
     @Override
@@ -1422,6 +1422,14 @@
     }
 
     @Override
+    public void registerForEmergencyNumberList(Handler h, int what, Object obj) {
+    }
+
+    @Override
+    public void unregisterForEmergencyNumberList(Handler h) {
+    }
+
+    @Override
     public void startNattKeepalive(
             int contextId, KeepalivePacketData packetData, int intervalMillis, Message result) {
     }
diff --git a/src/java/com/android/internal/telephony/uicc/IccIoResult.java b/src/java/com/android/internal/telephony/uicc/IccIoResult.java
index 01d270c..f777e81 100644
--- a/src/java/com/android/internal/telephony/uicc/IccIoResult.java
+++ b/src/java/com/android/internal/telephony/uicc/IccIoResult.java
@@ -192,9 +192,7 @@
                 + " sw2:0x"
                 + Integer.toHexString(sw2)
                 + " Payload: "
-                + ((Build.IS_DEBUGGABLE && Build.IS_ENG)
-                        ? IccUtils.bytesToHexString(payload)
-                        : "*******")
+                + (Build.IS_DEBUGGABLE ? IccUtils.bytesToHexString(payload) : "*******")
                 + ((!success()) ? " Error: " + getErrorString() : "");
     }
 
diff --git a/src/java/com/android/internal/telephony/uicc/UiccCard.java b/src/java/com/android/internal/telephony/uicc/UiccCard.java
index aae7874..97260af 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccCard.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccCard.java
@@ -85,7 +85,8 @@
 
             if (mCardState != CardState.CARDSTATE_ABSENT) {
                 if (mUiccProfile == null) {
-                    mUiccProfile = TelephonyComponentFactory.getInstance().makeUiccProfile(
+                    mUiccProfile = TelephonyComponentFactory.getInstance()
+                            .inject(UiccProfile.class.getName()).makeUiccProfile(
                             mContext, mCi, ics, mPhoneId, this, mLock);
                 } else {
                     mUiccProfile.update(mContext, mCi, ics);
@@ -509,6 +510,8 @@
         pw.println("UiccCard:");
         pw.println(" mCi=" + mCi);
         pw.println(" mCardState=" + mCardState);
+        pw.println(" mCardId=" + mCardId);
+        pw.println(" mPhoneId=" + mPhoneId);
         pw.println();
         if (mUiccProfile != null) {
             mUiccProfile.dump(fd, pw, args);
diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java
index cb860d8..3669f34 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccController.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccController.java
@@ -30,6 +30,7 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.Rlog;
 import android.telephony.TelephonyManager;
+import android.telephony.UiccCardInfo;
 import android.text.TextUtils;
 import android.util.LocalLog;
 
@@ -128,9 +129,18 @@
     // considered sensetive information.
     private ArrayList<String> mCardStrings;
 
+    // This is the card ID of the default eUICC. Whenever we receive slot status, we set it to the
+    // eUICC with the lowest slot index
+    private int mDefaultEuiccCardId;
+
+    private static final int INVALID_CARD_ID = TelephonyManager.INVALID_CARD_ID;
+
     // SharedPreference key for saving the known card strings (ICCIDs and EIDs) ordered by card ID
     private static final String CARD_STRINGS = "card_strings";
 
+    // SharedPreferences key for saving the default euicc card ID
+    private static final String DEFAULT_CARD = "default_card";
+
     private static final Object mLock = new Object();
     private static UiccController mInstance;
     private static ArrayList<IccSlotStatus> sLastSlotStatus;
@@ -199,6 +209,7 @@
 
         mLauncher = new UiccStateChangedLauncher(c, this);
         mCardStrings = loadCardStrings();
+        mDefaultEuiccCardId = INVALID_CARD_ID;
     }
 
     private int getSlotIdFromPhoneId(int phoneId) {
@@ -549,8 +560,11 @@
 
         UiccCard card = mUiccSlots[slotId].getUiccCard();
         if (card != null && (card.getCardState() == CardState.CARDSTATE_PRESENT)) {
-            // Card.getCardId returns the cardString, not the public card ID int
             String cardString = card.getCardId();
+            if (!mUiccSlots[slotId].isEuicc()) {
+                // getCardId() returns the raw ICCID for a UICC, so we strip it manually
+                cardString = IccUtils.stripTrailingFs(cardString);
+            }
             addCardId(cardString);
         }
 
@@ -570,10 +584,50 @@
 
     /**
      * Converts the card string (the ICCID/EID, formerly named card ID) to the public int cardId.
-     * Returns -1 if the card string does not map to a cardId.
+     * Returns INVALID_CARD_ID if the card string does not map to a cardId.
      */
     public int convertToPublicCardId(String cardString) {
-        return mCardStrings.indexOf(cardString);
+        int id = mCardStrings.indexOf(cardString);
+        if (id == -1) {
+            return INVALID_CARD_ID;
+        } else {
+            return id;
+        }
+    }
+
+    /**
+     * Returns the UiccCardInfo of all currently inserted UICCs and embedded eUICCs.
+     */
+    public ArrayList<UiccCardInfo> getAllUiccCardInfos() {
+        ArrayList<UiccCardInfo> infos = new ArrayList<>();
+        for (int slotIndex = 0; slotIndex < mUiccSlots.length; slotIndex++) {
+            final UiccSlot slot = mUiccSlots[slotIndex];
+            boolean isEuicc = slot.isEuicc();
+            String eid = null;
+            UiccCard card = slot.getUiccCard();
+            if (card == null) {
+                continue;
+            }
+            String iccid = card.getIccId();
+            int cardId = INVALID_CARD_ID;
+            if (isEuicc) {
+                eid = card.getCardId();
+                cardId = convertToPublicCardId(eid);
+            } else {
+                // leave eid null if the UICC is not embedded
+                cardId = convertToPublicCardId(iccid);
+            }
+            UiccCardInfo info = new UiccCardInfo(isEuicc, cardId, eid, iccid, slotIndex);
+            infos.add(info);
+        }
+        return infos;
+    }
+
+    /**
+     * Get the card ID of the default eUICC.
+     */
+    public int getCardIdForDefaultEuicc() {
+        return mDefaultEuiccCardId;
     }
 
     private ArrayList<String> loadCardStrings() {
@@ -629,6 +683,7 @@
         sLastSlotStatus = status;
 
         int numActiveSlots = 0;
+        mDefaultEuiccCardId = INVALID_CARD_ID;
         for (int i = 0; i < status.size(); i++) {
             IccSlotStatus iss = status.get(i);
             boolean isActive = (iss.slotState == IccSlotStatus.SlotState.SLOTSTATE_ACTIVE);
@@ -637,10 +692,12 @@
 
                 // sanity check: logicalSlotIndex should be valid for an active slot
                 if (!isValidPhoneIndex(iss.logicalSlotIndex)) {
-                    throw new RuntimeException("Logical slot index " + iss.logicalSlotIndex
-                            + " invalid for physical slot " + i);
+                    Rlog.e(LOG_TAG, "Skipping slot " + i + " as phone " + iss.logicalSlotIndex
+                               + " is not available to communicate with this slot");
+
+                } else {
+                    mPhoneIdToSlotId[iss.logicalSlotIndex] = i;
                 }
-                mPhoneIdToSlotId[iss.logicalSlotIndex] = i;
             }
 
             if (mUiccSlots[i] == null) {
@@ -650,11 +707,21 @@
                 mUiccSlots[i] = new UiccSlot(mContext, isActive);
             }
 
-            mUiccSlots[i].update(isActive ? mCis[iss.logicalSlotIndex] : null, iss);
+            if (!isValidPhoneIndex(iss.logicalSlotIndex)) {
+                mUiccSlots[i].update(null, iss);
+            } else {
+                mUiccSlots[i].update(isActive ? mCis[iss.logicalSlotIndex] : null, iss);
+            }
 
             if (mUiccSlots[i].isEuicc()) {
                 String eid = iss.eid;
                 addCardId(eid);
+
+                // whenever slot status is received, set default card to the eUICC with the
+                // lowest slot index.
+                if (mDefaultEuiccCardId == INVALID_CARD_ID) {
+                    mDefaultEuiccCardId = convertToPublicCardId(eid);
+                }
             }
         }
 
@@ -662,8 +729,8 @@
 
         // sanity check: number of active slots should be valid
         if (numActiveSlots != mPhoneIdToSlotId.length) {
-            throw new RuntimeException("Number of active slots " + numActiveSlots
-                    + " does not match the expected value " + mPhoneIdToSlotId.length);
+            Rlog.e(LOG_TAG, "Number of active slots " + numActiveSlots
+                       + " does not match the number of Phones" + mPhoneIdToSlotId.length);
         }
 
         // sanity check: slotIds should be unique in mPhoneIdToSlotId
@@ -801,6 +868,8 @@
         pw.flush();
         pw.println(" mIsCdmaSupported=" + isCdmaSupported(mContext));
         pw.println(" mUiccSlots: size=" + mUiccSlots.length);
+        pw.println(" mCardStrings=" + mCardStrings);
+        pw.println(" mDefaultEuiccCardId=" + mDefaultEuiccCardId);
         for (int i = 0; i < mUiccSlots.length; i++) {
             if (mUiccSlots[i] == null) {
                 pw.println("  mUiccSlots[" + i + "]=null");
diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
index 7f08d45..7215f51 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
@@ -205,6 +205,7 @@
 
                 case EVENT_CARRIER_CONFIG_CHANGED:
                     handleCarrierNameOverride();
+                    handleSimCountryIsoOverride();
                     break;
 
                 case EVENT_OPEN_LOGICAL_CHANNEL_DONE:
@@ -353,6 +354,41 @@
         updateCarrierNameForSubscription(subCon, subId);
     }
 
+    /**
+     * Override sim country iso based on carrier config.
+     * Telephony country iso is based on MCC table which is coarse and doesn't work with dual IMSI
+     * SIM. e.g, a US carrier might have a roaming agreement with carriers from Europe. Devices
+     * will switch to different IMSI (differnt mccmnc) when enter roaming state. As a result, sim
+     * country iso (locale) will change to non-US.
+     *
+     * Each sim carrier should have a single country code. We should improve the accuracy of
+     * SIM country code look-up by using carrierid-to-countrycode table as an override on top of
+     * MCC table
+     */
+    private void handleSimCountryIsoOverride() {
+        SubscriptionController subCon = SubscriptionController.getInstance();
+        final int subId = subCon.getSubIdUsingPhoneId(mPhoneId);
+        if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            loge("subId not valid for Phone " + mPhoneId);
+            return;
+        }
+
+        CarrierConfigManager configLoader = (CarrierConfigManager)
+                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        if (configLoader == null) {
+            loge("Failed to load a Carrier Config");
+            return;
+        }
+
+        PersistableBundle config = configLoader.getConfigForSubId(subId);
+        String iso = config.getString(CarrierConfigManager.KEY_SIM_COUNTRY_ISO_OVERRIDE_STRING);
+        if (!TextUtils.isEmpty(iso) &&
+                !iso.equals(mTelephonyManager.getSimCountryIsoForPhone(mPhoneId))) {
+            mTelephonyManager.setSimCountryIsoForPhone(mPhoneId, iso);
+            SubscriptionController.getInstance().setCountryIso(iso, subId);
+        }
+    }
+
     private void updateCarrierNameForSubscription(SubscriptionController subCon, int subId) {
         /* update display name with carrier override */
         SubscriptionInfo subInfo = subCon.getActiveSubscriptionInfo(
@@ -788,6 +824,16 @@
     }
 
     @Override
+    public boolean isEmptyProfile() {
+        // If there's no UiccCardApplication, it's an empty profile.
+        // Empty profile is a valid case of eSIM (default boot profile).
+        for (UiccCardApplication app : mUiccApplications) {
+            if (app != null) return false;
+        }
+        return true;
+    }
+
+    @Override
     public void setIccLockEnabled(boolean enabled, String password, Message onComplete) {
         synchronized (mLock) {
             if (mUiccApplication != null) {
diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java
index fcc60a1..edcad49 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java
@@ -201,7 +201,14 @@
     }
 
     public boolean isStateUnknown() {
-        return (mCardState == null || mCardState == CardState.CARDSTATE_ABSENT) && mStateIsUnknown;
+        if (mCardState == null || mCardState == CardState.CARDSTATE_ABSENT) {
+            // mStateIsUnknown is valid only in this scenario.
+            return mStateIsUnknown;
+        }
+        // if mUiccCard is null, assume the state to be UNKNOWN for now.
+        // The state may be known but since the actual card object is not available,
+        // it is safer to return UNKNOWN.
+        return mUiccCard == null;
     }
 
     private void checkIsEuiccSupported() {
@@ -393,6 +400,7 @@
         pw.println(" mCi=" + mCi);
         pw.println(" mActive=" + mActive);
         pw.println(" mLastRadioState=" + mLastRadioState);
+        pw.println(" mIccId=" + mIccId);
         pw.println(" mCardState=" + mCardState);
         if (mUiccCard != null) {
             pw.println(" mUiccCard=" + mUiccCard);
diff --git a/tests/telephonytests/Android.bp b/tests/telephonytests/Android.bp
index 3a8a1e6..2fe06d5 100644
--- a/tests/telephonytests/Android.bp
+++ b/tests/telephonytests/Android.bp
@@ -11,7 +11,7 @@
     ],
 
     static_libs: [
-        "android-support-test",
+        "androidx.test.rules",
         "frameworks-base-testutils",
         "guava",
         "mockito-target-minus-junit4",
diff --git a/tests/telephonytests/AndroidManifest.xml b/tests/telephonytests/AndroidManifest.xml
index 35ed2fb..3fbaacc 100644
--- a/tests/telephonytests/AndroidManifest.xml
+++ b/tests/telephonytests/AndroidManifest.xml
@@ -28,7 +28,7 @@
             </intent-filter>
         </activity>
     </application>
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.frameworks.telephonytests"
         android:label="Frameworks Telephony Tests">
     </instrumentation>
diff --git a/tests/telephonytests/AndroidTest.xml b/tests/telephonytests/AndroidTest.xml
index 74b2799..c3a405b 100644
--- a/tests/telephonytests/AndroidTest.xml
+++ b/tests/telephonytests/AndroidTest.xml
@@ -22,7 +22,7 @@
     <option name="test-tag" value="FrameworksTelephonyTests" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.frameworks.telephonytests" />
-        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false"/>
     </test>
 </configuration>
diff --git a/tests/telephonytests/src/android/telephony/ims/ImsCompatTests.java b/tests/telephonytests/src/android/telephony/ims/ImsCompatTests.java
index caa245f..414cb47 100644
--- a/tests/telephonytests/src/android/telephony/ims/ImsCompatTests.java
+++ b/tests/telephonytests/src/android/telephony/ims/ImsCompatTests.java
@@ -21,10 +21,11 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 
-import android.support.test.runner.AndroidJUnit4;
 import android.telephony.ims.aidl.IImsCallSessionListener;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.ims.internal.IImsMMTelFeature;
 
 import org.junit.After;
diff --git a/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java b/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java
index b7d2998..2695e4c 100644
--- a/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java
+++ b/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java
@@ -24,7 +24,6 @@
 
 import android.os.Parcel;
 import android.os.RemoteException;
-import android.support.test.runner.AndroidJUnit4;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
 import android.telephony.ims.feature.CapabilityChangeRequest;
 import android.telephony.ims.feature.ImsFeature;
@@ -32,6 +31,8 @@
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.ims.internal.IImsFeatureStatusCallback;
 
 import org.junit.After;
diff --git a/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java b/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java
index 3810f76..57f33ce 100644
--- a/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java
+++ b/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java
@@ -26,7 +26,6 @@
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.RemoteException;
-import android.support.test.runner.AndroidJUnit4;
 import android.telephony.ServiceState;
 import android.telephony.ims.aidl.IImsRegistration;
 import android.telephony.ims.aidl.IImsRegistrationCallback;
@@ -35,6 +34,8 @@
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/tests/telephonytests/src/android/telephony/ims/ImsServiceTest.java b/tests/telephonytests/src/android/telephony/ims/ImsServiceTest.java
index 34febcb..d6841cd 100644
--- a/tests/telephonytests/src/android/telephony/ims/ImsServiceTest.java
+++ b/tests/telephonytests/src/android/telephony/ims/ImsServiceTest.java
@@ -29,7 +29,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.RemoteException;
-import android.support.test.runner.AndroidJUnit4;
 import android.telephony.ims.aidl.IImsMmTelFeature;
 import android.telephony.ims.aidl.IImsServiceController;
 import android.telephony.ims.feature.ImsFeature;
@@ -38,6 +37,8 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.SparseArray;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.ims.ImsManager;
 import com.android.ims.internal.IImsFeatureStatusCallback;
 
diff --git a/tests/telephonytests/src/android/telephony/ims/MmTelFeatureTests.java b/tests/telephonytests/src/android/telephony/ims/MmTelFeatureTests.java
index 79b9d60..a1a9baf 100644
--- a/tests/telephonytests/src/android/telephony/ims/MmTelFeatureTests.java
+++ b/tests/telephonytests/src/android/telephony/ims/MmTelFeatureTests.java
@@ -28,7 +28,6 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
-import android.support.test.runner.AndroidJUnit4;
 import android.telecom.TelecomManager;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
 import android.telephony.ims.aidl.IImsMmTelFeature;
@@ -36,6 +35,8 @@
 import android.telephony.ims.stub.ImsCallSessionImplBase;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.ims.internal.IImsCallSession;
 import com.android.internal.telephony.ims.ImsTestBase;
 
diff --git a/tests/telephonytests/src/android/telephony/mbms/MbmsReceiverTest.java b/tests/telephonytests/src/android/telephony/mbms/MbmsReceiverTest.java
index 46cf4f7..b93d400 100644
--- a/tests/telephonytests/src/android/telephony/mbms/MbmsReceiverTest.java
+++ b/tests/telephonytests/src/android/telephony/mbms/MbmsReceiverTest.java
@@ -18,13 +18,13 @@
 
 import static org.junit.Assert.assertEquals;
 
-import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-
 @RunWith(AndroidJUnit4.class)
 public class MbmsReceiverTest {
     @Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityGsmTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityGsmTest.java
index cd4d17d..f50cea1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityGsmTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityGsmTest.java
@@ -18,7 +18,6 @@
 
 import android.os.Parcel;
 import android.telephony.CellIdentityGsm;
-import android.telephony.CellInfo;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -127,24 +126,6 @@
     }
 
     @SmallTest
-    public void testFormerConstructor() {
-        CellIdentityGsm ci =
-                new CellIdentityGsm(MCC, MNC, LAC, CID);
-
-        assertEquals(LAC, ci.getLac());
-        assertEquals(CID, ci.getCid());
-        assertEquals(Integer.MAX_VALUE, ci.getArfcn());
-        assertEquals(Integer.MAX_VALUE, ci.getBsic());
-        assertEquals(MCC, ci.getMcc());
-        assertEquals(MNC, ci.getMnc());
-        assertEquals(MCC_STR, ci.getMccString());
-        assertEquals(MNC_STR, ci.getMncString());
-        assertEquals(MCC_STR + MNC_STR, ci.getMobileNetworkOperator());
-        assertNull(ci.getOperatorAlphaLong());
-        assertNull(ci.getOperatorAlphaShort());
-    }
-
-    @SmallTest
     public void testEquals() {
         CellIdentityGsm ciA = new CellIdentityGsm(
                 LAC, CID, ARFCN, BSIC, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
@@ -185,15 +166,7 @@
                 new CellIdentityGsm(LAC, CID, ARFCN, BSIC, null, null, ALPHA_LONG, ALPHA_SHORT);
 
         Parcel p = Parcel.obtain();
-        p.writeInt(CellInfo.TYPE_GSM);
-        p.writeString(String.valueOf(Integer.MAX_VALUE));
-        p.writeString(String.valueOf(Integer.MAX_VALUE));
-        p.writeString(ALPHA_LONG);
-        p.writeString(ALPHA_SHORT);
-        p.writeInt(LAC);
-        p.writeInt(CID);
-        p.writeInt(ARFCN);
-        p.writeInt(BSIC);
+        ci.writeToParcel(p, 0);
         p.setDataPosition(0);
 
         CellIdentityGsm newCi = CellIdentityGsm.CREATOR.createFromParcel(p);
@@ -208,15 +181,7 @@
                 new CellIdentityGsm(LAC, CID, ARFCN, BSIC, null, null, ALPHA_LONG, ALPHA_SHORT);
 
         Parcel p = Parcel.obtain();
-        p.writeInt(CellInfo.TYPE_GSM);
-        p.writeString(invalidMcc);
-        p.writeString(invalidMnc);
-        p.writeString(ALPHA_LONG);
-        p.writeString(ALPHA_SHORT);
-        p.writeInt(LAC);
-        p.writeInt(CID);
-        p.writeInt(ARFCN);
-        p.writeInt(BSIC);
+        ci.writeToParcel(p, 0);
         p.setDataPosition(0);
 
         CellIdentityGsm newCi = CellIdentityGsm.CREATOR.createFromParcel(p);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityWcdmaTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityWcdmaTest.java
index 9fc0af4..6a049d6 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityWcdmaTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityWcdmaTest.java
@@ -18,7 +18,6 @@
 
 import android.os.Parcel;
 import android.telephony.CellIdentityWcdma;
-import android.telephony.CellInfo;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -127,23 +126,6 @@
     }
 
     @SmallTest
-    public void testFormerConstructor() {
-        CellIdentityWcdma ci =
-                new CellIdentityWcdma(MCC, MNC, LAC, CID, PSC);
-
-        assertEquals(LAC, ci.getLac());
-        assertEquals(CID, ci.getCid());
-        assertEquals(PSC, ci.getPsc());
-        assertEquals(MCC, ci.getMcc());
-        assertEquals(MNC, ci.getMnc());
-        assertEquals(MCC_STR, ci.getMccString());
-        assertEquals(MNC_STR, ci.getMncString());
-        assertEquals(MCC_STR + MNC_STR, ci.getMobileNetworkOperator());
-        assertNull(ci.getOperatorAlphaLong());
-        assertNull(ci.getOperatorAlphaShort());
-    }
-
-    @SmallTest
     public void testEquals() {
         CellIdentityWcdma ciA = new CellIdentityWcdma(
                 LAC, CID, PSC, UARFCN, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
@@ -183,15 +165,7 @@
                 new CellIdentityWcdma(LAC, CID, PSC, UARFCN, null, null, ALPHA_LONG, ALPHA_SHORT);
 
         Parcel p = Parcel.obtain();
-        p.writeInt(CellInfo.TYPE_WCDMA);
-        p.writeString(String.valueOf(Integer.MAX_VALUE));
-        p.writeString(String.valueOf(Integer.MAX_VALUE));
-        p.writeString(ALPHA_LONG);
-        p.writeString(ALPHA_SHORT);
-        p.writeInt(LAC);
-        p.writeInt(CID);
-        p.writeInt(PSC);
-        p.writeInt(UARFCN);
+        ci.writeToParcel(p, 0);
         p.setDataPosition(0);
 
         CellIdentityWcdma newCi = CellIdentityWcdma.CREATOR.createFromParcel(p);
@@ -206,15 +180,7 @@
                 new CellIdentityWcdma(LAC, CID, PSC, UARFCN, null, null, ALPHA_LONG, ALPHA_SHORT);
 
         Parcel p = Parcel.obtain();
-        p.writeInt(CellInfo.TYPE_WCDMA);
-        p.writeString(invalidMcc);
-        p.writeString(invalidMnc);
-        p.writeString(ALPHA_LONG);
-        p.writeString(ALPHA_SHORT);
-        p.writeInt(LAC);
-        p.writeInt(CID);
-        p.writeInt(PSC);
-        p.writeInt(UARFCN);
+        ci.writeToParcel(p, 0);
         p.setDataPosition(0);
 
         CellIdentityWcdma newCi = CellIdentityWcdma.CREATOR.createFromParcel(p);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthCdmaTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthCdmaTest.java
index 7ad38fc..063fb3c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthCdmaTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthCdmaTest.java
@@ -29,26 +29,26 @@
 
 public class CellSignalStrengthCdmaTest extends AndroidTestCase {
 
-    private static final int CDMA_DBM = 74;
-    private static final int CDMA_ECIO = 124;
-    private static final int EVDO_DBM = 23;
-    private static final int EVDO_ECIO = 108;
+    private static final int CDMA_DBM = -74;
+    private static final int CDMA_ECIO = -124;
+    private static final int EVDO_DBM = -23;
+    private static final int EVDO_ECIO = -108;
     private static final int EVDO_SNR = 7;
 
     @SmallTest
     public void testConstructor() {
         CellSignalStrengthCdma css = new CellSignalStrengthCdma(
                 CDMA_DBM, CDMA_ECIO, EVDO_DBM, EVDO_ECIO, EVDO_SNR);
-        assertEquals(-CDMA_DBM, css.getCdmaDbm());
-        assertEquals(-CDMA_ECIO, css.getCdmaEcio());
-        assertEquals(-EVDO_DBM, css.getEvdoDbm());
-        assertEquals(-EVDO_ECIO, css.getEvdoEcio());
+        assertEquals(CDMA_DBM, css.getCdmaDbm());
+        assertEquals(CDMA_ECIO, css.getCdmaEcio());
+        assertEquals(EVDO_DBM, css.getEvdoDbm());
+        assertEquals(EVDO_ECIO, css.getEvdoEcio());
         assertEquals(EVDO_SNR, css.getEvdoSnr());
     }
 
     @SmallTest
     public void testInvalidConstructor() {
-        CellSignalStrengthCdma css = new CellSignalStrengthCdma(-1, -1, -1, -1, -1);
+        CellSignalStrengthCdma css = new CellSignalStrengthCdma(200, 2000, 20, 400, 200);
         assertEquals(Integer.MAX_VALUE, css.getCdmaDbm());
         assertEquals(Integer.MAX_VALUE, css.getCdmaEcio());
         assertEquals(Integer.MAX_VALUE, css.getEvdoDbm());
@@ -74,7 +74,7 @@
                                 CDMA_DBM, CDMA_ECIO, EVDO_DBM, EVDO_ECIO, EVDO_SNR)));
         assertFalse(new CellSignalStrengthCdma(
                 CDMA_DBM, CDMA_ECIO, EVDO_DBM, EVDO_ECIO, EVDO_SNR).equals(
-                    new CellSignalStrengthCdma(CDMA_DBM, CDMA_ECIO, -1, EVDO_ECIO, EVDO_SNR)));
+                    new CellSignalStrengthCdma(CDMA_DBM, CDMA_ECIO, -24, EVDO_ECIO, EVDO_SNR)));
     }
 
     @SmallTest
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthNrTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthNrTest.java
index 2fdf0b1..074e9fc 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthNrTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthNrTest.java
@@ -30,13 +30,13 @@
 
 public class CellSignalStrengthNrTest extends AndroidTestCase {
     private static final int CSIRSRP = -123;
-    private static final int CSIRSRQ = -111;
+    private static final int CSIRSRQ = -11;
     private static final int ANOTHER_CSIRSRP = -111;
-    private static final int ANOTHER_CSIRSRQ = -120;
+    private static final int ANOTHER_CSIRSRQ = -12;
     private static final int INVALID_CSIRSRP = Integer.MAX_VALUE;
-    private static final int CSISINR = 64;
+    private static final int CSISINR = 18;
     private static final int SSRSRP = -112;
-    private static final int SSRSRQ = -94;
+    private static final int SSRSRQ = -13;
     private static final int SSSINR = 32;
 
     @Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthWcdmaTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthWcdmaTest.java
new file mode 100644
index 0000000..8323ba3
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthWcdmaTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.CellInfo;
+import android.telephony.CellSignalStrengthWcdma;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/** Unit tests for {@link CellSignalStrengthCdma}. */
+
+public class CellSignalStrengthWcdmaTest extends AndroidTestCase {
+
+    private static final int RSSI = -95;
+    private static final int BER = 3;
+    private static final int RSCP = -106;
+    private static final int ECNO = -5;
+
+    @SmallTest
+    public void testConstructor() {
+        CellSignalStrengthWcdma css = new CellSignalStrengthWcdma(RSSI, BER, RSCP, ECNO);
+        assertEquals(RSSI, css.getRssi());
+        assertEquals(BER, css.getBitErrorRate());
+        assertEquals(RSCP, css.getRscp());
+        assertEquals(ECNO, css.getEcNo());
+    }
+
+    @SmallTest
+    public void testInvalidConstructor() {
+        CellSignalStrengthWcdma css = new CellSignalStrengthWcdma(-1, -1, -1, 10);
+        assertEquals(CellInfo.UNAVAILABLE, css.getRssi());
+        assertEquals(CellInfo.UNAVAILABLE, css.getBitErrorRate());
+        assertEquals(CellInfo.UNAVAILABLE, css.getRscp());
+        assertEquals(CellInfo.UNAVAILABLE, css.getEcNo());
+    }
+
+    @SmallTest
+    public void testDefaultConstructor() {
+        CellSignalStrengthWcdma css = new CellSignalStrengthWcdma();
+        assertEquals(CellInfo.UNAVAILABLE, css.getRssi());
+        assertEquals(CellInfo.UNAVAILABLE, css.getBitErrorRate());
+        assertEquals(CellInfo.UNAVAILABLE, css.getRscp());
+        assertEquals(CellInfo.UNAVAILABLE, css.getEcNo());
+    }
+
+    @SmallTest
+    public void testEquals() {
+        assertTrue(new CellSignalStrengthWcdma(RSSI, BER, RSCP, ECNO).equals(
+                        new CellSignalStrengthWcdma(RSSI, BER, RSCP, ECNO)));
+        assertFalse(new CellSignalStrengthWcdma(RSSI, BER, RSCP, ECNO).equals(
+                    new CellSignalStrengthWcdma(RSSI, BER, RSCP + 1, ECNO)));
+    }
+
+    @SmallTest
+    public void testParcel() {
+        CellSignalStrengthWcdma css = new CellSignalStrengthWcdma(-1, -1, -1, 10);
+
+        Parcel p = Parcel.obtain();
+        css.writeToParcel(p, 0);
+        p.setDataPosition(0);
+
+        CellSignalStrengthWcdma newCss = CellSignalStrengthWcdma.CREATOR.createFromParcel(p);
+        assertEquals(css, newCss);
+    }
+
+    @SmallTest
+    public void testLevel() {
+        CellSignalStrengthWcdma css = new CellSignalStrengthWcdma(RSSI, BER, RSCP, ECNO);
+        PersistableBundle b = new PersistableBundle();
+
+        // No keys in the bundle - should use RSSI and default levels.
+        css.updateLevel(b, null); // ServiceState isn't used in WCDMA (yet)
+        assertEquals(2 /* MODERATE */, css.getLevel());
+
+        // Add RSCP levels but set the measurement as an invalid (empty string), should still use
+        // RSSI.
+        b.putIntArray(CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY,
+                new int[] {
+                        -115, /* SIGNAL_STRENGTH_POOR */
+                        -105, /* SIGNAL_STRENGTH_MODERATE */
+                        -95, /* SIGNAL_STRENGTH_GOOD */
+                        -85 /* SIGNAL_STRENGTH_GREAT */
+                });
+        b.putString(CarrierConfigManager.KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, "");
+        css.updateLevel(b, null); // ServiceState isn't used in WCDMA (yet)
+        assertEquals(2 /* MODERATE */, css.getLevel());
+
+        // Update the calculation to use RSCP, and expect the level to be calculated accordingly.
+        b.putString(CarrierConfigManager.KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING,
+                "rscp");
+        css.updateLevel(b, null); // ServiceState isn't used in WCDMA (yet)
+        assertEquals(1 /* POOR */, css.getLevel());
+    }
+
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java
index b2ee494..c9d82a4 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java
@@ -30,6 +30,7 @@
 import android.telephony.AccessNetworkConstants;
 import android.telephony.INetworkService;
 import android.telephony.INetworkServiceCallback;
+import android.telephony.LteVopsSupportInfo;
 import android.telephony.NetworkRegistrationState;
 import android.telephony.NetworkService;
 import android.telephony.NetworkServiceCallback;
@@ -154,10 +155,15 @@
 
         waitForMs(1000);
 
+        LteVopsSupportInfo lteVopsSupportInfo =
+                new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE,
+                        LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE);
+
         expectedState = new NetworkRegistrationState(
                 domain, AccessNetworkConstants.TransportType.WWAN, voiceRegState,
                 ServiceState.rilRadioTechnologyToNetworkType(voiceRadioTech), reasonForDenial,
-                false, availableServices, null, maxDataCalls, false, false);
+                false, availableServices, null, maxDataCalls, false, false, false,
+                lteVopsSupportInfo);
 
         try {
             verify(mCallback, times(1)).onGetNetworkRegistrationStateComplete(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ClientWakelockTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ClientWakelockTrackerTest.java
index 28ac9eb..742e3e1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ClientWakelockTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ClientWakelockTrackerTest.java
@@ -18,7 +18,7 @@
 
 import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
 
-import android.support.test.filters.FlakyTest;
+import androidx.test.filters.FlakyTest;
 
 import junit.framework.TestCase;
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
index 6313633..5637892 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
@@ -590,6 +590,8 @@
         //doReturn(mBundle).when(mCarrierConfigManager).getConfig(anyInt());
         doReturn(mBundle).when(mCarrierConfigManager).getConfig();
 
+        doReturn(true).when(mEuiccManager).isEnabled();
+
         mConfiguration.locale = Locale.US;
         doReturn(mConfiguration).when(mResources).getConfiguration();
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java
index 1785c8f..2758d7c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java
@@ -168,21 +168,15 @@
 
     @Test @SmallTest
     public void testNotifyDataConnectionFailed() throws Exception {
-        mDefaultPhoneNotifierUT.notifyDataConnectionFailed(mPhone, "BUSY", "APN_0");
-        verify(mTelephonyRegisteryMock).notifyDataConnectionFailedForSubscriber(0, "BUSY", "APN_0");
+        mDefaultPhoneNotifierUT.notifyDataConnectionFailed(mPhone, "APN_0");
+        verify(mTelephonyRegisteryMock).notifyDataConnectionFailedForSubscriber(0, "APN_0");
 
-        mDefaultPhoneNotifierUT.notifyDataConnectionFailed(mPhone, "LOCAL", "APN_0");
-        verify(mTelephonyRegisteryMock).notifyDataConnectionFailedForSubscriber(0, "LOCAL",
-                "APN_0");
-
-        mDefaultPhoneNotifierUT.notifyDataConnectionFailed(mPhone, "LOCAL", "APN_1");
-        verify(mTelephonyRegisteryMock).notifyDataConnectionFailedForSubscriber(0, "LOCAL",
-                "APN_1");
+        mDefaultPhoneNotifierUT.notifyDataConnectionFailed(mPhone, "APN_1");
+        verify(mTelephonyRegisteryMock).notifyDataConnectionFailedForSubscriber(0, "APN_1");
 
         doReturn(1).when(mPhone).getSubId();
-        mDefaultPhoneNotifierUT.notifyDataConnectionFailed(mPhone, "LOCAL", "APN_1");
-        verify(mTelephonyRegisteryMock).notifyDataConnectionFailedForSubscriber(1, "LOCAL",
-                "APN_1");
+        mDefaultPhoneNotifierUT.notifyDataConnectionFailed(mPhone, "APN_1");
+        verify(mTelephonyRegisteryMock).notifyDataConnectionFailedForSubscriber(1, "APN_1");
     }
 
     @Test @SmallTest
diff --git a/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java b/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
index 1f883b8..a5eb233 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
@@ -20,27 +20,29 @@
 
 import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
 
+import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Matchers.nullable;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import static java.util.Arrays.asList;
-
 import android.content.Intent;
 import android.net.ConnectivityManager;
 import android.os.BatteryManager;
 import android.os.HandlerThread;
 import android.os.Message;
-import android.support.test.filters.FlakyTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.FlakyTest;
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
+import org.junit.Test;
+
+import static java.util.Arrays.asList;
 
 import java.util.ArrayList;
 
-@Ignore
 public class DeviceStateMonitorTest extends TelephonyTest {
 
     private DeviceStateMonitor mDSM;
@@ -132,4 +134,41 @@
         verify(mSimulatedCommandsVerifier, times(1)).setUnsolResponseFilter(eq(-1),
                 nullable(Message.class));
     }
+
+    private void sendStates(int screenState, int chargingState, int wifiState) {
+        setReady(false);
+        mDSM.obtainMessage(
+                DeviceStateMonitor.EVENT_SCREEN_STATE_CHANGED, screenState, 0).sendToTarget();
+        mDSM.obtainMessage(
+                DeviceStateMonitor.EVENT_CHARGING_STATE_CHANGED, chargingState, 0).sendToTarget();
+        mDSM.obtainMessage(
+                DeviceStateMonitor.EVENT_WIFI_CONNECTION_CHANGED, wifiState, 0).sendToTarget();
+        mDSM.post(() -> setReady(true));
+        waitUntilReady();
+    }
+
+    @Test
+    @MediumTest
+    public void testWifi() throws Exception  {
+        // screen off
+        sendStates(0, 0, 0);
+        assertEquals(
+                DeviceStateMonitor.CELL_INFO_INTERVAL_LONG_MS, mDSM.computeCellInfoMinInterval());
+        // screen off, but charging
+        sendStates(0, 1, 0);
+        assertEquals(
+                DeviceStateMonitor.CELL_INFO_INTERVAL_LONG_MS, mDSM.computeCellInfoMinInterval());
+        // screen on, no wifi
+        sendStates(1, 0, 0);
+        assertEquals(
+                DeviceStateMonitor.CELL_INFO_INTERVAL_SHORT_MS, mDSM.computeCellInfoMinInterval());
+        // screen on, but on wifi
+        sendStates(1, 0, 1);
+        assertEquals(
+                DeviceStateMonitor.CELL_INFO_INTERVAL_LONG_MS, mDSM.computeCellInfoMinInterval());
+        // screen on, charging
+        sendStates(1, 1, 0);
+        assertEquals(
+                DeviceStateMonitor.CELL_INFO_INTERVAL_SHORT_MS, mDSM.computeCellInfoMinInterval());
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ExponentialBackoffTest.java b/tests/telephonytests/src/com/android/internal/telephony/ExponentialBackoffTest.java
index f9a883a..7c303bd 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ExponentialBackoffTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ExponentialBackoffTest.java
@@ -25,7 +25,8 @@
 
 import android.os.Handler;
 import android.os.Looper;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.telephony.ims.ImsTestBase;
 
@@ -34,6 +35,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+
 @RunWith(AndroidJUnit4.class)
 public class ExponentialBackoffTest extends ImsTestBase {
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
index d5f1c7a..e3e5d96 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
@@ -25,11 +25,12 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.BaseColumns;
-import android.support.test.InstrumentationRegistry;
 import android.telephony.SubscriptionManager;
 import android.test.mock.MockContentProvider;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+
 public class FakeTelephonyProvider extends MockContentProvider {
     static final String TAG = "FakeTelephonyProvider";
 
@@ -98,7 +99,11 @@
                     + SubscriptionManager.WFC_IMS_ROAMING_ENABLED + " INTEGER DEFAULT -1,"
                     + SubscriptionManager.IS_OPPORTUNISTIC + " INTEGER DEFAULT 0,"
                     + SubscriptionManager.GROUP_UUID + " TEXT,"
-                    + SubscriptionManager.IS_METERED + " INTEGER DEFAULT 1"
+                    + SubscriptionManager.IS_METERED + " INTEGER DEFAULT 1,"
+                    + SubscriptionManager.ISO_COUNTRY_CODE + " TEXT,"
+                    + SubscriptionManager.CARRIER_ID + " INTEGER DEFAULT -1,"
+                    + SubscriptionManager.PROFILE_CLASS
+                    + " INTEGER DEFAULT " + SubscriptionManager.PROFILE_CLASS_DEFAULT
                     + ");";
         }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java
index d12b6cc..1d68aea 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
@@ -31,13 +32,14 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
-import android.support.test.filters.FlakyTest;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.ServiceState;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.FlakyTest;
+
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -115,9 +117,8 @@
         assertEquals(1, mCTUT.mForegroundCall.getConnections().size());
         /* verify the command is sent out to RIL */
         verify(mSimulatedCommandsVerifier).dial(eq(PhoneNumberUtils.
-                        extractNetworkPortionAlt(mDialString)), anyInt(),
-                eq((UUSInfo) null),
-                isA(Message.class));
+                        extractNetworkPortionAlt(mDialString)), anyBoolean(), anyInt(),
+                anyInt(), eq((UUSInfo) null), isA(Message.class));
     }
 
     @Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
index cb5309b..d54ae1d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
@@ -49,7 +49,6 @@
 import android.os.Process;
 import android.os.WorkSource;
 import android.preference.PreferenceManager;
-import android.support.test.filters.FlakyTest;
 import android.telephony.CarrierConfigManager;
 import android.telephony.CellLocation;
 import android.telephony.ServiceState;
@@ -58,6 +57,8 @@
 import android.telephony.gsm.GsmCellLocation;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.FlakyTest;
+
 import com.android.internal.telephony.test.SimulatedCommands;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus;
 import com.android.internal.telephony.uicc.IccException;
@@ -397,6 +398,13 @@
         // no resource or sharedPreference set -- should be null
         assertEquals(null, mPhoneUT.getVoiceMailNumber());
 
+        // config_telephony_use_own_number_for_voicemail
+        mContextFixture.getCarrierConfigBundle()
+                .putBoolean(CarrierConfigManager
+                        .KEY_CONFIG_TELEPHONY_USE_OWN_NUMBER_FOR_VOICEMAIL_BOOL, true);
+        doReturn(voiceMailNumber).when(mSimRecords).getMsisdnNumber();
+        assertEquals(voiceMailNumber, mPhoneUT.getVoiceMailNumber());
+
         // voicemail number from config
         mContextFixture.getCarrierConfigBundle().
                 putString(CarrierConfigManager.KEY_DEFAULT_VM_NUMBER_STRING, voiceMailNumber);
@@ -433,9 +441,6 @@
         switchToCdma();
         String voiceMailNumber = "1234567890";
 
-        // no resource or sharedPreference set -- should be *86
-        assertEquals("*86", mPhoneUT.getVoiceMailNumber());
-
         // config_telephony_use_own_number_for_voicemail
         mContextFixture.getCarrierConfigBundle()
                 .putBoolean(CarrierConfigManager
@@ -724,7 +729,7 @@
         assertEquals(EVENT_EMERGENCY_CALL_TOGGLE, msgList.get(1).what);
 
         // verify setInternalDataEnabled
-        verify(mDcTracker).setInternalDataEnabled(true);
+        verify(mDataEnabledSettings).setInternalDataEnabled(true);
 
         // verify wakeLock released
         assertEquals(false, mPhoneUT.getWakeLock().isHeld());
@@ -812,7 +817,7 @@
         assertEquals(EVENT_EMERGENCY_CALL_TOGGLE, msgList.get(1).what);
 
         // verify setInternalDataEnabled
-        verify(mDcTracker).setInternalDataEnabled(true);
+        verify(mDataEnabledSettings).setInternalDataEnabled(true);
 
         // verify wakeLock released
         assertEquals(false, mPhoneUT.getWakeLock().isHeld());
diff --git a/tests/telephonytests/src/com/android/internal/telephony/LocaleTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/LocaleTrackerTest.java
index ce2d62f..be18cfb 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/LocaleTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/LocaleTrackerTest.java
@@ -31,6 +31,7 @@
 import android.os.HandlerThread;
 import android.os.Message;
 import android.telephony.CellIdentityGsm;
+import android.telephony.CellInfo;
 import android.telephony.CellInfoGsm;
 import android.telephony.ServiceState;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -83,8 +84,10 @@
         mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
 
         mCellInfo = new CellInfoGsm();
-        mCellInfo.setCellIdentity(new CellIdentityGsm(Integer.parseInt(US_MCC),
-                Integer.parseInt(FAKE_MNC), 0, 0));
+        mCellInfo.setCellIdentity(new CellIdentityGsm(
+                    CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+                    CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+                    US_MCC, FAKE_MNC, null, null));
         doAnswer(invocation -> {
             Message m = invocation.getArgument(1);
             AsyncResult.forMessage(m, Arrays.asList(mCellInfo), null);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkRegistrationStateTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkRegistrationStateTest.java
index eb52e7c..1f553fe 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/NetworkRegistrationStateTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkRegistrationStateTest.java
@@ -19,16 +19,16 @@
 import static junit.framework.Assert.assertEquals;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
 import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.CellIdentityLte;
 import android.telephony.NetworkRegistrationState;
 import android.telephony.TelephonyManager;
 
+import androidx.test.filters.SmallTest;
+
 import org.junit.Test;
 
 /** Unit tests for {@link NetworkRegistrationState}. */
-
 public class NetworkRegistrationStateTest {
 
     @Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkScanRequestTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkScanRequestTest.java
index ed1a723..4538dea 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/NetworkScanRequestTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkScanRequestTest.java
@@ -19,19 +19,19 @@
 import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.AccessNetworkConstants.EutranBand;
 import android.telephony.AccessNetworkConstants.GeranBand;
 import android.telephony.NetworkScanRequest;
 import android.telephony.RadioAccessSpecifier;
 
+import androidx.test.filters.SmallTest;
+
 import org.junit.Test;
 
 import java.util.ArrayList;
 
 /** Unit tests for {@link NetworkScanRequest}. */
-
 public class NetworkScanRequestTest {
 
     @Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkScanResultTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkScanResultTest.java
index 041c5f5..1b58f36 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/NetworkScanResultTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkScanResultTest.java
@@ -19,7 +19,6 @@
 import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
 import android.telephony.CellIdentityGsm;
 import android.telephony.CellIdentityLte;
 import android.telephony.CellInfo;
@@ -28,12 +27,13 @@
 import android.telephony.CellSignalStrengthGsm;
 import android.telephony.CellSignalStrengthLte;
 
+import androidx.test.filters.SmallTest;
+
 import org.junit.Test;
 
 import java.util.ArrayList;
 
 /** Unit tests for {@link NetworkScanResult}. */
-
 public class NetworkScanResultTest {
 
     @Test
@@ -41,7 +41,7 @@
     public void testParcel() {
         ArrayList<CellInfo> infos = new ArrayList<CellInfo>();
 
-        CellIdentityGsm cig = new CellIdentityGsm(310, 310, 1, 2, 3, 4);
+        CellIdentityGsm cig = new CellIdentityGsm(1, 2, 40, 5, "001", "01", "test", "tst");
         CellSignalStrengthGsm cssg = new CellSignalStrengthGsm(5, 6, 7);
         CellInfoGsm gsm = new CellInfoGsm();
         gsm.setRegistered(true);
@@ -50,7 +50,8 @@
         gsm.setCellSignalStrength(cssg);
         infos.add(gsm);
 
-        CellIdentityLte cil = new CellIdentityLte(320, 320, 11, 12, 13, 14);
+        CellIdentityLte cil = new CellIdentityLte(
+                10, 5, 200, 2000, 10000, "001", "01", "test", "tst");
         CellSignalStrengthLte cssl = new CellSignalStrengthLte(15, 16, 17, 18, 19, 20);
         CellInfoLte lte = new CellInfoLte();
         lte.setRegistered(false);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
index b9c8163..c3adcc6 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -22,12 +22,13 @@
 import static junit.framework.Assert.assertTrue;
 
 import android.net.Uri;
-import android.support.test.filters.FlakyTest;
 import android.telephony.PhoneNumberUtils;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.text.SpannableStringBuilder;
 import android.text.style.TtsSpan;
 
+import androidx.test.filters.FlakyTest;
+
 import org.junit.Ignore;
 import org.junit.Test;
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
index 56bf746..e3ffa59 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
@@ -103,14 +103,14 @@
 
         // verify nothing has been done while there are no inputs
         assertFalse("data allowed initially", mDataAllowed[0]);
-        assertFalse("data allowed initially", mDataAllowed[0]);
-        assertFalse("phone active initially", mPhoneSwitcher.shouldApplySpecifiedRequests(0));
+        assertFalse("data allowed initially", mDataAllowed[1]);
 
         NetworkRequest internetNetworkRequest = addInternetNetworkRequest(null, 50);
         waitABit();
 
         assertFalse("data allowed after request", mDataAllowed[0]);
-        assertFalse("phone active after request", mPhoneSwitcher.shouldApplySpecifiedRequests(0));
+        assertFalse("phone active after request", mPhoneSwitcher
+                .shouldApplyNetworkRequest(internetNetworkRequest, 0));
 
         // not registered yet - shouldn't inc
         verify(mActivePhoneSwitchHandler, never()).sendMessageAtTime(any(), anyLong());
@@ -413,38 +413,34 @@
         setSlotIndexToSubId(1, 2);
         setDefaultDataSubId(1);
         waitABit();
-        // Phone 0 (sub 1) should preferredDataModem it has default data sub.
+        // Phone 0 (sub 1) should be preferred data phone as it has default data sub.
         verify(mMockRadioConfig).setPreferredDataModem(eq(0), any());
         verify(mActivePhoneSwitchHandler, times(2)).sendMessageAtTime(any(), anyLong());
-        assertTrue(mPhoneSwitcher.shouldApplySpecifiedRequests(0));
-        assertTrue(mPhoneSwitcher.shouldApplySpecifiedRequests(1));
-        assertTrue(mPhoneSwitcher.shouldApplyUnspecifiedRequests(0));
-        assertFalse(mPhoneSwitcher.shouldApplyUnspecifiedRequests(1));
 
         clearInvocations(mMockRadioConfig);
         clearInvocations(mActivePhoneSwitchHandler);
 
         // Notify phoneSwitcher about default data sub and default network request.
         // It shouldn't change anything.
-        addInternetNetworkRequest(null, 50);
-        addMmsNetworkRequest(2);
+        NetworkRequest internetRequest = addInternetNetworkRequest(null, 50);
+        NetworkRequest mmsRequest = addMmsNetworkRequest(2);
         waitABit();
         verify(mMockRadioConfig, never()).setPreferredDataModem(anyInt(), any());
         verify(mActivePhoneSwitchHandler, never()).sendMessageAtTime(any(), anyLong());
-        assertTrue(mPhoneSwitcher.shouldApplySpecifiedRequests(0));
-        assertTrue(mPhoneSwitcher.shouldApplySpecifiedRequests(1));
-        assertTrue(mPhoneSwitcher.shouldApplyUnspecifiedRequests(0));
-        assertFalse(mPhoneSwitcher.shouldApplyUnspecifiedRequests(1));
+        assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest(internetRequest, 0));
+        assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest(mmsRequest, 0));
+        assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest(internetRequest, 1));
+        assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest(mmsRequest, 1));
 
         // Set sub 2 as preferred sub should make phone 1 preferredDataModem
         mPhoneSwitcher.setPreferredData(2);
         waitABit();
         verify(mMockRadioConfig).setPreferredDataModem(eq(1), any());
         verify(mActivePhoneSwitchHandler, times(2)).sendMessageAtTime(any(), anyLong());
-        assertTrue(mPhoneSwitcher.shouldApplySpecifiedRequests(0));
-        assertTrue(mPhoneSwitcher.shouldApplySpecifiedRequests(1));
-        assertFalse(mPhoneSwitcher.shouldApplyUnspecifiedRequests(0));
-        assertTrue(mPhoneSwitcher.shouldApplyUnspecifiedRequests(1));
+        assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest(internetRequest, 0));
+        assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest(mmsRequest, 0));
+        assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest(internetRequest, 1));
+        assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest(mmsRequest, 1));
 
         clearInvocations(mMockRadioConfig);
         clearInvocations(mActivePhoneSwitchHandler);
@@ -454,10 +450,10 @@
         waitABit();
         verify(mMockRadioConfig).setPreferredDataModem(eq(0), any());
         verify(mActivePhoneSwitchHandler, times(2)).sendMessageAtTime(any(), anyLong());
-        assertTrue(mPhoneSwitcher.shouldApplySpecifiedRequests(0));
-        assertTrue(mPhoneSwitcher.shouldApplySpecifiedRequests(1));
-        assertTrue(mPhoneSwitcher.shouldApplyUnspecifiedRequests(0));
-        assertFalse(mPhoneSwitcher.shouldApplyUnspecifiedRequests(1));
+        assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest(internetRequest, 0));
+        assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest(mmsRequest, 0));
+        assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest(internetRequest, 1));
+        assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest(mmsRequest, 1));
 
         // SetDataAllowed should never be triggered.
         verify(mCommandsInterface0, never()).setDataAllowed(anyBoolean(), any());
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
index f528ac4..b87b416 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
@@ -110,7 +110,6 @@
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.WorkSource;
-import android.support.test.filters.FlakyTest;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.CellIdentityCdma;
 import android.telephony.CellIdentityGsm;
@@ -133,6 +132,8 @@
 import android.telephony.data.ApnSetting;
 import android.telephony.data.DataProfile;
 
+import androidx.test.filters.FlakyTest;
+
 import com.android.internal.telephony.RIL.RilHandler;
 import com.android.internal.telephony.dataconnection.DcTracker;
 
@@ -177,10 +178,10 @@
     private static final int CI = 268435456;
     private static final int CID = 65535;
     private static final int CQI = 2147483647;
-    private static final int DBM = 74;
+    private static final int DBM = -74;
     private static final int EARFCN = 262140;
     private static final int BANDWIDTH = 5000;
-    private static final int ECIO = 124;
+    private static final int ECIO = -124;
     private static final String EMPTY_ALPHA_LONG = "";
     private static final String EMPTY_ALPHA_SHORT = "";
     private static final int LAC = 65535;
@@ -194,13 +195,16 @@
     private static final int PCI = 503;
     private static final int PSC = 500;
     private static final int RIL_TIMESTAMP_TYPE_OEM_RIL = 3;
-    private static final int RSSNR = 2147483647;
-    private static final int RSRP = 96;
-    private static final int RSRQ = 10;
-    private static final int RSCP = 94;
-    private static final int ECNO = 5;
+    private static final int RSSNR = CellInfo.UNAVAILABLE;
+    private static final int RSRP = -96;
+    private static final int RSRQ = -10;
+    private static final int RSCP = -94;
+    private static final int RSCP_ASU = 26;
+    private static final int ECNO = -21;
+    private static final int ECNO_ASU = 6;
     private static final int SIGNAL_NOISE_RATIO = 6;
-    private static final int SIGNAL_STRENGTH = 24;
+    private static final int RSSI = -65;
+    private static final int RSSI_ASU = 24;
     private static final int SYSTEM_ID = 65533;
     private static final int TAC = 65535;
     private static final int TIME_ADVANCE = 4;
@@ -1087,9 +1091,9 @@
         lte.cellIdentityLte.earfcn = EARFCN;
         lte.cellIdentityLte.mcc = MCC_STR;
         lte.cellIdentityLte.mnc = MNC_STR;
-        lte.signalStrengthLte.signalStrength = SIGNAL_STRENGTH;
-        lte.signalStrengthLte.rsrp = RSRP;
-        lte.signalStrengthLte.rsrq = RSRQ;
+        lte.signalStrengthLte.signalStrength = RSSI_ASU;
+        lte.signalStrengthLte.rsrp = -RSRP;
+        lte.signalStrengthLte.rsrq = -RSRQ;
         lte.signalStrengthLte.rssnr = RSSNR;
         lte.signalStrengthLte.cqi = CQI;
         lte.signalStrengthLte.timingAdvance = TIME_ADVANCE;
@@ -1113,7 +1117,7 @@
         CellIdentityLte cil = new CellIdentityLte(CI, PCI, TAC, EARFCN, Integer.MAX_VALUE, MCC_STR,
                 MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT);
         CellSignalStrengthLte css = new CellSignalStrengthLte(
-                SIGNAL_STRENGTH, -RSRP, -RSRQ, RSSNR, CQI, TIME_ADVANCE);
+                RSSI, RSRP, RSRQ, RSSNR, CQI, TIME_ADVANCE);
         expected.setCellIdentity(cil);
         expected.setCellSignalStrength(css);
         expected.setCellConnectionStatus(CellInfo.CONNECTION_UNKNOWN);
@@ -1131,7 +1135,7 @@
         cellinfo.cellIdentityGsm.arfcn = ARFCN;
         cellinfo.cellIdentityGsm.mcc = MCC_STR;
         cellinfo.cellIdentityGsm.mnc = MNC_STR;
-        cellinfo.signalStrengthGsm.signalStrength = SIGNAL_STRENGTH;
+        cellinfo.signalStrengthGsm.signalStrength = RSSI_ASU;
         cellinfo.signalStrengthGsm.bitErrorRate = BIT_ERROR_RATE;
         cellinfo.signalStrengthGsm.timingAdvance = TIME_ADVANCE;
         android.hardware.radio.V1_0.CellInfo record = new android.hardware.radio.V1_0.CellInfo();
@@ -1154,7 +1158,7 @@
         CellIdentityGsm ci = new CellIdentityGsm(
                 LAC, CID, ARFCN, BSIC, MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT);
         CellSignalStrengthGsm cs = new CellSignalStrengthGsm(
-                SIGNAL_STRENGTH, BIT_ERROR_RATE, TIME_ADVANCE);
+                RSSI, BIT_ERROR_RATE, TIME_ADVANCE);
         expected.setCellIdentity(ci);
         expected.setCellSignalStrength(cs);
         expected.setCellConnectionStatus(CellInfo.CONNECTION_UNKNOWN);
@@ -1172,7 +1176,7 @@
         cellinfo.cellIdentityWcdma.uarfcn = UARFCN;
         cellinfo.cellIdentityWcdma.mcc = MCC_STR;
         cellinfo.cellIdentityWcdma.mnc = MNC_STR;
-        cellinfo.signalStrengthWcdma.signalStrength = SIGNAL_STRENGTH;
+        cellinfo.signalStrengthWcdma.signalStrength = RSSI_ASU;
         cellinfo.signalStrengthWcdma.bitErrorRate = BIT_ERROR_RATE;
         android.hardware.radio.V1_0.CellInfo record = new android.hardware.radio.V1_0.CellInfo();
         record.cellInfoType = TYPE_WCDMA;
@@ -1194,7 +1198,7 @@
         CellIdentityWcdma ci = new CellIdentityWcdma(
                 LAC, CID, PSC, UARFCN, MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT);
         CellSignalStrengthWcdma cs = new CellSignalStrengthWcdma(
-                SIGNAL_STRENGTH, BIT_ERROR_RATE, Integer.MAX_VALUE, Integer.MAX_VALUE);
+                RSSI, BIT_ERROR_RATE, Integer.MAX_VALUE, Integer.MAX_VALUE);
         expected.setCellIdentity(ci);
         expected.setCellSignalStrength(cs);
         expected.setCellConnectionStatus(CellInfo.CONNECTION_UNKNOWN);
@@ -1212,9 +1216,9 @@
         cellinfo.cellIdentityTdscdma.uarfcn = UARFCN;
         cellinfo.cellIdentityTdscdma.base.mcc = MCC_STR;
         cellinfo.cellIdentityTdscdma.base.mnc = MNC_STR;
-        cellinfo.signalStrengthTdscdma.signalStrength = SIGNAL_STRENGTH;
+        cellinfo.signalStrengthTdscdma.signalStrength = RSSI_ASU;
         cellinfo.signalStrengthTdscdma.bitErrorRate = BIT_ERROR_RATE;
-        cellinfo.signalStrengthTdscdma.rscp = RSCP;
+        cellinfo.signalStrengthTdscdma.rscp = RSCP_ASU;
         android.hardware.radio.V1_2.CellInfo record = new android.hardware.radio.V1_2.CellInfo();
         record.cellInfoType = TYPE_TD_SCDMA;
         record.registered = false;
@@ -1236,7 +1240,7 @@
         CellIdentityTdscdma ci = new CellIdentityTdscdma(
                 MCC_STR, MNC_STR, LAC, CID, PSC, UARFCN, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT);
         CellSignalStrengthTdscdma cs = new CellSignalStrengthTdscdma(
-                SIGNAL_STRENGTH, BIT_ERROR_RATE, RSCP);
+                RSSI, BIT_ERROR_RATE, RSCP);
         expected.setCellIdentity(ci);
         expected.setCellSignalStrength(cs);
         cellInfoTdscdma.setTimeStamp(TIMESTAMP); // override the timestamp
@@ -1252,10 +1256,10 @@
         cellinfo.cellIdentityCdma.baseStationId = BASESTATION_ID;
         cellinfo.cellIdentityCdma.longitude = LONGITUDE;
         cellinfo.cellIdentityCdma.latitude = LATITUDE;
-        cellinfo.signalStrengthCdma.dbm = DBM;
-        cellinfo.signalStrengthCdma.ecio = ECIO;
-        cellinfo.signalStrengthEvdo.dbm = DBM;
-        cellinfo.signalStrengthEvdo.ecio = ECIO;
+        cellinfo.signalStrengthCdma.dbm = -DBM;
+        cellinfo.signalStrengthCdma.ecio = -ECIO;
+        cellinfo.signalStrengthEvdo.dbm = -DBM;
+        cellinfo.signalStrengthEvdo.ecio = -ECIO;
         cellinfo.signalStrengthEvdo.signalNoiseRatio = SIGNAL_NOISE_RATIO;
         android.hardware.radio.V1_0.CellInfo record = new android.hardware.radio.V1_0.CellInfo();
         record.cellInfoType = TYPE_CDMA;
@@ -1298,7 +1302,7 @@
         CellIdentityLte cil = new CellIdentityLte(
                 CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
         CellSignalStrengthLte css = new CellSignalStrengthLte(
-                SIGNAL_STRENGTH, -RSRP, -RSRQ, RSSNR, CQI, TIME_ADVANCE);
+                RSSI, RSRP, RSRQ, RSSNR, CQI, TIME_ADVANCE);
         expected.setCellIdentity(cil);
         expected.setCellSignalStrength(css);
         expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE);
@@ -1319,7 +1323,7 @@
         CellIdentityLte cil = new CellIdentityLte(CI, PCI, TAC, EARFCN, BANDWIDTH, MCC_STR, MNC_STR,
                 EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT);
         CellSignalStrengthLte css = new CellSignalStrengthLte(
-                SIGNAL_STRENGTH, -RSRP, -RSRQ, RSSNR, CQI, TIME_ADVANCE);
+                RSSI, RSRP, RSRQ, RSSNR, CQI, TIME_ADVANCE);
         expected.setCellIdentity(cil);
         expected.setCellSignalStrength(css);
         expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE);
@@ -1342,7 +1346,7 @@
         CellIdentityLte cil = new CellIdentityLte(
                 CI, PCI, TAC, EARFCN, BANDWIDTH, null, null, ALPHA_LONG, ALPHA_SHORT);
         CellSignalStrengthLte css = new CellSignalStrengthLte(
-                SIGNAL_STRENGTH, -RSRP, -RSRQ, RSSNR, CQI, TIME_ADVANCE);
+                RSSI, RSRP, RSRQ, RSSNR, CQI, TIME_ADVANCE);
         expected.setCellIdentity(cil);
         expected.setCellSignalStrength(css);
         expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE);
@@ -1362,7 +1366,7 @@
         CellIdentityGsm ci = new CellIdentityGsm(
                 LAC, CID, ARFCN, BSIC, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
         CellSignalStrengthGsm cs = new CellSignalStrengthGsm(
-                SIGNAL_STRENGTH, BIT_ERROR_RATE, TIME_ADVANCE);
+                RSSI, BIT_ERROR_RATE, TIME_ADVANCE);
         expected.setCellIdentity(ci);
         expected.setCellSignalStrength(cs);
         expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE);
@@ -1383,7 +1387,7 @@
         CellIdentityGsm ci = new CellIdentityGsm(
                 LAC, CID, ARFCN, BSIC, MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT);
         CellSignalStrengthGsm cs = new CellSignalStrengthGsm(
-                SIGNAL_STRENGTH, BIT_ERROR_RATE, TIME_ADVANCE);
+                RSSI, BIT_ERROR_RATE, TIME_ADVANCE);
         expected.setCellIdentity(ci);
         expected.setCellSignalStrength(cs);
         expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE);
@@ -1406,7 +1410,7 @@
         CellIdentityGsm ci = new CellIdentityGsm(
                 LAC, CID, ARFCN, BSIC, null, null, ALPHA_LONG, ALPHA_SHORT);
         CellSignalStrengthGsm cs = new CellSignalStrengthGsm(
-                SIGNAL_STRENGTH, BIT_ERROR_RATE, TIME_ADVANCE);
+                RSSI, BIT_ERROR_RATE, TIME_ADVANCE);
         expected.setCellIdentity(ci);
         expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE);
         expected.setCellSignalStrength(cs);
@@ -1427,7 +1431,7 @@
         CellIdentityWcdma ci = new CellIdentityWcdma(
                 LAC, CID, PSC, UARFCN, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT);
         CellSignalStrengthWcdma cs =
-                new CellSignalStrengthWcdma(SIGNAL_STRENGTH, BIT_ERROR_RATE, RSCP, ECNO);
+                new CellSignalStrengthWcdma(RSSI, BIT_ERROR_RATE, RSCP, ECNO);
         expected.setCellIdentity(ci);
         expected.setCellSignalStrength(cs);
         expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE);
@@ -1448,7 +1452,7 @@
         CellIdentityWcdma ci = new CellIdentityWcdma(
                 LAC, CID, PSC, UARFCN, MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT);
         CellSignalStrengthWcdma cs = new CellSignalStrengthWcdma(
-                SIGNAL_STRENGTH, BIT_ERROR_RATE, RSCP, ECNO);
+                RSSI, BIT_ERROR_RATE, RSCP, ECNO);
         expected.setCellIdentity(ci);
         expected.setCellSignalStrength(cs);
         expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE);
@@ -1471,7 +1475,7 @@
         CellIdentityWcdma ci = new CellIdentityWcdma(
                 LAC, CID, PSC, UARFCN, null, null, ALPHA_LONG, ALPHA_SHORT);
         CellSignalStrengthWcdma cs = new CellSignalStrengthWcdma(
-                SIGNAL_STRENGTH, BIT_ERROR_RATE, RSCP, ECNO);
+                RSSI, BIT_ERROR_RATE, RSCP, ECNO);
         expected.setCellIdentity(ci);
         expected.setCellSignalStrength(cs);
         expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE);
@@ -1557,9 +1561,9 @@
         lte.cellIdentityLte.base.mnc = mnc;
         lte.cellIdentityLte.operatorNames.alphaLong = alphaLong;
         lte.cellIdentityLte.operatorNames.alphaShort = alphaShort;
-        lte.signalStrengthLte.signalStrength = SIGNAL_STRENGTH;
-        lte.signalStrengthLte.rsrp = RSRP;
-        lte.signalStrengthLte.rsrq = RSRQ;
+        lte.signalStrengthLte.signalStrength = RSSI_ASU;
+        lte.signalStrengthLte.rsrp = -RSRP;
+        lte.signalStrengthLte.rsrq = -RSRQ;
         lte.signalStrengthLte.rssnr = RSSNR;
         lte.signalStrengthLte.cqi = CQI;
         lte.signalStrengthLte.timingAdvance = TIME_ADVANCE;
@@ -1588,7 +1592,7 @@
         cellinfo.cellIdentityGsm.base.mnc = mnc;
         cellinfo.cellIdentityGsm.operatorNames.alphaLong = alphaLong;
         cellinfo.cellIdentityGsm.operatorNames.alphaShort = alphaShort;
-        cellinfo.signalStrengthGsm.signalStrength = SIGNAL_STRENGTH;
+        cellinfo.signalStrengthGsm.signalStrength = RSSI_ASU;
         cellinfo.signalStrengthGsm.bitErrorRate = BIT_ERROR_RATE;
         cellinfo.signalStrengthGsm.timingAdvance = TIME_ADVANCE;
         android.hardware.radio.V1_2.CellInfo record = new android.hardware.radio.V1_2.CellInfo();
@@ -1617,10 +1621,10 @@
         cellinfo.cellIdentityWcdma.base.mnc = mnc;
         cellinfo.cellIdentityWcdma.operatorNames.alphaLong = alphaLong;
         cellinfo.cellIdentityWcdma.operatorNames.alphaShort = alphaShort;
-        cellinfo.signalStrengthWcdma.base.signalStrength = SIGNAL_STRENGTH;
+        cellinfo.signalStrengthWcdma.base.signalStrength = RSSI_ASU;
         cellinfo.signalStrengthWcdma.base.bitErrorRate = BIT_ERROR_RATE;
-        cellinfo.signalStrengthWcdma.rscp = RSCP;
-        cellinfo.signalStrengthWcdma.ecno = ECNO;
+        cellinfo.signalStrengthWcdma.rscp = RSCP_ASU;
+        cellinfo.signalStrengthWcdma.ecno = ECNO_ASU;
         android.hardware.radio.V1_2.CellInfo record = new android.hardware.radio.V1_2.CellInfo();
         record.cellInfoType = TYPE_WCDMA;
         record.registered = false;
@@ -1645,10 +1649,10 @@
         cellinfo.cellIdentityCdma.base.latitude = LATITUDE;
         cellinfo.cellIdentityCdma.operatorNames.alphaLong = alphaLong;
         cellinfo.cellIdentityCdma.operatorNames.alphaShort = alphaShort;
-        cellinfo.signalStrengthCdma.dbm = DBM;
-        cellinfo.signalStrengthCdma.ecio = ECIO;
-        cellinfo.signalStrengthEvdo.dbm = DBM;
-        cellinfo.signalStrengthEvdo.ecio = ECIO;
+        cellinfo.signalStrengthCdma.dbm = -DBM;
+        cellinfo.signalStrengthCdma.ecio = -ECIO;
+        cellinfo.signalStrengthEvdo.dbm = -DBM;
+        cellinfo.signalStrengthEvdo.ecio = -ECIO;
         cellinfo.signalStrengthEvdo.signalNoiseRatio = SIGNAL_NOISE_RATIO;
         android.hardware.radio.V1_2.CellInfo record = new android.hardware.radio.V1_2.CellInfo();
         record.cellInfoType = TYPE_CDMA;
@@ -1664,63 +1668,6 @@
         return RIL.convertHalCellInfoList_1_2(records);
     }
 
-    public android.telephony.SignalStrength getTdScdmaSignalStrength_1_0(int tdscdmaNegDbm) {
-        android.hardware.radio.V1_0.SignalStrength halSs =
-                new android.hardware.radio.V1_0.SignalStrength();
-        halSs.lte.signalStrength = SIGNAL_STRENGTH;
-        halSs.lte.rsrp = RSRP;
-        halSs.lte.rsrq = RSRQ;
-        halSs.lte.rssnr = RSSNR;
-        halSs.gw.signalStrength = SIGNAL_STRENGTH;
-        halSs.gw.bitErrorRate = BIT_ERROR_RATE;
-        halSs.cdma.dbm = DBM;
-        halSs.cdma.ecio = ECIO;
-        halSs.evdo.dbm = DBM;
-        halSs.evdo.ecio = ECIO;
-        halSs.evdo.signalNoiseRatio = SIGNAL_NOISE_RATIO;
-        halSs.tdScdma.rscp = tdscdmaNegDbm;
-        android.telephony.SignalStrength ss = RIL.convertHalSignalStrength(halSs);
-        // FIXME: We should not need to call validateInput here b/74115980.
-        ss.validateInput();
-        return ss;
-    }
-
-    public android.telephony.SignalStrength getTdScdmaSignalStrength_1_2(int tdscdmaAsu) {
-        android.hardware.radio.V1_2.SignalStrength halSs =
-                new android.hardware.radio.V1_2.SignalStrength();
-        halSs.lte.signalStrength = SIGNAL_STRENGTH;
-        halSs.lte.rsrp = RSRP;
-        halSs.lte.rsrq = RSRQ;
-        halSs.lte.rssnr = RSSNR;
-        halSs.gsm.signalStrength = SIGNAL_STRENGTH;
-        halSs.gsm.bitErrorRate = BIT_ERROR_RATE;
-        halSs.cdma.dbm = DBM;
-        halSs.cdma.ecio = ECIO;
-        halSs.evdo.dbm = DBM;
-        halSs.evdo.ecio = ECIO;
-        halSs.evdo.signalNoiseRatio = SIGNAL_NOISE_RATIO;
-        halSs.wcdma.base.signalStrength = 99;
-        halSs.wcdma.rscp = 255;
-        halSs.tdScdma.rscp = tdscdmaAsu;
-        android.telephony.SignalStrength ss = RIL.convertHalSignalStrength_1_2(halSs);
-        // FIXME: We should not need to call validateInput here b/74115980
-        // but unless we call it, we have to pass Integer.MAX_VALUE for wcdma RSCP,
-        // which is outside the allowable range for the HAL. This value is being
-        // coerced inside SignalStrength.validateInput().
-        ss.validateInput();
-        return ss;
-    }
-
-    @Test
-    public void testHalSignalStrengthTdScdma() throws Exception {
-        // Check that the minimum value is the same.
-        assertEquals(getTdScdmaSignalStrength_1_0(120), getTdScdmaSignalStrength_1_2(0));
-        // Check that the maximum common value is the same.
-        assertEquals(getTdScdmaSignalStrength_1_0(25), getTdScdmaSignalStrength_1_2(95));
-        // Check that an invalid value is the same.
-        assertEquals(getTdScdmaSignalStrength_1_0(-1), getTdScdmaSignalStrength_1_2(255));
-    }
-
     @Test
     @FlakyTest
     public void testSetupDataCall() throws Exception {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RadioAccessSpecifierTest.java b/tests/telephonytests/src/com/android/internal/telephony/RadioAccessSpecifierTest.java
index 511b5c2..e4cc90e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/RadioAccessSpecifierTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/RadioAccessSpecifierTest.java
@@ -19,15 +19,15 @@
 import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.AccessNetworkConstants.GeranBand;
 import android.telephony.RadioAccessSpecifier;
 
+import androidx.test.filters.SmallTest;
+
 import org.junit.Test;
 
 /** Unit tests for {@link RadioAccessSpecifier}. */
-
 public class RadioAccessSpecifierTest {
 
     @Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTest.java
index 16e0656..45a4a7b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTest.java
@@ -19,6 +19,7 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.telephony.AccessNetworkConstants;
+import android.telephony.LteVopsSupportInfo;
 import android.telephony.NetworkRegistrationState;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
@@ -288,10 +289,13 @@
                 0, 0, 0, false,
                 null, null, true, 0, 0, 0);
 
-
+        LteVopsSupportInfo lteVopsSupportInfo =
+                new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE,
+                        LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE);
         NetworkRegistrationState wwanDataRegState = new NetworkRegistrationState(
                 NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN,
-                0, 0, 0, false, null, null, 0, false, false);
+                0, 0, 0, false, null, null, 0, false, false, false,
+                lteVopsSupportInfo);
 
         NetworkRegistrationState wlanRegState = new NetworkRegistrationState(
                 NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WLAN,
@@ -313,7 +317,7 @@
 
         wwanDataRegState = new NetworkRegistrationState(
                 NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN,
-                0, 0, 0, true, null, null, 0, false, false);
+                0, 0, 0, true, null, null, 0, false, false, false, lteVopsSupportInfo);
         ss.addNetworkRegistrationState(wwanDataRegState);
         assertEquals(ss.getNetworkRegistrationStates(NetworkRegistrationState.DOMAIN_PS,
                 AccessNetworkConstants.TransportType.WWAN), wwanDataRegState);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
index 4f581bf..592f2c1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
@@ -25,7 +25,6 @@
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.nullable;
 import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.anyObject;
 import static org.mockito.Mockito.anyString;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.doReturn;
@@ -39,6 +38,7 @@
 import android.app.IAlarmManager;
 import android.app.Notification;
 import android.app.NotificationManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -52,15 +52,11 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
-import android.os.Parcel;
 import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.WorkSource;
-import android.support.test.filters.FlakyTest;
-import android.telephony.AccessNetworkConstants;
-import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.CarrierConfigManager;
 import android.telephony.CellIdentity;
 import android.telephony.CellIdentityCdma;
@@ -68,6 +64,14 @@
 import android.telephony.CellIdentityLte;
 import android.telephony.CellInfo;
 import android.telephony.CellInfoGsm;
+import android.telephony.CellSignalStrength;
+import android.telephony.CellSignalStrengthCdma;
+import android.telephony.CellSignalStrengthGsm;
+import android.telephony.CellSignalStrengthLte;
+import android.telephony.CellSignalStrengthTdscdma;
+import android.telephony.CellSignalStrengthWcdma;
+import android.telephony.INetworkService;
+import android.telephony.LteVopsSupportInfo;
 import android.telephony.NetworkRegistrationState;
 import android.telephony.NetworkService;
 import android.telephony.PhysicalChannelConfig;
@@ -82,9 +86,10 @@
 import android.util.Pair;
 import android.util.TimestampedValue;
 
+import androidx.test.filters.FlakyTest;
+
 import com.android.internal.R;
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
-import com.android.internal.telephony.dataconnection.DcTracker;
 import com.android.internal.telephony.test.SimulatedCommands;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus;
 
@@ -102,9 +107,6 @@
 import java.util.List;
 
 public class ServiceStateTrackerTest extends TelephonyTest {
-
-    @Mock
-    private DcTracker mDct;
     @Mock
     private ProxyController mProxyController;
     @Mock
@@ -112,7 +114,12 @@
     @Mock
     protected IAlarmManager mAlarmManager;
 
-    CellularNetworkService mCellularNetworkService;
+    private CellularNetworkService mCellularNetworkService;
+
+    @Mock
+    private NetworkService mIwlanNetworkService;
+    @Mock
+    private INetworkService.Stub mIwlanNetworkServiceStub;
 
     private ServiceStateTracker sst;
     private ServiceStateTrackerTestHandler mSSTTestHandler;
@@ -146,17 +153,33 @@
 
     private void addNetworkService() {
         mCellularNetworkService = new CellularNetworkService();
-        ServiceInfo serviceInfo =  new ServiceInfo();
-        serviceInfo.packageName = "com.android.phone";
-        serviceInfo.permission = "android.permission.BIND_TELEPHONY_NETWORK_SERVICE";
-        IntentFilter filter = new IntentFilter();
+        ServiceInfo CellularServiceInfo = new ServiceInfo();
+        CellularServiceInfo.packageName = "com.android.phone";
+        CellularServiceInfo.name = "CellularNetworkService";
+        CellularServiceInfo.permission = "android.permission.BIND_TELEPHONY_NETWORK_SERVICE";
+        IntentFilter cellularIntentfilter = new IntentFilter();
         mContextFixture.addService(
                 NetworkService.NETWORK_SERVICE_INTERFACE,
-                null,
+                new ComponentName("com.android.phone",
+                        "com.android.internal.telephony.CellularNetworkService"),
                 "com.android.phone",
                 mCellularNetworkService.mBinder,
-                serviceInfo,
-                filter);
+                CellularServiceInfo,
+                cellularIntentfilter);
+
+        ServiceInfo iwlanServiceInfo = new ServiceInfo();
+        iwlanServiceInfo.packageName = "com.xyz.iwlan.networkservice";
+        iwlanServiceInfo.name = "IwlanNetworkService";
+        iwlanServiceInfo.permission = "android.permission.BIND_TELEPHONY_NETWORK_SERVICE";
+        IntentFilter iwlanIntentFilter = new IntentFilter();
+        mContextFixture.addService(
+                NetworkService.NETWORK_SERVICE_INTERFACE,
+                new ComponentName("com.xyz.iwlan.networkservice",
+                        "com.xyz.iwlan.IwlanNetworkService"),
+                "com.xyz.iwlan.networkservice",
+                mIwlanNetworkServiceStub,
+                iwlanServiceInfo,
+                iwlanIntentFilter);
     }
 
     @Before
@@ -167,10 +190,12 @@
 
         mContextFixture.putResource(R.string.config_wwan_network_service_package,
                 "com.android.phone");
+        mContextFixture.putResource(R.string.config_wlan_network_service_package,
+                "com.xyz.iwlan.networkservice");
+        doReturn(mIwlanNetworkServiceStub).when(mIwlanNetworkServiceStub).asBinder();
         addNetworkService();
 
-        doReturn(true).when(mDct).isDisconnected();
-        mPhone.mDcTracker = mDct;
+        doReturn(true).when(mDcTracker).isDisconnected();
 
         replaceInstance(ProxyController.class, "sProxyController", null, mProxyController);
         mBundle = mContextFixture.getCarrierConfigBundle();
@@ -191,9 +216,7 @@
 
         int dds = SubscriptionManager.getDefaultDataSubscriptionId();
         doReturn(dds).when(mPhone).getSubId();
-
-        doReturn(new ArrayList<Integer>(Arrays.asList(AccessNetworkConstants.TransportType.WWAN)))
-                .when(mTransportManager).getAvailableTransports();
+        doReturn(true).when(mPhone).areAllDataDisconnected();
 
         mSSTTestHandler = new ServiceStateTrackerTestHandler(getClass().getSimpleName());
         mSSTTestHandler.start();
@@ -225,11 +248,11 @@
     public void testSetRadioPowerOffUnderDataConnected() {
         sst.setRadioPower(true);
         waitForMs(100);
-        doReturn(false).when(mDct).isDisconnected();
+        doReturn(false).when(mPhone).areAllDataDisconnected();
         sst.setRadioPower(false);
         waitForMs(200);
         verify(this.mProxyController, times(1)).registerForAllDataDisconnected(anyInt(),
-                 eq(sst), anyInt(), anyObject());
+                 eq(sst), anyInt());
     }
 
     @Test
@@ -357,31 +380,10 @@
     }
 
     private CellInfoGsm getCellInfoGsm() {
-        Parcel p = Parcel.obtain();
-        // CellInfo
-        p.writeInt(1);
-        p.writeInt(1);
-        p.writeInt(2);
-        p.writeLong(1453510289108L);
-        p.writeInt(0);
-        // CellIdentity
-        p.writeInt(1);
-        p.writeString("310");
-        p.writeString("260");
-        p.writeString("long");
-        p.writeString("short");
-        // CellIdentityGsm
-        p.writeInt(123);
-        p.writeInt(456);
-        p.writeInt(950);
-        p.writeInt(27);
-        // CellSignalStrength
-        p.writeInt(99);
-        p.writeInt(0);
-        p.writeInt(3);
-        p.setDataPosition(0);
-
-        return CellInfoGsm.CREATOR.createFromParcel(p);
+        CellInfoGsm tmp = new CellInfoGsm();
+        tmp.setCellIdentity(new CellIdentityGsm(0, 1, 900, 5, "001", "01", "test", "tst"));
+        tmp.setCellSignalStrength(new CellSignalStrengthGsm(-85, 2, 3));
+        return tmp;
     }
 
     @Test
@@ -483,8 +485,8 @@
         // The service state of GsmCdmaPhone is STATE_OUT_OF_SERVICE, and IMS is unregistered.
         ServiceState ss = new ServiceState();
         ss.setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE);
-        sst.mSS = ss;
 
+        sst.mSS = ss;
         sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_IMS_SERVICE_STATE_CHANGED));
         waitForMs(200);
 
@@ -503,71 +505,56 @@
         verify(mPhone, times(1)).notifyServiceStateChanged(any(ServiceState.class));
     }
 
-    @Test
-    @MediumTest
-    public void testSignalStrength() {
-        SignalStrength ss = new SignalStrength(
-                30, // gsmSignalStrength
-                0,  // gsmBitErrorRate
-                -1, // cdmaDbm
-                -1, // cdmaEcio
-                -1, // evdoDbm
-                -1, // evdoEcio
-                -1, // evdoSnr
-                99, // lteSignalStrength
-                SignalStrength.INVALID,     // lteRsrp
-                SignalStrength.INVALID,     // lteRsrq
-                SignalStrength.INVALID,     // lteRssnr
-                SignalStrength.INVALID,     // lteCqi
-                SignalStrength.INVALID      // tdScdmaRscp
-        );
-
+    private void sendSignalStrength(SignalStrength ss) {
         mSimulatedCommands.setSignalStrength(ss);
         mSimulatedCommands.notifySignalStrength();
         waitForMs(300);
+    }
+
+    @Test
+    @MediumTest
+    public void testSignalStrength() {
+        // Send in GSM Signal Strength Info and expect isGsm == true
+        SignalStrength ss = new SignalStrength(
+                new CellSignalStrengthCdma(),
+                new CellSignalStrengthGsm(-53, 0, SignalStrength.INVALID),
+                new CellSignalStrengthWcdma(),
+                new CellSignalStrengthTdscdma(),
+                new CellSignalStrengthLte());
+
+        sendSignalStrength(ss);
         assertEquals(sst.getSignalStrength(), ss);
         assertEquals(sst.getSignalStrength().isGsm(), true);
 
-        // switch to CDMA
-        doReturn(false).when(mPhone).isPhoneTypeGsm();
-        doReturn(true).when(mPhone).isPhoneTypeCdmaLte();
-        sst.updatePhoneType();
-        sst.mSS.setRilDataRadioTechnology(ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
+        // Send in CDMA+LTE Signal Strength Info and expect isGsm == true
+        ss = new SignalStrength(
+                new CellSignalStrengthCdma(-90, -12,
+                        SignalStrength.INVALID, SignalStrength.INVALID, SignalStrength.INVALID),
+                new CellSignalStrengthGsm(),
+                new CellSignalStrengthWcdma(),
+                new CellSignalStrengthTdscdma(),
+                new CellSignalStrengthLte(
+                        -110, -114, -5, 0, SignalStrength.INVALID, SignalStrength.INVALID));
 
-        mSimulatedCommands.notifySignalStrength();
-        waitForMs(300);
+        sendSignalStrength(ss);
         assertEquals(sst.getSignalStrength(), ss);
         assertEquals(sst.getSignalStrength().isGsm(), true);
 
-        // notify signal strength again, but this time data RAT is not LTE
-        sst.mSS.setRilVoiceRadioTechnology(ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT);
-        sst.mSS.setRilDataRadioTechnology(ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD);
-        mSimulatedCommands.notifySignalStrength();
-        waitForMs(300);
+        // Send in CDMA-only Signal Strength Info and expect isGsm == false
+        ss = new SignalStrength(
+                new CellSignalStrengthCdma(-90, -12,
+                        SignalStrength.INVALID, SignalStrength.INVALID, SignalStrength.INVALID),
+                new CellSignalStrengthGsm(),
+                new CellSignalStrengthWcdma(),
+                new CellSignalStrengthTdscdma(),
+                new CellSignalStrengthLte());
+
+        sendSignalStrength(ss);
         assertEquals(sst.getSignalStrength(), ss);
         assertEquals(sst.getSignalStrength().isGsm(), false);
     }
 
-    @Test
-    public void testSetsNewSignalStrengthReportingCriteria() {
-        int[] wcdmaThresholds = {
-                -110, /* SIGNAL_STRENGTH_POOR */
-                -100, /* SIGNAL_STRENGTH_MODERATE */
-                -90, /* SIGNAL_STRENGTH_GOOD */
-                -80  /* SIGNAL_STRENGTH_GREAT */
-        };
-        mBundle.putIntArray(CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY,
-                wcdmaThresholds);
-
-        int[] lteThresholds = {
-                -130, /* SIGNAL_STRENGTH_POOR */
-                -120, /* SIGNAL_STRENGTH_MODERATE */
-                -110, /* SIGNAL_STRENGTH_GOOD */
-                -100,  /* SIGNAL_STRENGTH_GREAT */
-        };
-        mBundle.putIntArray(CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY,
-                lteThresholds);
-
+    private void sendCarrierConfigUpdate() {
         CarrierConfigManager mockConfigManager = Mockito.mock(CarrierConfigManager.class);
         when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
                 .thenReturn(mockConfigManager);
@@ -576,160 +563,89 @@
         Intent intent = new Intent().setAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
         mContext.sendBroadcast(intent);
         waitForMs(300);
-
-        verify(mPhone).setSignalStrengthReportingCriteria(eq(wcdmaThresholds),
-                eq(AccessNetworkType.UTRAN));
-        verify(mPhone).setSignalStrengthReportingCriteria(eq(lteThresholds),
-                eq(AccessNetworkType.EUTRAN));
     }
 
     @Test
-    @MediumTest
-    public void testSignalLevelWithWcdmaRscpThresholds() {
+    public void testLteSignalStrengthReportingCriteria() {
+        SignalStrength ss = new SignalStrength(
+                new CellSignalStrengthCdma(),
+                new CellSignalStrengthGsm(),
+                new CellSignalStrengthWcdma(),
+                new CellSignalStrengthTdscdma(),
+                new CellSignalStrengthLte(
+                        -110, /* rssi */
+                        -114, /* rsrp */
+                        -5, /* rsrq */
+                        0, /* rssnr */
+                        SignalStrength.INVALID, /* cqi */
+                        SignalStrength.INVALID /* ta */));
+
+        mBundle.putBoolean(CarrierConfigManager.KEY_USE_ONLY_RSRP_FOR_LTE_SIGNAL_BAR_BOOL,
+                true);
+
+        sendCarrierConfigUpdate();
+
+        mSimulatedCommands.setSignalStrength(ss);
+        mSimulatedCommands.notifySignalStrength();
+        waitForMs(300);
+        // Default thresholds are POOR=-115 MODERATE=-105 GOOD=-95 GREAT=-85
+        assertEquals(CellSignalStrength.SIGNAL_STRENGTH_POOR, sst.getSignalStrength().getLevel());
+
+        int[] lteThresholds = {
+                -130, // SIGNAL_STRENGTH_POOR
+                -120, // SIGNAL_STRENGTH_MODERATE
+                -110, // SIGNAL_STRENGTH_GOOD
+                -100,  // SIGNAL_STRENGTH_GREAT
+        };
+        mBundle.putIntArray(CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY,
+                lteThresholds);
+        sendCarrierConfigUpdate();
+
+        mSimulatedCommands.setSignalStrength(ss);
+        mSimulatedCommands.notifySignalStrength();
+        waitForMs(300);
+        assertEquals(sst.getSignalStrength().getLevel(),
+                CellSignalStrength.SIGNAL_STRENGTH_MODERATE);
+    }
+
+    @Test
+    public void testWcdmaSignalStrengthReportingCriteria() {
+        SignalStrength ss = new SignalStrength(
+                new CellSignalStrengthCdma(),
+                new CellSignalStrengthGsm(),
+                new CellSignalStrengthWcdma(-79, 0, -85, -5),
+                new CellSignalStrengthTdscdma(),
+                new CellSignalStrengthLte());
+
+        mSimulatedCommands.setSignalStrength(ss);
+        mSimulatedCommands.notifySignalStrength();
+        waitForMs(300);
+        assertEquals(sst.getSignalStrength().getLevel(), CellSignalStrength.SIGNAL_STRENGTH_GOOD);
+
+        int[] wcdmaThresholds = {
+                -110, // SIGNAL_STRENGTH_POOR
+                -100, // SIGNAL_STRENGTH_MODERATE
+                -90, // SIGNAL_STRENGTH_GOOD
+                -80  // SIGNAL_STRENGTH_GREAT
+        };
         mBundle.putIntArray(CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY,
-                new int[] {
-                        -110, /* SIGNAL_STRENGTH_POOR */
-                        -100, /* SIGNAL_STRENGTH_MODERATE */
-                        -90, /* SIGNAL_STRENGTH_GOOD */
-                        -80  /* SIGNAL_STRENGTH_GREAT */
-                });
+                wcdmaThresholds);
         mBundle.putString(
                 CarrierConfigManager.KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING,
                 "rscp");
-
-        SignalStrength ss = new SignalStrength(
-                30, // gsmSignalStrength
-                0,  // gsmBitErrorRate
-                -1, // cdmaDbm
-                -1, // cdmaEcio
-                -1, // evdoDbm
-                -1, // evdoEcio
-                -1, // evdoSnr
-                99, // lteSignalStrength
-                SignalStrength.INVALID,     // lteRsrp
-                SignalStrength.INVALID,     // lteRsrq
-                SignalStrength.INVALID,     // lteRssnr
-                SignalStrength.INVALID,     // lteCqi
-                SignalStrength.INVALID,     // tdScdmaRscp
-                99,                         // wcdmaSignalStrength
-                45                         // wcdmaRscpAsu
-        );
+        sendCarrierConfigUpdate();
         mSimulatedCommands.setSignalStrength(ss);
         mSimulatedCommands.notifySignalStrength();
         waitForMs(300);
-        assertEquals(sst.getSignalStrength(), ss);
-        assertEquals(sst.getSignalStrength().getWcdmaLevel(), SignalStrength.SIGNAL_STRENGTH_GREAT);
-        assertEquals(sst.getSignalStrength().getWcdmaAsuLevel(), 45);
-        assertEquals(sst.getSignalStrength().getWcdmaDbm(), -75);
-
-        ss = new SignalStrength(
-                30, // gsmSignalStrength
-                0,  // gsmBitErrorRate
-                -1, // cdmaDbm
-                -1, // cdmaEcio
-                -1, // evdoDbm
-                -1, // evdoEcio
-                -1, // evdoSnr
-                99, // lteSignalStrength
-                SignalStrength.INVALID,     // lteRsrp
-                SignalStrength.INVALID,     // lteRsrq
-                SignalStrength.INVALID,     // lteRssnr
-                SignalStrength.INVALID,     // lteCqi
-                SignalStrength.INVALID,     // tdScdmaRscp
-                99,                         // wcdmaSignalStrength
-                35                          // wcdmaRscpAsu
-        );
-        mSimulatedCommands.setSignalStrength(ss);
-        mSimulatedCommands.notifySignalStrength();
-        waitForMs(300);
-        assertEquals(sst.getSignalStrength(), ss);
-        assertEquals(sst.getSignalStrength().getWcdmaLevel(), SignalStrength.SIGNAL_STRENGTH_GOOD);
-        assertEquals(sst.getSignalStrength().getWcdmaAsuLevel(), 35);
-        assertEquals(sst.getSignalStrength().getWcdmaDbm(), -85);
-
-        ss = new SignalStrength(
-                30, // gsmSignalStrength
-                0,  // gsmBitErrorRate
-                -1, // cdmaDbm
-                -1, // cdmaEcio
-                -1, // evdoDbm
-                -1, // evdoEcio
-                -1, // evdoSnr
-                99, // lteSignalStrength
-                SignalStrength.INVALID,     // lteRsrp
-                SignalStrength.INVALID,     // lteRsrq
-                SignalStrength.INVALID,     // lteRssnr
-                SignalStrength.INVALID,     // lteCqi
-                SignalStrength.INVALID,     // tdScdmaRscp
-                99,                         // wcdmaSignalStrength
-                25                          // wcdmaRscpAsu
-        );
-        mSimulatedCommands.setSignalStrength(ss);
-        mSimulatedCommands.notifySignalStrength();
-        waitForMs(300);
-        assertEquals(sst.getSignalStrength(), ss);
-        assertEquals(sst.getSignalStrength().getWcdmaLevel(),
-                SignalStrength.SIGNAL_STRENGTH_MODERATE);
-        assertEquals(sst.getSignalStrength().getWcdmaAsuLevel(), 25);
-        assertEquals(sst.getSignalStrength().getWcdmaDbm(), -95);
-
-        ss = new SignalStrength(
-                30, // gsmSignalStrength
-                0,  // gsmBitErrorRate
-                -1, // cdmaDbm
-                -1, // cdmaEcio
-                -1, // evdoDbm
-                -1, // evdoEcio
-                -1, // evdoSnr
-                99, // lteSignalStrength
-                SignalStrength.INVALID,     // lteRsrp
-                SignalStrength.INVALID,     // lteRsrq
-                SignalStrength.INVALID,     // lteRssnr
-                SignalStrength.INVALID,     // lteCqi
-                SignalStrength.INVALID,     // tdScdmaRscp
-                99,                         // wcdmaSignalStrength
-                15                          // wcdmaRscpAsu
-        );
-        mSimulatedCommands.setSignalStrength(ss);
-        mSimulatedCommands.notifySignalStrength();
-        waitForMs(300);
-        assertEquals(sst.getSignalStrength(), ss);
-        assertEquals(sst.getSignalStrength().getWcdmaLevel(), SignalStrength.SIGNAL_STRENGTH_POOR);
-        assertEquals(sst.getSignalStrength().getWcdmaAsuLevel(), 15);
-        assertEquals(sst.getSignalStrength().getWcdmaDbm(), -105);
-
-        ss = new SignalStrength(
-                30, // gsmSignalStrength
-                0,  // gsmBitErrorRate
-                -1, // cdmaDbm
-                -1, // cdmaEcio
-                -1, // evdoDbm
-                -1, // evdoEcio
-                -1, // evdoSnr
-                99, // lteSignalStrength
-                SignalStrength.INVALID,     // lteRsrp
-                SignalStrength.INVALID,     // lteRsrq
-                SignalStrength.INVALID,     // lteRssnr
-                SignalStrength.INVALID,     // lteCqi
-                SignalStrength.INVALID,     // tdScdmaRscp
-                99,                         // wcdmaSignalStrength
-                5                           // wcdmaRscpAsu
-        );
-        mSimulatedCommands.setSignalStrength(ss);
-        mSimulatedCommands.notifySignalStrength();
-        waitForMs(300);
-        assertEquals(sst.getSignalStrength(), ss);
-        assertEquals(sst.getSignalStrength().getWcdmaLevel(),
-                SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
-        assertEquals(sst.getSignalStrength().getWcdmaAsuLevel(), 5);
-        assertEquals(sst.getSignalStrength().getWcdmaDbm(), -115);
+        assertEquals(sst.getSignalStrength().getLevel(), CellSignalStrength.SIGNAL_STRENGTH_GOOD);
     }
 
     @Test
     @MediumTest
     // TODO(nharold): we probably should remove support for this procedure (GET_LOC)
     public void testGsmCellLocation() {
-        CellIdentityGsm cellIdentityGsm = new CellIdentityGsm(0, 0, 2, 3);
+        CellIdentityGsm cellIdentityGsm = new CellIdentityGsm(
+                2, 3, 900, 5, "001", "01", "test", "tst");
         NetworkRegistrationState result = new NetworkRegistrationState(
                 0, 0, 0, 0, 0, false, null, cellIdentityGsm);
 
@@ -748,7 +664,7 @@
     @MediumTest
     // TODO(nharold): we probably should remove support for this procedure (GET_LOC)
     public void testCdmaCellLocation() {
-        CellIdentityCdma cellIdentityCdma = new CellIdentityCdma(1, 2, 3, 4, 5);
+        CellIdentityCdma cellIdentityCdma = new CellIdentityCdma(1, 2, 3, 4, 5, "test", "tst");
         NetworkRegistrationState result = new NetworkRegistrationState(
                 0, 0, 0, 0, 0, false, null, cellIdentityCdma);
 
@@ -1655,8 +1571,12 @@
     }
 
     private void changeRegState(int state, CellIdentity cid, int voiceRat, int dataRat) {
+        LteVopsSupportInfo lteVopsSupportInfo =
+                new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE,
+                    LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE);
         NetworkRegistrationState dataResult = new NetworkRegistrationState(
-                0, 0, state, dataRat, 0, false, null, cid, 1, false, false);
+                0, 0, state, dataRat, 0, false, null, cid, 1, false, false, false,
+                lteVopsSupportInfo);
         sst.mPollingContext[0] = 2;
         // update data reg state to be in service
         sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_GPRS,
@@ -1673,7 +1593,8 @@
     // Expect no rat update when move from E to G.
     @Test
     public void testRatRatchet() throws Exception {
-        CellIdentityGsm cellIdentity = new CellIdentityGsm(-1, -1, -1, -1, -1, -1);
+        CellIdentityGsm cellIdentity =
+                new CellIdentityGsm(0, 1, 900, 5, "001", "01", "test", "tst");
         // start on GPRS
         changeRegState(1, cellIdentity, 16, 1);
         assertEquals(ServiceState.STATE_IN_SERVICE, sst.getCurrentDataConnectionState());
@@ -1690,14 +1611,15 @@
     // Bypass rat rachet when cell id changed. Expect rat update from E to G
     @Test
     public void testRatRatchetWithCellChange() throws Exception {
-        CellIdentityGsm cellIdentity = new CellIdentityGsm(-1, -1, -1, -1, -1, -1);
+        CellIdentityGsm cellIdentity =
+                new CellIdentityGsm(0, 1, 900, 5, "001", "01", "test", "tst");
         // update data reg state to be in service
         changeRegState(1, cellIdentity, 16, 2);
         assertEquals(ServiceState.STATE_IN_SERVICE, sst.getCurrentDataConnectionState());
         assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_GSM, sst.mSS.getRilVoiceRadioTechnology());
         assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_EDGE, sst.mSS.getRilDataRadioTechnology());
-        // RAT: EDGE -> GPRS cell ID: -1 -> 5
-        cellIdentity = new CellIdentityGsm(-1, -1, -1, 5, -1, -1);
+        // RAT: EDGE -> GPRS cell ID: 1 -> 2
+        cellIdentity = new CellIdentityGsm(0, 2, 900, 5, "001", "01", "test", "tst");
         changeRegState(1, cellIdentity, 16, 1);
         assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_GPRS, sst.mSS.getRilDataRadioTechnology());
 
@@ -1711,7 +1633,8 @@
     @Test
     public void testRatRatchetWithCellChangeBeforeRatChange() throws Exception {
         // cell ID update
-        CellIdentityGsm cellIdentity = new CellIdentityGsm(-1, -1, -1, 5, -1, -1);
+        CellIdentityGsm cellIdentity =
+                new CellIdentityGsm(0, 1, 900, 5, "001", "01", "test", "tst");
         changeRegState(1, cellIdentity, 16, 2);
         assertEquals(ServiceState.STATE_IN_SERVICE, sst.getCurrentDataConnectionState());
         assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_EDGE, sst.mSS.getRilDataRadioTechnology());
@@ -1743,9 +1666,12 @@
     }
 
     private void sendRegStateUpdateForLteCellId(CellIdentityLte cellId) {
+        LteVopsSupportInfo lteVopsSupportInfo =
+                new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE,
+                    LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE);
         NetworkRegistrationState dataResult = new NetworkRegistrationState(
                 2, 1, 1, TelephonyManager.NETWORK_TYPE_LTE, 0, false, null, cellId, 1,
-                false, false);
+                false, false, false, lteVopsSupportInfo);
         NetworkRegistrationState voiceResult = new NetworkRegistrationState(
                 1, 1, 1, TelephonyManager.NETWORK_TYPE_LTE, 0, false, null, cellId,
                 false, 0, 0, 0);
@@ -1807,9 +1733,12 @@
     @Test
     public void testPhyChanBandwidthResetsOnOos() throws Exception {
         testPhyChanBandwidthRatchetedOnPhyChanBandwidth();
+        LteVopsSupportInfo lteVopsSupportInfo =
+                new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE,
+                    LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE);
         NetworkRegistrationState dataResult = new NetworkRegistrationState(
                 2, 1, 0, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0, false, null, null, 1, false,
-                false);
+                false, false, lteVopsSupportInfo);
         NetworkRegistrationState voiceResult = new NetworkRegistrationState(
                 1, 1, 0, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0, false, null, null,
                 false, 0, 0, 0);
@@ -1867,4 +1796,55 @@
         doReturn(true).when(mRuimRecords).isProvisioned();
         assertEquals(mockMdn, sst.getMdnNumber());
     }
+
+    @Test
+    @SmallTest
+    public void testOnVopsInfoChanged() {
+        ServiceState ss = new ServiceState();
+        ss.setVoiceRegState(ServiceState.STATE_IN_SERVICE);
+        ss.setDataRegState(ServiceState.STATE_IN_SERVICE);
+        sst.mSS = ss;
+
+        CellIdentityLte cellId =
+                new CellIdentityLte(1, 1, 5, 1, 5000, "001", "01", "test", "tst");
+        LteVopsSupportInfo lteVopsSupportInfo =
+                new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED,
+                    LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED);
+
+        NetworkRegistrationState dataResult = new NetworkRegistrationState(
+                2, 1, 1, TelephonyManager.NETWORK_TYPE_LTE, 0, false, null, cellId, 1,
+                false, false, false, lteVopsSupportInfo);
+        sst.mPollingContext[0] = 2;
+
+        sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_GPRS,
+                new AsyncResult(sst.mPollingContext, dataResult, null)));
+        NetworkRegistrationState voiceResult = new NetworkRegistrationState(
+                1, 1, 1, TelephonyManager.NETWORK_TYPE_LTE, 0, false, null, cellId, false, 0, 0, 0);
+        sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_REGISTRATION,
+                new AsyncResult(sst.mPollingContext, voiceResult, null)));
+
+        waitForMs(200);
+        assertEquals(ServiceState.STATE_IN_SERVICE, sst.getCurrentDataConnectionState());
+        NetworkRegistrationState sSnetworkRegistrationState =
+                sst.mSS.getNetworkRegistrationState(2, 1);
+        assertEquals(lteVopsSupportInfo,
+                sSnetworkRegistrationState.getDataSpecificStates().lteVopsSupportInfo);
+
+        lteVopsSupportInfo =
+                new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_SUPPORTED,
+                    LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED);
+        dataResult = new NetworkRegistrationState(
+                2, 1, 1, TelephonyManager.NETWORK_TYPE_LTE, 0, false, null, cellId, 1,
+                false, false, false, lteVopsSupportInfo);
+        sst.mPollingContext[0] = 1;
+        sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_GPRS,
+                new AsyncResult(sst.mPollingContext, dataResult, null)));
+        waitForMs(200);
+
+        sSnetworkRegistrationState =
+                sst.mSS.getNetworkRegistrationState(2, 1);
+        assertEquals(lteVopsSupportInfo,
+                sSnetworkRegistrationState.getDataSpecificStates().lteVopsSupportInfo);
+
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthTest.java b/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthTest.java
index 0b33c80..e5dbdac 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthTest.java
@@ -20,13 +20,23 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+import android.telephony.CellInfo;
+import android.telephony.CellSignalStrength;
+import android.telephony.CellSignalStrengthCdma;
+import android.telephony.CellSignalStrengthGsm;
+import android.telephony.CellSignalStrengthLte;
+import android.telephony.CellSignalStrengthTdscdma;
+import android.telephony.CellSignalStrengthWcdma;
 import android.telephony.SignalStrength;
 
+import androidx.test.filters.SmallTest;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+import java.util.List;
+
 /** Unit tests for {@link IpSecConfig}. */
 @SmallTest
 @RunWith(JUnit4.class)
@@ -35,12 +45,15 @@
     @Test
     public void testDefaults() throws Exception {
         SignalStrength s = new SignalStrength();
-        assertEquals(SignalStrength.INVALID, s.getCdmaDbm());
-        assertEquals(-1, s.getCdmaEcio());
-        assertEquals(SignalStrength.INVALID, s.getEvdoDbm());
-        assertEquals(-1, s.getEvdoEcio());
-        assertEquals(-1, s.getEvdoSnr());
-        assertEquals(-1, s.getGsmBitErrorRate());
+        assertEquals(CellInfo.UNAVAILABLE, s.getCdmaDbm());
+        assertEquals(CellInfo.UNAVAILABLE, s.getCdmaEcio());
+        assertEquals(CellInfo.UNAVAILABLE, s.getEvdoDbm());
+        assertEquals(CellInfo.UNAVAILABLE, s.getEvdoEcio());
+        assertEquals(CellInfo.UNAVAILABLE, s.getEvdoSnr());
+        assertEquals(CellInfo.UNAVAILABLE, s.getGsmBitErrorRate());
+        // getGsmSignalStrength is an oddball because internally it actually returns an AsuLevel
+        // rather than a dBm value. For backwards compatibility reasons, this is left as the
+        // RSSI ASU value [0-31], 99.
         assertEquals(99, s.getGsmSignalStrength());
         assertEquals(true, s.isGsm());
     }
@@ -50,25 +63,11 @@
         assertParcelingIsLossless(new SignalStrength());
 
         SignalStrength s = new SignalStrength(
-                20,      // gsmSignalStrength
-                5,       // gsmBitErrorRate
-                -95,     // cdmaDbm
-                10,      // cdmaEcio
-                -98,     // evdoDbm
-                -5,      // evdoEcio
-                -2,      // evdoSnr
-                45,      // lteSignalStrength
-                -105,    // lteRsrp
-                -110,    // lteRsrq
-                -115,    // lteRssnr
-                13,      // lteCqi
-                -90,     // tdscdmaRscp
-                45,      // wcdmaSignalStrength
-                20,      // wcdmaRscpAsu
-                2,       // lteRsrpBoost
-                false,   // gsmFlag
-                true,    // lteLevelBaseOnRsrp
-                "rscp"); // wcdmaDefaultMeasurement
+                new CellSignalStrengthCdma(-93, -132, -89, -125, 5),
+                new CellSignalStrengthGsm(-79, 2, 5),
+                new CellSignalStrengthWcdma(-94, 4, -102, -5),
+                new CellSignalStrengthTdscdma(-95, 2, -103),
+                new CellSignalStrengthLte(-85, -91, -6, -10, 12, 1));
         assertParcelingIsLossless(s);
     }
 
@@ -79,5 +78,39 @@
         SignalStrength sso = SignalStrength.CREATOR.createFromParcel(p);
         assertTrue(sso.equals(ssi));
     }
+
+    @Test
+    public void testGetCellSignalStrengths() throws Exception {
+        CellSignalStrengthLte lte = new CellSignalStrengthLte(-85, -91, -6, -10, 12, 1);
+        CellSignalStrengthGsm gsm = new CellSignalStrengthGsm(-79, 2, 5);
+        CellSignalStrengthCdma cdma = new CellSignalStrengthCdma(-93, -132, -89, -125, 5);
+        CellSignalStrengthWcdma wcdma = new CellSignalStrengthWcdma(-94, 4, -102, -5);
+        CellSignalStrengthTdscdma tdscdma = new CellSignalStrengthTdscdma(-95, 2, -103);
+
+        // Test that a single object is properly stored and returned by getCellSignalStrengths()
+        SignalStrength s = new SignalStrength(
+                new CellSignalStrengthCdma(),
+                gsm,
+                new CellSignalStrengthWcdma(),
+                new CellSignalStrengthTdscdma(),
+                new CellSignalStrengthLte());
+
+        List<CellSignalStrength> css = s.getCellSignalStrengths();
+        assertEquals(1, css.size());
+        assertTrue(gsm.equals(css.get(0)));
+
+        // Test that a multiple objects are properly stored and returned by getCellSignalStrengths()
+        s = new SignalStrength(
+                cdma,
+                new CellSignalStrengthGsm(),
+                new CellSignalStrengthWcdma(),
+                new CellSignalStrengthTdscdma(),
+                lte);
+
+        css = s.getCellSignalStrengths();
+        assertEquals(2, css.size());
+        assertTrue(css.contains(cdma));
+        assertTrue(css.contains(lte));
+    }
 }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/Sms7BitEncodingTranslatorTest.java b/tests/telephonytests/src/com/android/internal/telephony/Sms7BitEncodingTranslatorTest.java
index cf11d1b..0ada744 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/Sms7BitEncodingTranslatorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/Sms7BitEncodingTranslatorTest.java
@@ -21,9 +21,10 @@
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.doReturn;
 
-import android.support.test.filters.FlakyTest;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.FlakyTest;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsUsageMonitorShortCodeTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsUsageMonitorShortCodeTest.java
index 76fce94..2d7fc4f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SmsUsageMonitorShortCodeTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SmsUsageMonitorShortCodeTest.java
@@ -25,7 +25,8 @@
 import static org.junit.Assert.assertEquals;
 
 import android.os.Looper;
-import android.support.test.filters.FlakyTest;
+
+import androidx.test.filters.FlakyTest;
 
 import org.junit.Ignore;
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
index 8e124fa..a9476d9 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.doReturn;
@@ -45,6 +46,7 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 
+import java.util.Arrays;
 import java.util.List;
 
 public class SubscriptionControllerTest extends TelephonyTest {
@@ -250,6 +252,24 @@
                 captorIntent.getValue().getAction());
     }
 
+    @Test @SmallTest
+    public void testSetGetCarrierId() {
+        testInsertSim();
+        int carrierId = 1234;
+        mSubscriptionControllerUT.setCarrierId(carrierId, 1);
+
+        SubscriptionInfo subInfo = mSubscriptionControllerUT
+                .getActiveSubscriptionInfo(1, mCallingPackage);
+        assertNotNull(subInfo);
+        assertEquals(carrierId, subInfo.getCarrierId());
+
+         /* verify broadcast intent */
+        ArgumentCaptor<Intent> captorIntent = ArgumentCaptor.forClass(Intent.class);
+        verify(mContext, atLeast(1)).sendBroadcast(captorIntent.capture());
+        assertEquals(TelephonyIntents.ACTION_SUBINFO_RECORD_UPDATED,
+                captorIntent.getValue().getAction());
+    }
+
     @Test
     @SmallTest
     public void testSetDefaultDataSubId() throws Exception {
@@ -398,14 +418,17 @@
         mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE);
 
         int[] subIdList = new int[] {1, 2};
-        // It should fail since it has no permission.
-        String groupId = mSubscriptionControllerUT.setSubscriptionGroup(
-                subIdList, mContext.getOpPackageName());
-        assertEquals(null, groupId);
+        try {
+            mSubscriptionControllerUT.setSubscriptionGroup(
+                    subIdList, mContext.getOpPackageName());
+            fail("setSubscriptionGroup should fail with no permission.");
+        } catch (SecurityException e) {
+            // Expected result.
+        }
 
         // With modify permission it should succeed.
         mContextFixture.addCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE);
-        groupId = mSubscriptionControllerUT.setSubscriptionGroup(
+        String groupId = mSubscriptionControllerUT.setSubscriptionGroup(
                 subIdList, mContext.getOpPackageName());
         assertNotEquals(null, groupId);
 
@@ -414,13 +437,6 @@
                 subIdList, mContext.getOpPackageName());
         assertNotEquals(null, newGroupId);
         assertNotEquals(groupId, newGroupId);
-
-        // SubId 6 doesn't exist. Should fail.
-        subIdList = new int[] {1, 6};
-        mContextFixture.addCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE);
-        groupId = mSubscriptionControllerUT.setSubscriptionGroup(
-                subIdList, mContext.getOpPackageName());
-        assertEquals(null, groupId);
     }
 
     @Test
@@ -428,7 +444,7 @@
     public void testSetSubscriptionGroupWithCarrierPrivilegePermission() throws Exception {
         testInsertSim();
         // Adding a second profile and mark as embedded.
-        mSubscriptionControllerUT.addSubInfoRecord("test2", 0);
+        mSubscriptionControllerUT.addSubInfoRecord("test2", 1);
         ContentValues values = new ContentValues();
         values.put(SubscriptionManager.IS_EMBEDDED, 1);
         mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values,
@@ -440,26 +456,38 @@
 
         int[] subIdList = new int[] {1, 2};
         // It should fail since it has no permission.
-        String groupId = mSubscriptionControllerUT.setSubscriptionGroup(
-                subIdList, mContext.getOpPackageName());
-        assertEquals(null, groupId);
+        try {
+            mSubscriptionControllerUT.setSubscriptionGroup(
+                    subIdList, mContext.getOpPackageName());
+            fail("setSubscriptionGroup should fail with no permission.");
+        } catch (SecurityException e) {
+            // Expected result.
+        }
 
-        // With modify permission it should succeed.
         doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(1);
-        groupId = mSubscriptionControllerUT.setSubscriptionGroup(
-                subIdList, mContext.getOpPackageName());
-        assertEquals(null, groupId);
+        try {
+            mSubscriptionControllerUT.setSubscriptionGroup(
+                    subIdList, mContext.getOpPackageName());
+            fail("setSubscriptionGroup should fail with no permission on sub 2.");
+        } catch (SecurityException e) {
+            // Expected result.
+        }
 
         doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(2);
-        groupId = mSubscriptionControllerUT.setSubscriptionGroup(
+        String groupId = mSubscriptionControllerUT.setSubscriptionGroup(
                 subIdList, mContext.getOpPackageName());
         assertNotEquals(null, groupId);
 
         List<SubscriptionInfo> subInfoList = mSubscriptionControllerUT
                 .getActiveSubscriptionInfoList(mContext.getOpPackageName());
 
-        // Revoke carrier privilege of sub 2 but make it manageable by caller.
-        doReturn(false).when(mTelephonyManager).hasCarrierPrivileges(2);
+        // Put sub3 into slot 1 to make sub2 inactive.
+        mContextFixture.addCallingOrSelfPermission(
+                android.Manifest.permission.MODIFY_PHONE_STATE);
+        mSubscriptionControllerUT.addSubInfoRecord("test3", 1);
+        mContextFixture.removeCallingOrSelfPermission(
+                android.Manifest.permission.MODIFY_PHONE_STATE);
+        // As sub2 is inactive, it will checks carrier privilege against access rules in the db.
         doReturn(true).when(mSubscriptionManager).canManageSubscription(
                 eq(subInfoList.get(1)), anyString());
 
@@ -469,9 +497,104 @@
         assertNotEquals(groupId, newGroupId);
     }
 
+    @Test
+    @SmallTest
+    public void testDisabledSubscriptionGroup() throws Exception {
+        registerMockTelephonyRegistry();
+
+        testInsertSim();
+        // Adding a second profile and mark as embedded.
+        mSubscriptionControllerUT.addSubInfoRecord("test2", 0);
+
+        ContentValues values = new ContentValues();
+        values.put(SubscriptionManager.IS_EMBEDDED, 1);
+        values.put(SubscriptionManager.IS_OPPORTUNISTIC, 1);
+        mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values,
+                SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 2, null);
+        mSubscriptionControllerUT.refreshCachedActiveSubscriptionInfoList();
+
+        verify(mTelephonyRegisteryMock, times(1))
+                .notifyOpportunisticSubscriptionInfoChanged();
+
+        // Set sub 1 and 2 into same group.
+        int[] subIdList = new int[] {1, 2};
+        String groupId = mSubscriptionControllerUT.setSubscriptionGroup(
+                subIdList, mContext.getOpPackageName());
+        assertNotEquals(null, groupId);
+
+        verify(mTelephonyRegisteryMock, times(2))
+                .notifyOpportunisticSubscriptionInfoChanged();
+        List<SubscriptionInfo> opptSubList = mSubscriptionControllerUT
+                .getOpportunisticSubscriptions(mCallingPackage);
+        assertEquals(1, opptSubList.size());
+        assertEquals(2, opptSubList.get(0).getSubscriptionId());
+        assertEquals(false, opptSubList.get(0).isGroupDisabled());
+
+        // Unplug SIM 1. This should trigger subscription controller disabling sub 2.
+        values = new ContentValues();
+        values.put(SubscriptionManager.SIM_SLOT_INDEX, -1);
+        mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values,
+                SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 1, null);
+        mSubscriptionControllerUT.refreshCachedActiveSubscriptionInfoList();
+
+        verify(mTelephonyRegisteryMock, times(3))
+                .notifyOpportunisticSubscriptionInfoChanged();
+        opptSubList = mSubscriptionControllerUT.getOpportunisticSubscriptions(mCallingPackage);
+        assertEquals(1, opptSubList.size());
+        assertEquals(2, opptSubList.get(0).getSubscriptionId());
+        assertEquals(true, opptSubList.get(0).isGroupDisabled());
+    }
+
+    @Test
+    @SmallTest
+    public void testSetSubscriptionGroup() throws Exception {
+        testInsertSim();
+        // Adding a second profile and mark as embedded.
+        mSubscriptionControllerUT.addSubInfoRecord("test2", 0);
+        ContentValues values = new ContentValues();
+        values.put(SubscriptionManager.IS_EMBEDDED, 1);
+        mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values,
+                SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 2, null);
+        mSubscriptionControllerUT.refreshCachedActiveSubscriptionInfoList();
+
+        int[] subIdList = new int[] {1, 2};
+        String groupUuid = mSubscriptionControllerUT.setSubscriptionGroup(
+                subIdList, mContext.getOpPackageName());
+        assertNotEquals(null, groupUuid);
+
+        // Sub 1 and sub 2 should be in same group.
+        List<SubscriptionInfo> infoList = mSubscriptionControllerUT
+                .getSubscriptionsInGroup(1, mContext.getOpPackageName());
+        assertNotEquals(null, infoList);
+        assertEquals(2, infoList.size());
+        assertEquals(1, infoList.get(0).getSubscriptionId());
+        assertEquals(2, infoList.get(1).getSubscriptionId());
+
+        // Remove group of sub 1.
+        subIdList = new int[] {1};
+        boolean result = mSubscriptionControllerUT.removeSubscriptionsFromGroup(
+                subIdList, mContext.getOpPackageName());
+        assertEquals(true, result);
+        infoList = mSubscriptionControllerUT
+                .getSubscriptionsInGroup(2, mContext.getOpPackageName());
+        assertEquals(1, infoList.size());
+        assertEquals(2, infoList.get(0).getSubscriptionId());
+    }
+
     private void registerMockTelephonyRegistry() {
         mServiceManagerMockedServices.put("telephony.registry", mTelephonyRegisteryMock);
         doReturn(mTelephonyRegisteryMock).when(mTelephonyRegisteryMock)
                 .queryLocalInterface(anyString());
     }
+
+    @Test
+    @SmallTest
+    public void testGetActiveSubIdList() throws Exception {
+        mSubscriptionControllerUT.addSubInfoRecord("123", 1);   // sub 1
+        mSubscriptionControllerUT.addSubInfoRecord("456", 0);   // sub 2
+
+        // Make sure the return sub ids are sorted by slot index
+        assertTrue("active sub ids = " + mSubscriptionControllerUT.getActiveSubIdList(),
+                Arrays.equals(mSubscriptionControllerUT.getActiveSubIdList(), new int[]{2, 1}));
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 5fd046f..74f288d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -18,6 +18,7 @@
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.nullable;
 import static org.mockito.Mockito.anyInt;
@@ -43,6 +44,7 @@
 import android.os.ServiceManager;
 import android.provider.BlockedNumberContract;
 import android.provider.Settings;
+import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -58,8 +60,10 @@
 import com.android.ims.ImsManager;
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
 import com.android.internal.telephony.cdma.EriManager;
+import com.android.internal.telephony.dataconnection.DataEnabledSettings;
 import com.android.internal.telephony.dataconnection.DcTracker;
 import com.android.internal.telephony.dataconnection.TransportManager;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
 import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
@@ -103,6 +107,8 @@
     @Mock
     protected ServiceStateTracker mSST;
     @Mock
+    protected EmergencyNumberTracker mEmergencyNumberTracker;
+    @Mock
     protected GsmCdmaCallTracker mCT;
     @Mock
     protected ImsPhoneCallTracker mImsCT;
@@ -204,6 +210,8 @@
     protected LocaleTracker mLocaleTracker;
     @Mock
     protected RestrictedState mRestrictedState;
+    @Mock
+    protected DataEnabledSettings mDataEnabledSettings;
 
     protected ImsCallProfile mImsCallProfile;
     protected TelephonyManager mTelephonyManager;
@@ -335,9 +343,13 @@
         mPackageManager = mContext.getPackageManager();
 
         //mTelephonyComponentFactory
+        doReturn(mTelephonyComponentFactory).when(mTelephonyComponentFactory).inject(anyString());
         doReturn(mSST).when(mTelephonyComponentFactory)
                 .makeServiceStateTracker(nullable(GsmCdmaPhone.class),
                         nullable(CommandsInterface.class));
+        doReturn(mEmergencyNumberTracker).when(mTelephonyComponentFactory)
+                .makeEmergencyNumberTracker(nullable(Phone.class),
+                        nullable(CommandsInterface.class));
         doReturn(mUiccProfile).when(mTelephonyComponentFactory)
                 .makeUiccProfile(nullable(Context.class), nullable(CommandsInterface.class),
                         nullable(IccCardStatus.class), anyInt(), nullable(UiccCard.class),
@@ -347,7 +359,7 @@
         doReturn(mIccPhoneBookIntManager).when(mTelephonyComponentFactory)
                 .makeIccPhoneBookInterfaceManager(nullable(Phone.class));
         doReturn(mDcTracker).when(mTelephonyComponentFactory)
-                .makeDcTracker(nullable(Phone.class));
+                .makeDcTracker(nullable(Phone.class), anyInt());
         doReturn(mWspTypeDecoder).when(mTelephonyComponentFactory)
                 .makeWspTypeDecoder(nullable(byte[].class));
         doReturn(mImsCT).when(mTelephonyComponentFactory)
@@ -375,6 +387,8 @@
         doReturn(mLocaleTracker).when(mTelephonyComponentFactory)
                 .makeLocaleTracker(nullable(Phone.class), nullable(NitzStateMachine.class),
                         nullable(Looper.class));
+        doReturn(mDataEnabledSettings).when(mTelephonyComponentFactory)
+                .makeDataEnabledSettings(nullable(Phone.class));
 
         //mPhone
         doReturn(mContext).when(mPhone).getContext();
@@ -384,17 +398,18 @@
         doReturn(mServiceState).when(mPhone).getServiceState();
         doReturn(mServiceState).when(mImsPhone).getServiceState();
         doReturn(mPhone).when(mImsPhone).getDefaultPhone();
-        mPhone.mDcTracker = mDcTracker;
-        doReturn(true).when(mDcTracker).isDataEnabled();
         doReturn(true).when(mPhone).isPhoneTypeGsm();
         doReturn(PhoneConstants.PHONE_TYPE_GSM).when(mPhone).getPhoneType();
         doReturn(mCT).when(mPhone).getCallTracker();
         doReturn(mSST).when(mPhone).getServiceStateTracker();
+        doReturn(mEmergencyNumberTracker).when(mPhone).getEmergencyNumberTracker();
         doReturn(mCarrierSignalAgent).when(mPhone).getCarrierSignalAgent();
         doReturn(mCarrierActionAgent).when(mPhone).getCarrierActionAgent();
         doReturn(mAppSmsManager).when(mPhone).getAppSmsManager();
         doReturn(mIccSmsInterfaceManager).when(mPhone).getIccSmsInterfaceManager();
         doReturn(mTransportManager).when(mPhone).getTransportManager();
+        doReturn(mDataEnabledSettings).when(mPhone).getDataEnabledSettings();
+        doReturn(mDcTracker).when(mPhone).getDcTracker(anyInt());
         mIccSmsInterfaceManager.mDispatchersController = mSmsDispatchersController;
         mPhone.mEriManager = mEriManager;
 
@@ -467,6 +482,11 @@
         mSST.mSS = mServiceState;
         mSST.mRestrictedState = mRestrictedState;
         mServiceManagerMockedServices.put("connectivity_metrics_logger", mConnMetLoggerBinder);
+        doReturn(new int[]{TransportType.WWAN, TransportType.WLAN})
+                .when(mTransportManager).getAvailableTransports();
+        doReturn(TransportType.WWAN).when(mTransportManager).getCurrentTransport(anyInt());
+        doReturn(true).when(mDataEnabledSettings).isDataEnabled();
+        doReturn(true).when(mDataEnabledSettings).isInternalDataEnabled();
 
         //SIM
         doReturn(1).when(mTelephonyManager).getSimCount();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java
index 08e54ac..604772b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java
@@ -40,10 +40,11 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Telephony;
-import android.support.test.filters.FlakyTest;
 import android.test.mock.MockContentResolver;
 import android.test.suitebuilder.annotation.MediumTest;
 
+import androidx.test.filters.FlakyTest;
+
 import com.android.internal.telephony.FakeSmsContentProvider;
 import com.android.internal.telephony.InboundSmsHandler;
 import com.android.internal.telephony.InboundSmsTracker;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java
index 55036ad..cae6566 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java
@@ -17,7 +17,6 @@
 package com.android.internal.telephony.cdma;
 
 import android.hardware.radio.V1_0.CdmaSmsMessage;
-import android.support.test.filters.FlakyTest;
 import android.telephony.Rlog;
 import android.telephony.SmsCbCmasInfo;
 import android.telephony.SmsCbMessage;
@@ -25,6 +24,8 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.FlakyTest;
+
 import com.android.internal.telephony.GsmAlphabet;
 import com.android.internal.telephony.cdma.sms.BearerData;
 import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java
index 32cad59..2d2d7ba 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java
@@ -111,7 +111,7 @@
         mApnContext.setDependencyMet(true);
         assertFalse(mApnContext.isConnectable());
 
-        mApnContext.setState(DctConstants.State.SCANNING);
+        mApnContext.setState(DctConstants.State.RETRYING);
         assertTrue(mApnContext.isConnectable());
         assertTrue(mApnContext.isConnectedOrConnecting());
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java
index b7b8d83..8893742 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java
@@ -292,9 +292,9 @@
                 null, null, -1, "user", "password", 0,
                 ApnSetting.TYPE_DEFAULT, ApnSetting.PROTOCOL_IPV6, ApnSetting.PROTOCOL_IP, true,
                 4096, 0, false, 0, 0, 0, 0, ApnSetting.MVNO_TYPE_SPN, "");
-        String expected = "[ApnSettingV5] Name, 99, 12345, apn, null, "
+        String expected = "[ApnSettingV6] Name, 99, 12345, apn, null, "
                 + "null, null, null, 10, 0, default, "
-                + "IPV6, IP, true, 0, false, 0, 0, 0, 0, spn, , false, 4096, 0";
+                + "IPV6, IP, true, 0, false, 0, 0, 0, 0, spn, , false, 4096, 0, -1";
         assertEquals(expected, apn.toString());
 
         final int networkTypeBitmask = 1 << (14 - 1);
@@ -303,9 +303,9 @@
                 null, null, -1, "user", "password", 0,
                 ApnSetting.TYPE_DEFAULT, ApnSetting.PROTOCOL_IPV6, ApnSetting.PROTOCOL_IP, true,
                 networkTypeBitmask, 0, false, 0, 0, 0, 0, ApnSetting.MVNO_TYPE_SPN, "", 3, -1);
-        expected = "[ApnSettingV5] Name, 99, 12345, apn, null, "
+        expected = "[ApnSettingV6] Name, 99, 12345, apn, null, "
                 + "null, null, null, 10, 0, default, "
-                + "IPV6, IP, true, 0, false, 0, 0, 0, 0, spn, , false, 8192, 3";
+                + "IPV6, IP, true, 0, false, 0, 0, 0, 0, spn, , false, 8192, 3, -1";
         assertEquals(expected, apn.toString());
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
index dab06d8..2bd4d2d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
@@ -201,7 +201,6 @@
                 ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
         doReturn(mApn1).when(mApnContext).getApnSetting();
         doReturn(PhoneConstants.APN_TYPE_DEFAULT).when(mApnContext).getApnType();
-        doReturn(true).when(mDcTracker).isDataEnabled();
 
         mDcFailBringUp.saveParameters(0, 0, -2);
         doReturn(mDcFailBringUp).when(mDcTesterFailBringUpAll).getDcFailBringUp();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcFailCauseTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataFailCauseTest.java
similarity index 82%
rename from tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcFailCauseTest.java
rename to tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataFailCauseTest.java
index 48fc139..e881cc9 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcFailCauseTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataFailCauseTest.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
+import android.telephony.DataFailCause;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.internal.telephony.TelephonyTest;
@@ -36,7 +37,7 @@
 import java.util.ArrayList;
 import java.util.Random;
 
-public class DcFailCauseTest extends TelephonyTest {
+public class DataFailCauseTest extends TelephonyTest {
 
     private PersistableBundle mPersistableBundle;
 
@@ -161,10 +162,12 @@
     @SmallTest
     public void testPermanentFailDefault() throws Exception {
         for (DcFailCauseData data : mFailCauseDataList) {
-            assertEquals("cause = " + data.mCause, data.mPermanentFailure, DcFailCause.fromInt(
-                    data.mCause).isPermanentFailure(mContext, mPhone.getSubId()));
+            assertEquals("cause = " + data.mCause, data.mPermanentFailure,
+                    DataFailCause.isPermanentFailure(mContext, DataFailCause.getFailCause(
+                    data.mCause), mPhone.getSubId()));
         }
-        assertFalse(DcFailCause.fromInt(123456).isPermanentFailure(mContext, mPhone.getSubId()));
+        assertFalse(DataFailCause.isPermanentFailure(mContext,
+                DataFailCause.getFailCause(123456), mPhone.getSubId()));
     }
 
     @Test
@@ -180,14 +183,17 @@
         // Run it twice to make sure the cached carrier config is working as expected.
         for (int i = 0; i < 2; i++) {
             for (DcFailCauseData data : mFailCauseDataList) {
-                if (DcFailCause.fromInt(data.mCause).equals(
-                        DcFailCause.SERVICE_OPTION_NOT_SUBSCRIBED) ||
-                        DcFailCause.fromInt(data.mCause).equals(DcFailCause.TETHERED_CALL_ACTIVE)) {
-                    assertTrue("cause = " + data.mCause, DcFailCause.fromInt(data.mCause).
-                            isPermanentFailure(mContext, mPhone.getSubId()));
+                if (DataFailCause.getFailCause(data.mCause) == (
+                        DataFailCause.SERVICE_OPTION_NOT_SUBSCRIBED) ||
+                        DataFailCause.getFailCause(data.mCause) == (
+                                DataFailCause.TETHERED_CALL_ACTIVE)) {
+                    assertTrue("cause = " + data.mCause,
+                            DataFailCause.isPermanentFailure(mContext,
+                                    DataFailCause.getFailCause(data.mCause), mPhone.getSubId()));
                 } else {
-                    assertFalse("cause = " + data.mCause, DcFailCause.fromInt(data.mCause).
-                            isPermanentFailure(mContext, mPhone.getSubId()));
+                    assertFalse("cause = " + data.mCause,
+                            DataFailCause.isPermanentFailure(mContext,
+                                    DataFailCause.getFailCause(data.mCause), mPhone.getSubId()));
                 }
             }
         }
@@ -198,43 +204,43 @@
     public void testEventLoggable() throws Exception {
         for (DcFailCauseData data : mFailCauseDataList) {
             assertEquals("cause = " + data.mCause, data.mEventLoggable,
-                    DcFailCause.fromInt(data.mCause).isEventLoggable());
+                    DataFailCause.isEventLoggable(DataFailCause.getFailCause(data.mCause)));
         }
-        assertFalse(DcFailCause.fromInt(123456).isEventLoggable());
+        assertFalse(DataFailCause.isEventLoggable(DataFailCause.getFailCause(123456)));
     }
 
     @Test
     @SmallTest
     public void testGetErrorCode() throws Exception {
         for (DcFailCauseData data : mFailCauseDataList) {
-            assertEquals(data.mCause, DcFailCause.fromInt(data.mCause).getErrorCode());
+            assertEquals(data.mCause, DataFailCause.getFailCause(data.mCause));
         }
-        assertEquals(DcFailCause.UNKNOWN.getErrorCode(),
-                DcFailCause.fromInt(123456).getErrorCode());
+        assertEquals(DataFailCause.UNKNOWN,
+                DataFailCause.getFailCause(123456));
     }
 
     @Test
     public void testIsRadioRestartFailureRegularDeactivation() {
-        assertFalse(DcFailCause.fromInt(DcFailCause.REGULAR_DEACTIVATION.getErrorCode())
-                .isRadioRestartFailure(mContext, mPhone.getSubId()));
+        assertFalse(DataFailCause.isRadioRestartFailure(mContext,
+                DataFailCause.getFailCause(DataFailCause.REGULAR_DEACTIVATION), mPhone.getSubId()));
         mPersistableBundle.putBoolean(CarrierConfigManager
                 .KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL, true);
-        assertTrue(DcFailCause.fromInt(DcFailCause.REGULAR_DEACTIVATION.getErrorCode())
-                .isRadioRestartFailure(mContext, mPhone.getSubId()));
+        assertTrue(DataFailCause.isRadioRestartFailure(mContext,
+                DataFailCause.getFailCause(DataFailCause.REGULAR_DEACTIVATION), mPhone.getSubId()));
     }
 
     @Test
     public void testIsRadioRestartFailureNotRegularDeactivation() {
-        DcFailCause randomCause = DcFailCause.fromInt(mFailCauseDataList
+        int randomCause = DataFailCause.getFailCause(mFailCauseDataList
                 .get(new Random().nextInt(mFailCauseDataList.size())).mCause);
-        while (randomCause == DcFailCause.REGULAR_DEACTIVATION) {
-            randomCause = DcFailCause.fromInt(mFailCauseDataList
+        while (randomCause == DataFailCause.REGULAR_DEACTIVATION) {
+            randomCause = DataFailCause.getFailCause(mFailCauseDataList
                     .get(new Random().nextInt(mFailCauseDataList.size())).mCause);
         }
-        assertFalse(randomCause.isRadioRestartFailure(mContext, mPhone.getSubId()));
-        int [] matchingErrorCodes = {randomCause.getErrorCode()};
+        assertFalse(DataFailCause.isRadioRestartFailure(mContext, randomCause, mPhone.getSubId()));
+        int [] matchingErrorCodes = {randomCause};
         mPersistableBundle.putIntArray(CarrierConfigManager
                 .KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY, matchingErrorCodes);
-        assertTrue(randomCause.isRadioRestartFailure(mContext, mPhone.getSubId()));
+        assertTrue(DataFailCause.isRadioRestartFailure(mContext, randomCause, mPhone.getSubId()));
     }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
index a5025d1..5e1188b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
@@ -29,10 +29,10 @@
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
@@ -59,7 +59,6 @@
 import android.os.PersistableBundle;
 import android.provider.Settings;
 import android.provider.Telephony;
-import android.support.test.filters.FlakyTest;
 import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.CarrierConfigManager;
 import android.telephony.ServiceState;
@@ -77,10 +76,11 @@
 import android.util.LocalLog;
 import android.util.Pair;
 
+import androidx.test.filters.FlakyTest;
+
 import com.android.internal.R;
 import com.android.internal.telephony.DctConstants;
 import com.android.internal.telephony.ISub;
-import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyTest;
 import com.android.server.pm.PackageManagerService;
@@ -97,9 +97,6 @@
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 public class DcTrackerTest extends TelephonyTest {
 
@@ -110,8 +107,6 @@
             "mobile_ims,11,0,2,60000,true", "mobile_cbs,12,0,2,60000,true",
             "mobile_ia,14,0,2,-1,true", "mobile_emergency,15,0,2,-1,true"};
 
-    private final static List<String> sApnTypes = Arrays.asList(
-            "default", "mms", "cbs", "fota", "supl", "ia", "emergency", "dun", "hipri", "ims");
     private static final int LTE_BEARER_BITMASK = 1 << (ServiceState.RIL_RADIO_TECHNOLOGY_LTE - 1);
     private static final int EHRPD_BEARER_BITMASK =
             1 << (ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD - 1);
@@ -132,20 +127,17 @@
     private static final Uri PREFERAPN_URI = Uri.parse(
             Telephony.Carriers.CONTENT_URI + "/preferapn");
     private static final int DATA_ENABLED_CHANGED = 0;
+    private static final String FAKE_PLMN = "44010";
 
     @Mock
     ISub mIsub;
     @Mock
     IBinder mBinder;
     @Mock
-    NetworkRequest mNetworkRequest;
-    @Mock
     SubscriptionInfo mSubscriptionInfo;
     @Mock
     ApnContext mApnContext;
     @Mock
-    ApnSetting mApnSetting;
-    @Mock
     DataConnection mDataConnection;
     @Mock
     PackageManagerService mMockPackageManagerInternal;
@@ -208,20 +200,13 @@
             logd("   sortOrder = " + sortOrder);
 
             if (uri.compareTo(Telephony.Carriers.CONTENT_URI) == 0
-                    || uri.compareTo(Uri.withAppendedPath(
-                            Telephony.Carriers.CONTENT_URI, "filtered")) == 0) {
-                if (projection == null && selectionArgs == null && selection != null) {
+                    || uri.toString().startsWith(Uri.withAppendedPath(
+                            Telephony.Carriers.CONTENT_URI, "filtered").toString())
+                    || uri.toString().startsWith(Uri.withAppendedPath(
+                            Telephony.Carriers.SIM_APN_URI, "filtered").toString())) {
+                if (projection == null) {
 
-                    Pattern pattern = Pattern.compile("^numeric = '([0-9]*)'");
-                    Matcher matcher = pattern.matcher(selection);
-                    if (!matcher.find()) {
-                        logd("Cannot find MCC/MNC from " + selection);
-                        return null;
-                    }
-
-                    String plmn = matcher.group(1);
-
-                    logd("Query '" + plmn + "' APN settings");
+                    logd("Query '" + FAKE_PLMN + "' APN settings");
                     MatrixCursor mc = new MatrixCursor(
                             new String[]{Telephony.Carriers._ID, Telephony.Carriers.NUMERIC,
                                     Telephony.Carriers.NAME, Telephony.Carriers.APN,
@@ -235,9 +220,11 @@
                                     Telephony.Carriers.CARRIER_ENABLED, Telephony.Carriers.BEARER,
                                     Telephony.Carriers.BEARER_BITMASK,
                                     Telephony.Carriers.PROFILE_ID,
-                                    Telephony.Carriers.MODEM_COGNITIVE,
-                                    Telephony.Carriers.MAX_CONNS, Telephony.Carriers.WAIT_TIME,
-                                    Telephony.Carriers.MAX_CONNS_TIME, Telephony.Carriers.MTU,
+                                    Telephony.Carriers.MODEM_PERSIST,
+                                    Telephony.Carriers.MAX_CONNECTIONS,
+                                    Telephony.Carriers.WAIT_TIME_RETRY,
+                                    Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS,
+                                    Telephony.Carriers.MTU,
                                     Telephony.Carriers.MVNO_TYPE,
                                     Telephony.Carriers.MVNO_MATCH_DATA,
                                     Telephony.Carriers.NETWORK_TYPE_BITMASK,
@@ -246,7 +233,7 @@
 
                     mc.addRow(new Object[]{
                             2163,                   // id
-                            plmn,                   // numeric
+                            FAKE_PLMN,              // numeric
                             "sp-mode",              // name
                             FAKE_APN1,              // apn
                             "",                     // proxy
@@ -278,7 +265,7 @@
 
                     mc.addRow(new Object[]{
                             2164,                   // id
-                            plmn,                   // numeric
+                            FAKE_PLMN,              // numeric
                             "mopera U",             // name
                             FAKE_APN2,              // apn
                             "",                     // proxy
@@ -310,7 +297,7 @@
 
                     mc.addRow(new Object[]{
                             2165,                   // id
-                            plmn,                   // numeric
+                            FAKE_PLMN,              // numeric
                             "b-mobile for Nexus",   // name
                             FAKE_APN3,              // apn
                             "",                     // proxy
@@ -342,7 +329,7 @@
 
                     mc.addRow(new Object[]{
                             2166,                   // id
-                            plmn,                   // numeric
+                            FAKE_PLMN,              // numeric
                             "sp-mode ehrpd",        // name
                             FAKE_APN4,              // apn
                             "",                     // proxy
@@ -373,8 +360,8 @@
                     });
 
                     mc.addRow(new Object[]{
-                            2166,                   // id
-                            plmn,                   // numeric
+                            2167,                   // id
+                            FAKE_PLMN,              // numeric
                             "b-mobile for Nexus",   // name
                             FAKE_APN5,              // apn
                             "",                     // proxy
@@ -435,7 +422,6 @@
         doReturn("fake.action_attached").when(mPhone).getActionAttached();
         doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_LTE).when(mServiceState)
                 .getRilDataRadioTechnology();
-        doReturn("44010").when(mSimRecords).getOperatorNumeric();
 
         mContextFixture.putStringArrayResource(com.android.internal.R.array.networkAttributes,
                 sNetworkAttributes);
@@ -543,7 +529,7 @@
     }
 
     private void verifyDataConnected(final String apnSetting) {
-        verify(mPhone, times(1)).notifyDataConnection(eq(Phone.REASON_CONNECTED),
+        verify(mPhone, atLeastOnce()).notifyDataConnection(
                 eq(PhoneConstants.APN_TYPE_DEFAULT));
 
         verify(mAlarmManager, times(1)).set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(),
@@ -580,9 +566,6 @@
     @Test
     @MediumTest
     public void testDataSetup() throws Exception {
-
-        mDct.setUserDataEnabled(true);
-
         mSimulatedCommands.setDataCallResult(true, createSetupDataCallResult());
 
         DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
@@ -593,31 +576,10 @@
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
         waitForMs(200);
 
-        ArgumentCaptor<String> apnTypeArgumentCaptor = ArgumentCaptor.forClass(String.class);
-        verify(mPhone, times(sNetworkAttributes.length)).notifyDataConnection(
-                eq(Phone.REASON_SIM_LOADED), apnTypeArgumentCaptor.capture(),
-                eq(PhoneConstants.DataState.DISCONNECTED));
-
-        assertEquals(sApnTypes, apnTypeArgumentCaptor.getAllValues());
-
         logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
         waitForMs(200);
 
-        apnTypeArgumentCaptor = ArgumentCaptor.forClass(String.class);
-        verify(mPhone, times(sNetworkAttributes.length)).notifyDataConnection(
-                eq(Phone.REASON_DATA_ATTACHED), apnTypeArgumentCaptor.capture(),
-                eq(PhoneConstants.DataState.DISCONNECTED));
-
-        assertEquals(sApnTypes, apnTypeArgumentCaptor.getAllValues());
-
-        apnTypeArgumentCaptor = ArgumentCaptor.forClass(String.class);
-        verify(mPhone, times(sNetworkAttributes.length)).notifyDataConnection(
-                eq(Phone.REASON_DATA_ENABLED), apnTypeArgumentCaptor.capture(),
-                eq(PhoneConstants.DataState.DISCONNECTED));
-
-        assertEquals(sApnTypes, apnTypeArgumentCaptor.getAllValues());
-
         logd("Sending EVENT_ENABLE_NEW_APN");
         // APN id 0 is APN_TYPE_DEFAULT
         mDct.setEnabled(ApnSetting.TYPE_DEFAULT, true);
@@ -643,21 +605,17 @@
     @Test
     @MediumTest
     public void testDataRetry() throws Exception {
-
-        mDct.setUserDataEnabled(true);
+        AsyncResult ar = new AsyncResult(null,
+                new Pair<>(true, DataEnabledSettings.REASON_USER_DATA_ENABLED), null);
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_CHANGED, ar));
+        waitForMs(200);
 
         // LOST_CONNECTION(0x10004) is a non-permanent failure, so we'll retry data setup later.
-        /*DataCallResponse dcResponse = new DataCallResponse(0x10004, -1, 1, 2, "IP", FAKE_IFNAME,
-                Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)),
-                Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)),
-                Arrays.asList(FAKE_PCSCF_ADDRESS),
-                1440);*/
         SetupDataCallResult result = createSetupDataCallResult();
         result.status = 0x10004;
 
         // Simulate RIL fails the data call setup
-        mSimulatedCommands.setDataCallResult(false, result);
+        mSimulatedCommands.setDataCallResult(true, result);
 
         DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
         boolean allowed = isDataAllowed(dataConnectionReasons);
@@ -667,37 +625,15 @@
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
         waitForMs(200);
 
-        ArgumentCaptor<String> apnTypeArgumentCaptor = ArgumentCaptor.forClass(String.class);
-        verify(mPhone, times(sNetworkAttributes.length)).notifyDataConnection(
-                eq(Phone.REASON_SIM_LOADED), apnTypeArgumentCaptor.capture(),
-                eq(PhoneConstants.DataState.DISCONNECTED));
-
-        assertEquals(sApnTypes, apnTypeArgumentCaptor.getAllValues());
-
         logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
         waitForMs(200);
 
-        apnTypeArgumentCaptor = ArgumentCaptor.forClass(String.class);
-        verify(mPhone, times(sNetworkAttributes.length)).notifyDataConnection(
-                eq(Phone.REASON_DATA_ATTACHED), apnTypeArgumentCaptor.capture(),
-                eq(PhoneConstants.DataState.DISCONNECTED));
-
-        assertEquals(sApnTypes, apnTypeArgumentCaptor.getAllValues());
-
-        apnTypeArgumentCaptor = ArgumentCaptor.forClass(String.class);
-        verify(mPhone, times(sNetworkAttributes.length)).notifyDataConnection(
-                eq(Phone.REASON_DATA_ENABLED), apnTypeArgumentCaptor.capture(),
-                eq(PhoneConstants.DataState.DISCONNECTED));
-
-        assertEquals(sApnTypes, apnTypeArgumentCaptor.getAllValues());
-
         logd("Sending EVENT_ENABLE_NEW_APN");
         // APN id 0 is APN_TYPE_DEFAULT
         mDct.setEnabled(ApnSetting.TYPE_DEFAULT, true);
         waitForMs(200);
 
-
         dataConnectionReasons = new DataConnectionReasons();
         allowed = isDataAllowed(dataConnectionReasons);
         assertTrue(dataConnectionReasons.toString(), allowed);
@@ -711,10 +647,6 @@
                 any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, LTE_BEARER_BITMASK);
 
-        // Make sure we never notify connected because the data call setup is supposed to fail.
-        verify(mPhone, never()).notifyDataConnection(eq(Phone.REASON_CONNECTED),
-                eq(PhoneConstants.APN_TYPE_DEFAULT));
-
         // Verify the retry manger schedule another data call setup.
         verify(mAlarmManager, times(1)).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
                 anyLong(), any(PendingIntent.class));
@@ -751,7 +683,6 @@
     public void testUserDisableData() throws Exception {
         //step 1: setup two DataCalls one for Metered: default, another one for Non-metered: IMS
         //set Default and MMS to be metered in the CarrierConfigManager
-        boolean dataEnabled = mDct.isUserDataEnabled();
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
         mDct.setEnabled(ApnSetting.TYPE_IMS, true);
@@ -765,10 +696,6 @@
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
         waitForMs(200);
 
-        logd("Sending DATA_ENABLED_CMD");
-        mDct.setUserDataEnabled(true);
-
-        waitForMs(200);
         ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
         verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
                 eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
@@ -778,7 +705,10 @@
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, LTE_BEARER_BITMASK);
 
         logd("Sending DATA_DISABLED_CMD");
-        mDct.setUserDataEnabled(false);
+        doReturn(false).when(mDataEnabledSettings).isDataEnabled();
+        AsyncResult ar = new AsyncResult(null,
+                new Pair<>(false, DataEnabledSettings.REASON_USER_DATA_ENABLED), null);
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_CHANGED, ar));
         waitForMs(200);
 
         // expected tear down all metered DataConnections
@@ -788,10 +718,6 @@
         assertEquals(DctConstants.State.CONNECTED, mDct.getOverallState());
         assertEquals(DctConstants.State.IDLE, mDct.getState(PhoneConstants.APN_TYPE_DEFAULT));
         assertEquals(DctConstants.State.CONNECTED, mDct.getState(PhoneConstants.APN_TYPE_IMS));
-
-        // reset the setting at the end of this test
-        mDct.setUserDataEnabled(dataEnabled);
-        waitForMs(200);
     }
 
     @Test
@@ -804,7 +730,6 @@
 
         //set Default and MMS to be metered in the CarrierConfigManager
         boolean roamingEnabled = mDct.getDataRoamingEnabled();
-        boolean dataEnabled = mDct.isUserDataEnabled();
 
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
@@ -820,10 +745,6 @@
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
         waitForMs(200);
 
-        logd("Sending DATA_ENABLED_CMD");
-        mDct.setUserDataEnabled(true);
-
-        waitForMs(300);
         ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
         verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
                 eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
@@ -849,7 +770,6 @@
 
         // reset roaming settings / data enabled settings at end of this test
         mDct.setDataRoamingEnabledByUser(roamingEnabled);
-        mDct.setUserDataEnabled(dataEnabled);
         waitForMs(200);
     }
 
@@ -861,7 +781,6 @@
         //step 3: only non-metered data call is established
 
         boolean roamingEnabled = mDct.getDataRoamingEnabled();
-        boolean dataEnabled = mDct.isUserDataEnabled();
         doReturn(true).when(mServiceState).getDataRoaming();
 
         //set Default and MMS to be metered in the CarrierConfigManager
@@ -870,9 +789,6 @@
         mDct.setEnabled(ApnSetting.TYPE_IMS, true);
         mDct.setEnabled(ApnSetting.TYPE_DEFAULT, true);
 
-        logd("Sending DATA_ENABLED_CMD");
-        mDct.setUserDataEnabled(true);
-
         logd("Sending DISABLE_ROAMING_CMD");
         mDct.setDataRoamingEnabledByUser(false);
 
@@ -899,7 +815,6 @@
 
         // reset roaming settings / data enabled settings at end of this test
         mDct.setDataRoamingEnabledByUser(roamingEnabled);
-        mDct.setUserDataEnabled(dataEnabled);
         waitForMs(200);
     }
 
@@ -912,13 +827,16 @@
         ContentResolver resolver = mContext.getContentResolver();
         Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONED, 1);
 
-        mDct.setUserDataEnabled(true);
-
         mContextFixture.putBooleanResource(
                 com.android.internal.R.bool.config_auto_attach_data_on_creation, true);
 
         mSimulatedCommands.setDataCallResult(true, createSetupDataCallResult());
 
+        AsyncResult ar = new AsyncResult(null,
+                new Pair<>(true, DataEnabledSettings.REASON_USER_DATA_ENABLED), null);
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_CHANGED, ar));
+        waitForMs(200);
+
         DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
         boolean allowed = isDataAllowed(dataConnectionReasons);
         assertFalse(dataConnectionReasons.toString(), allowed);
@@ -980,9 +898,6 @@
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
 
-        boolean dataEnabled = mDct.isUserDataEnabled();
-        mDct.setUserDataEnabled(true);
-
         mDct.setEnabled(ApnSetting.TYPE_IMS, true);
         mDct.setEnabled(ApnSetting.TYPE_DEFAULT, true);
 
@@ -1003,11 +918,10 @@
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, LTE_BEARER_BITMASK);
         assertEquals(DctConstants.State.CONNECTED, mDct.getOverallState());
 
-        Message msg = mDct.obtainMessage(DctConstants.EVENT_SET_CARRIER_DATA_ENABLED);
-        AsyncResult.forMessage(msg).result = false;
-        mDct.sendMessage(msg);
-
-        waitForMs(100);
+        AsyncResult ar = new AsyncResult(null,
+                new Pair<>(false, DataEnabledSettings.REASON_DATA_ENABLED_BY_CARRIER), null);
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_CHANGED, ar));
+        waitForMs(200);
 
         // Validate all metered data connections have been torn down
         verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall(
@@ -1015,10 +929,6 @@
                 any(Message.class));
         assertEquals(DctConstants.State.CONNECTED, mDct.getOverallState());
         assertEquals(DctConstants.State.IDLE, mDct.getState(PhoneConstants.APN_TYPE_DEFAULT));
-
-        // Reset settings at the end of test
-        mDct.setUserDataEnabled(dataEnabled);
-        waitForMs(200);
     }
 
     private void initApns(String targetApn, String[] canHandleTypes) {
@@ -1055,8 +965,6 @@
     public void testGetDataConnectionState() throws Exception {
         initApns(PhoneConstants.APN_TYPE_SUPL,
                 new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_DEFAULT});
-        mDct.setUserDataEnabled(false);
-
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT});
 
@@ -1082,7 +990,8 @@
     @SmallTest
     public void testTrySetupDataUnmeteredDataDisabled() throws Exception {
         initApns(PhoneConstants.APN_TYPE_FOTA, new String[]{PhoneConstants.APN_TYPE_ALL});
-        mDct.setUserDataEnabled(false);
+        //mDct.setUserDataEnabled(false);
+        doReturn(false).when(mDataEnabledSettings).isDataEnabled();
 
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT});
@@ -1110,7 +1019,8 @@
     @SmallTest
     public void testTrySetupMeteredDataDisabled() throws Exception {
         initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
-        mDct.setUserDataEnabled(false);
+        //mDct.setUserDataEnabled(false);
+        doReturn(false).when(mDataEnabledSettings).isDataEnabled();
 
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT});
@@ -1138,7 +1048,8 @@
         initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
         doReturn(true).when(mApnContext).hasRestrictedRequests(eq(true));
 
-        mDct.setUserDataEnabled(false);
+        //mDct.setUserDataEnabled(false);
+        doReturn(false).when(mDataEnabledSettings).isDataEnabled();
 
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT});
@@ -1166,7 +1077,6 @@
         initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
         doReturn(true).when(mApnContext).hasRestrictedRequests(eq(true));
 
-        mDct.setUserDataEnabled(true);
         mDct.setDataRoamingEnabledByUser(false);
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT});
@@ -1195,7 +1105,6 @@
     public void testTrySetupNotConnectable() throws Exception {
         initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
         doReturn(false).when(mApnContext).isConnectable();
-        mDct.setUserDataEnabled(true);
 
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT});
@@ -1223,7 +1132,6 @@
         initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
         doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN).when(mServiceState)
                 .getRilDataRadioTechnology();
-        mDct.setUserDataEnabled(true);
 
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT});
@@ -1250,7 +1158,6 @@
     public void testTrySetupDefaultInECBM() throws Exception {
         initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
         doReturn(true).when(mPhone).isInEcm();
-        mDct.setUserDataEnabled(true);
 
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT});
@@ -1281,7 +1188,6 @@
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT});
         mDct.setEnabled(ApnSetting.TYPE_DEFAULT, true);
-        mDct.setUserDataEnabled(true);
         initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
 
         logd("Sending EVENT_RECORDS_LOADED");
@@ -1402,7 +1308,6 @@
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT});
         mDct.setEnabled(ApnSetting.TYPE_DEFAULT, true);
-        mDct.setUserDataEnabled(true);
         initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
 
         logd("Sending EVENT_RECORDS_LOADED");
@@ -1447,7 +1352,7 @@
     }
 
     // Test provisioning
-    @Test
+    /*@Test
     @SmallTest
     public void testDataEnableInProvisioning() throws Exception {
         ContentResolver resolver = mContext.getContentResolver();
@@ -1481,8 +1386,9 @@
         assertTrue(mDct.isDataEnabled());
         assertTrue(mDct.isUserDataEnabled());
         assertEquals(1, Settings.Global.getInt(resolver, Settings.Global.MOBILE_DATA));
-    }
+    }*/
 
+    /*
     @Test
     @SmallTest
     public void testNotifyDataEnabledChanged() throws Exception {
@@ -1518,7 +1424,7 @@
         waitForMs(200);
         verifyDataEnabledChangedMessage(
                 true, DataEnabledSettings.REASON_PROVISIONING_DATA_ENABLED_CHANGED);
-    }
+    }*/
 
     private void verifyDataEnabledChangedMessage(boolean enabled, int reason) {
         verify(mHandler, times(1)).sendMessageDelayed(any(), anyLong());
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
index 4caa0bb..8521369 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
@@ -16,6 +16,13 @@
 
 package com.android.internal.telephony.dataconnection;
 
+import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.doAnswer;
+
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.NetworkCapabilities;
@@ -24,132 +31,134 @@
 import android.os.Binder;
 import android.os.HandlerThread;
 import android.os.Looper;
-import android.support.test.filters.FlakyTest;
 import android.telephony.Rlog;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import com.android.internal.telephony.ContextFixture;
+import androidx.test.filters.FlakyTest;
+
+import com.android.internal.telephony.PhoneSwitcher;
 import com.android.internal.telephony.RadioConfig;
+import com.android.internal.telephony.SubscriptionController;
+import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.mocks.ConnectivityServiceMock;
-import com.android.internal.telephony.mocks.DcTrackerMock;
 import com.android.internal.telephony.mocks.PhoneSwitcherMock;
 import com.android.internal.telephony.mocks.SubscriptionControllerMock;
 import com.android.internal.telephony.mocks.SubscriptionMonitorMock;
 import com.android.internal.telephony.mocks.TelephonyRegistryMock;
 
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 
-import java.lang.reflect.Field;
+import java.util.ArrayList;
 
-public class TelephonyNetworkFactoryTest extends AndroidTestCase {
+public class TelephonyNetworkFactoryTest extends TelephonyTest {
     private final static String LOG_TAG = "TelephonyNetworkFactoryTest";
 
     @Mock
-    RadioConfig mMockRadioConfig;
-
-    private void waitABit() {
-        try {
-            Thread.sleep(250);
-        } catch (Exception e) {}
-    }
+    private RadioConfig mMockRadioConfig;
 
     private String mTestName = "";
 
+    private TelephonyRegistryMock mTelephonyRegistryMock;
+    private PhoneSwitcherMock mPhoneSwitcherMock;
+    private SubscriptionControllerMock mSubscriptionControllerMock;
+    private SubscriptionMonitorMock mSubscriptionMonitorMock;
+    private HandlerThread mHandlerThread;
+    private ConnectivityServiceMock mConnectivityServiceMock;
+    private Looper mLooper;
+    private final ArrayList<NetworkRequest> mNetworkRequestList = new ArrayList<>();
+
+    private TelephonyNetworkFactory mTelephonyNetworkFactoryUT;
+
     private void log(String str) {
         Rlog.d(LOG_TAG + " " + mTestName, str);
     }
 
-    private class TestSetup {
-        final TelephonyRegistryMock telephonyRegistryMock;
-        final PhoneSwitcherMock phoneSwitcherMock;
-        final SubscriptionControllerMock subscriptionControllerMock;
-        final SubscriptionMonitorMock subscriptionMonitorMock;
-        final HandlerThread handlerThread;
-        final ConnectivityServiceMock connectivityServiceMock;
-        final Looper looper;
-        DcTrackerMock dcTrackerMock;
-        final Context contextMock;
-        private Object mLock = new Object();
-        private static final int MAX_INIT_WAIT_MS = 30000; // 30 seconds
-
-        TestSetup(int numPhones) throws Exception {
-            MockitoAnnotations.initMocks(TelephonyNetworkFactoryTest.this);
-            mockRadioConfig();
-            handlerThread = new HandlerThread("TelephonyNetworkFactoryTest") {
-                @Override
-                public void onLooperPrepared() {
-                    synchronized (mLock) {
-                        if (dcTrackerMock == null) dcTrackerMock = new DcTrackerMock();
-                        mLock.notifyAll();
-                    }
-                }
-            };
-            handlerThread.start();
-            // wait until dct created
-            synchronized (mLock) {
-                try {
-                    mLock.wait(MAX_INIT_WAIT_MS);
-                } catch (InterruptedException ie) {
-                }
-                if (dcTrackerMock == null) fail("failed to initialize dct");
-            }
-            looper = handlerThread.getLooper();
-
-            final ContextFixture contextFixture = new ContextFixture();
-            String[] networkConfigString = getContext().getResources().getStringArray(
-                    com.android.internal.R.array.networkAttributes);
-            contextFixture.putStringArrayResource(com.android.internal.R.array.networkAttributes,
-                    networkConfigString);
-            contextMock = contextFixture.getTestDouble();
-
-            connectivityServiceMock = new ConnectivityServiceMock(contextMock);
-            ConnectivityManager cm =
-                    new ConnectivityManager(contextMock, connectivityServiceMock);
-            contextFixture.setSystemService(Context.CONNECTIVITY_SERVICE, cm);
-
-            telephonyRegistryMock = new TelephonyRegistryMock();
-            phoneSwitcherMock = new PhoneSwitcherMock(numPhones, looper);
-            subscriptionControllerMock =
-                    new SubscriptionControllerMock(contextMock, telephonyRegistryMock, numPhones);
-            subscriptionMonitorMock = new SubscriptionMonitorMock(numPhones);
-        }
-
-        void die() {
-            connectivityServiceMock.die();
-            looper.quit();
-            handlerThread.quit();
-        }
-    }
-
-    private TelephonyNetworkFactory makeTnf(int phoneId, TestSetup ts) {
-        return new TelephonyNetworkFactory(ts.phoneSwitcherMock, ts.subscriptionControllerMock,
-                ts.subscriptionMonitorMock, ts.looper, ts.contextMock, phoneId, ts.dcTrackerMock);
-    }
-
-    private NetworkRequest makeSubSpecificDefaultRequest(TestSetup ts, int subId) {
+    private NetworkRequest makeSubSpecificInternetRequest(int subId) {
         NetworkCapabilities netCap = (new NetworkCapabilities()).
                 addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).
                 addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED).
                 addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
         netCap.setNetworkSpecifier(new StringNetworkSpecifier(Integer.toString(subId)));
-        return ts.connectivityServiceMock.requestNetwork(netCap, null, 0, new Binder(), -1);
+        return mConnectivityServiceMock.requestNetwork(netCap, null, 0, new Binder(), -1);
     }
-    private NetworkRequest makeSubSpecificMmsRequest(TestSetup ts, int subId) {
+    private NetworkRequest makeSubSpecificMmsRequest(int subId) {
         NetworkCapabilities netCap = (new NetworkCapabilities()).
                 addCapability(NetworkCapabilities.NET_CAPABILITY_MMS).
                 addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED).
                 addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
         netCap.setNetworkSpecifier(new StringNetworkSpecifier(Integer.toString(subId)));
-        return ts.connectivityServiceMock.requestNetwork(netCap, null, 0, new Binder(), -1);
+        return mConnectivityServiceMock.requestNetwork(netCap, null, 0, new Binder(), -1);
     }
 
+    @Before
+    public void setUp() throws Exception {
+        super.setUp(getClass().getSimpleName());
+        replaceInstance(RadioConfig.class, "sRadioConfig", null, mMockRadioConfig);
+
+        mHandlerThread = new HandlerThread("TelephonyNetworkFactoryTest");
+        mHandlerThread.start();
+        mLooper = mHandlerThread.getLooper();
+
+        mContextFixture.putStringArrayResource(com.android.internal.R.array.networkAttributes,
+                new String[]{"wifi,1,1,1,-1,true", "mobile,0,0,0,-1,true",
+                        "mobile_mms,2,0,2,60000,true", "mobile_supl,3,0,2,60000,true",
+                        "mobile_dun,4,0,2,60000,true", "mobile_hipri,5,0,3,60000,true",
+                        "mobile_fota,10,0,2,60000,true", "mobile_ims,11,0,2,60000,true",
+                        "mobile_cbs,12,0,2,60000,true", "wifi_p2p,13,1,0,-1,true",
+                        "mobile_ia,14,0,2,-1,true", "mobile_emergency,15,0,2,-1,true"});
+
+        doAnswer(invocation -> {
+            mNetworkRequestList.add((NetworkRequest) invocation.getArguments()[0]);
+            return null;
+        }).when(mDcTracker).requestNetwork(any(), any());
+
+        doAnswer(invocation -> {
+            mNetworkRequestList.remove((NetworkRequest) invocation.getArguments()[0]);
+            return null;
+        }).when(mDcTracker).releaseNetwork(any(), any(), anyBoolean());
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mConnectivityServiceMock.die();
+        mLooper.quit();
+        mHandlerThread.quit();
+        super.tearDown();
+    }
+
+    private void createMockedTelephonyComponents(int numberOfPhones) throws Exception {
+        mConnectivityServiceMock = new ConnectivityServiceMock(mContext);
+        mContextFixture.setSystemService(Context.CONNECTIVITY_SERVICE,
+                new ConnectivityManager(mContext, mConnectivityServiceMock));
+        mTelephonyRegistryMock = new TelephonyRegistryMock();
+        mPhoneSwitcherMock = new PhoneSwitcherMock(numberOfPhones, mLooper);
+        mSubscriptionControllerMock = new SubscriptionControllerMock(mContext,
+                mTelephonyRegistryMock, numberOfPhones);
+        mSubscriptionMonitorMock = new SubscriptionMonitorMock(numberOfPhones);
+        mPhoneSwitcherMock = new PhoneSwitcherMock(numberOfPhones, mLooper);
+        mSubscriptionControllerMock = new SubscriptionControllerMock(mContext,
+                mTelephonyRegistryMock, numberOfPhones);
+        mSubscriptionMonitorMock = new SubscriptionMonitorMock(numberOfPhones);
+
+        replaceInstance(SubscriptionController.class, "sInstance", null,
+                mSubscriptionControllerMock);
+        replaceInstance(PhoneSwitcher.class, "sPhoneSwitcher", null, mPhoneSwitcherMock);
+
+        mTelephonyNetworkFactoryUT = new TelephonyNetworkFactory(mSubscriptionMonitorMock, mLooper,
+                mPhone);
+
+        replaceInstance(TelephonyNetworkFactory.class, "mDcTracker",
+                mTelephonyNetworkFactoryUT, mDcTracker);
+    }
 
     /**
      * Test that phone active changes cause the DcTracker to get poked.
      */
     @FlakyTest
+    @Test
     @SmallTest
     public void testActive() throws Exception {
         mTestName = "testActive";
@@ -157,91 +166,68 @@
         final int phoneId = 0;
         final int subId = 0;
 
-        TestSetup ts = new TestSetup(numberOfPhones);
+        createMockedTelephonyComponents(numberOfPhones);
 
-        makeTnf(phoneId, ts);
-
-        ts.phoneSwitcherMock.setPreferredDataPhoneId(phoneId);
-        ts.subscriptionControllerMock.setDefaultDataSubId(subId);
-        ts.subscriptionControllerMock.setSlotSubId(phoneId, subId);
-        ts.subscriptionMonitorMock.notifySubscriptionChanged(phoneId);
+        mPhoneSwitcherMock.setPreferredDataPhoneId(phoneId);
+        mSubscriptionControllerMock.setDefaultDataSubId(subId);
+        mSubscriptionControllerMock.setSlotSubId(phoneId, subId);
+        mSubscriptionMonitorMock.notifySubscriptionChanged(phoneId);
 
         log("addDefaultRequest");
-        ts.connectivityServiceMock.addDefaultRequest();
-        waitABit();
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 0) {
-            fail("pretest of LiveRequests != 0");
-        }
+        mConnectivityServiceMock.addDefaultRequest();
+        waitForMs(250);
+        assertEquals(0, mNetworkRequestList.size());
 
         log("setPhoneActive true: phoneId = " + phoneId);
-        ts.phoneSwitcherMock.setPhoneActive(phoneId, true);
-        waitABit();
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 1) {
-            fail("post-active test of LiveRequests != 1");
-        }
+        mPhoneSwitcherMock.setPhoneActive(phoneId, true);
+        waitForMs(250);
+        assertEquals(1, mNetworkRequestList.size());
 
-        log("makeSubSpecificDefaultRequest: subId = " + subId);
-        NetworkRequest subSpecificDefault = makeSubSpecificDefaultRequest(ts, subId);
-        waitABit();
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 2) {
-            fail("post-second-request test of LiveRequests != 2");
-        }
+        log("makeSubSpecificInternetRequest: subId = " + subId);
+        NetworkRequest subSpecificDefault = makeSubSpecificInternetRequest(subId);
+        waitForMs(250);
+        assertEquals(2, mNetworkRequestList.size());
 
         log("setPhoneActive false: phoneId = " + phoneId);
-        ts.phoneSwitcherMock.setPhoneActive(phoneId, false);
-        waitABit();
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 0) {
-            fail("post-inactive test of LiveRequests != 0");
-        }
+        mPhoneSwitcherMock.setPhoneActive(phoneId, false);
+        waitForMs(250);
+        assertEquals(0, mNetworkRequestList.size());
 
-        log("makeSubSpecificDefaultRequest: subId = " + subId);
-        NetworkRequest subSpecificMms = makeSubSpecificMmsRequest(ts, subId);
-        waitABit();
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 0) {
-            fail("post-mms-add test of LiveRequests != 0");
-        }
+        log("makeSubSpecificInternetRequest: subId = " + subId);
+        NetworkRequest subSpecificMms = makeSubSpecificMmsRequest(subId);
+        waitForMs(250);
+        assertEquals(0, mNetworkRequestList.size());
 
         log("setPhoneActive true: phoneId = " + phoneId);
-        ts.phoneSwitcherMock.setPhoneActive(phoneId, true);
-        waitABit();
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 3) {
-            fail("post-active-mms-add test of LiveRequests != 3");
-        }
+        mPhoneSwitcherMock.setPhoneActive(phoneId, true);
+        waitForMs(250);
+        assertEquals(3, mNetworkRequestList.size());
 
         log("releaseNetworkRequest: subSpecificDefault = " + subSpecificDefault);
-        ts.connectivityServiceMock.releaseNetworkRequest(subSpecificDefault);
-        waitABit();
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 2) {
-            fail("post-remove-default test of LiveRequests != 2");
-        }
+        mConnectivityServiceMock.releaseNetworkRequest(subSpecificDefault);
+        waitForMs(250);
+        assertEquals(2, mNetworkRequestList.size());
 
         log("setPhoneActive false: phoneId = " + phoneId);
-        ts.phoneSwitcherMock.setPhoneActive(phoneId, false);
-        waitABit();
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 0) {
-            fail("test 8, LiveRequests != 0");
-        }
+        mPhoneSwitcherMock.setPhoneActive(phoneId, false);
+        waitForMs(250);
+        assertEquals(0, mNetworkRequestList.size());
 
         log("releaseNetworkRequest: subSpecificMms = " + subSpecificMms);
-        ts.connectivityServiceMock.releaseNetworkRequest(subSpecificMms);
-        waitABit();
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 0) {
-            fail("test 9, LiveRequests != 0");
-        }
+        mConnectivityServiceMock.releaseNetworkRequest(subSpecificMms);
+        waitForMs(250);
+        assertEquals(0, mNetworkRequestList.size());
 
         log("setPhoneActive true: phoneId = " + phoneId);
-        ts.phoneSwitcherMock.setPhoneActive(phoneId, true);
-        waitABit();
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 1) {
-            fail("test 10, LiveRequests != 1," + ts.dcTrackerMock.getNumberOfLiveRequests());
-        }
-
-        ts.die();
+        mPhoneSwitcherMock.setPhoneActive(phoneId, true);
+        waitForMs(250);
+        assertEquals(1, mNetworkRequestList.size());
     }
 
     /**
      * Test that network request changes cause the DcTracker to get poked.
      */
+    @Test
     @SmallTest
     public void testRequests() throws Exception {
         mTestName = "testActive";
@@ -252,87 +238,59 @@
         final int altSubId = 1;
         final int unusedSubId = 2;
 
-        TestSetup ts = new TestSetup(numberOfPhones);
+        createMockedTelephonyComponents(numberOfPhones);
 
-        makeTnf(phoneId, ts);
+        mPhoneSwitcherMock.setPreferredDataPhoneId(phoneId);
+        mSubscriptionControllerMock.setDefaultDataSubId(subId);
+        mSubscriptionControllerMock.setSlotSubId(phoneId, subId);
+        mSubscriptionMonitorMock.notifySubscriptionChanged(phoneId);
+        waitForMs(250);
 
-        ts.phoneSwitcherMock.setPreferredDataPhoneId(phoneId);
-        ts.subscriptionControllerMock.setDefaultDataSubId(subId);
-        ts.subscriptionControllerMock.setSlotSubId(phoneId, subId);
-        ts.subscriptionMonitorMock.notifySubscriptionChanged(phoneId);
-        waitABit();
+        assertEquals(0, mNetworkRequestList.size());
 
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 0) {
-            fail("test 1, LiveRequests != 0");
-        }
+        mPhoneSwitcherMock.setPhoneActive(phoneId, true);
+        waitForMs(250);
+        assertEquals(0, mNetworkRequestList.size());
 
-        ts.phoneSwitcherMock.setPhoneActive(phoneId, true);
-        waitABit();
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 0) {
-            fail("test 2, LiveRequests != 0");
-        }
+        mConnectivityServiceMock.addDefaultRequest();
+        waitForMs(250);
+        assertEquals(1, mNetworkRequestList.size());
 
-        ts.connectivityServiceMock.addDefaultRequest();
-        waitABit();
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 1) {
-            fail("test 3, LiveRequests != 1");
-        }
+        mSubscriptionControllerMock.setSlotSubId(altPhoneId, altSubId);
+        waitForMs(250);
+        assertEquals(1, mNetworkRequestList.size());
 
-        ts.subscriptionControllerMock.setSlotSubId(altPhoneId, altSubId);
-        waitABit();
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 1) {
-            fail("test 4, LiveRequests != 1");
-        }
+        mPhoneSwitcherMock.setPreferredDataPhoneId(altPhoneId);
+        mSubscriptionControllerMock.setDefaultDataSubId(altSubId);
+        mPhoneSwitcherMock.notifyActivePhoneChange(phoneId);
 
-        ts.phoneSwitcherMock.setPreferredDataPhoneId(altPhoneId);
-        ts.subscriptionControllerMock.setDefaultDataSubId(altSubId);
-        ts.phoneSwitcherMock.notifyActivePhoneChange(phoneId);
+        waitForMs(250);
+        assertEquals(0, mNetworkRequestList.size());
 
-        waitABit();
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 0) {
-            fail("test 5, LiveRequests != 0");
-        }
+        makeSubSpecificMmsRequest(subId);
+        waitForMs(250);
+        assertEquals(1, mNetworkRequestList.size());
 
-        makeSubSpecificMmsRequest(ts, subId);
-        waitABit();
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 1) {
-            fail("test 6,  LiveRequests != 1");
-        }
+        mSubscriptionControllerMock.setSlotSubId(phoneId, unusedSubId);
+        mSubscriptionMonitorMock.notifySubscriptionChanged(phoneId);
+        waitForMs(250);
+        assertEquals(0, mNetworkRequestList.size());
 
-        ts.subscriptionControllerMock.setSlotSubId(phoneId, unusedSubId);
-        ts.subscriptionMonitorMock.notifySubscriptionChanged(phoneId);
-        waitABit();
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 0) {
-            fail("test 7,  LiveRequests != 0");
-        }
+        makeSubSpecificInternetRequest(subId);
+        waitForMs(250);
+        assertEquals(0, mNetworkRequestList.size());
 
-        makeSubSpecificDefaultRequest(ts, subId);
-        waitABit();
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 0) {
-            fail("test 8, LiveRequests != 0");
-        }
+        mSubscriptionControllerMock.setSlotSubId(phoneId, subId);
+        mSubscriptionMonitorMock.notifySubscriptionChanged(phoneId);
+        waitForMs(250);
+        // Although specified a subId, Internet request is only handled by
+        // preferred data phone.
+        assertEquals(1, mNetworkRequestList.size());
 
-        ts.subscriptionControllerMock.setSlotSubId(phoneId, subId);
-        ts.subscriptionMonitorMock.notifySubscriptionChanged(phoneId);
-        waitABit();
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 2) {
-            fail("test 9,  LiveRequests != 2");
-        }
-
-        ts.subscriptionControllerMock.setDefaultDataSubId(subId);
-        ts.phoneSwitcherMock.setPreferredDataPhoneId(phoneId);
-        ts.phoneSwitcherMock.notifyActivePhoneChange(phoneId);
-        waitABit();
-        if (ts.dcTrackerMock.getNumberOfLiveRequests() != 3) {
-            fail("test 10, LiveRequests != 3");
-        }
-        ts.die();
-    }
-
-    private void mockRadioConfig() throws Exception {
-        Field field = RadioConfig.class.getDeclaredField("sRadioConfig");
-        field.setAccessible(true);
-
-        field.set(null, mMockRadioConfig);
+        mSubscriptionControllerMock.setDefaultDataSubId(subId);
+        mPhoneSwitcherMock.setPreferredDataPhoneId(phoneId);
+        mPhoneSwitcherMock.notifyActivePhoneChange(phoneId);
+        waitForMs(250);
+        assertEquals(3, mNetworkRequestList.size());
     }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTest.java
index 5e4cc44..2ade4ab 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTest.java
@@ -29,10 +29,12 @@
         EmergencyNumber number = new EmergencyNumber(
                 "911",
                 "us",
+                "30",
                 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
                 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING);
         assertEquals(number.getNumber(), "911");
         assertEquals(number.getCountryIso(), "us");
+        assertEquals(number.getMnc(), "30");
         assertTrue(number.isInEmergencyServiceCategories(
                 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED));
         assertTrue(number.isInEmergencyServiceCategories(
@@ -73,11 +75,13 @@
         EmergencyNumber number = new EmergencyNumber(
                 "911",
                 "us",
+                "30",
                 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD,
                 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING
                         | EmergencyNumber.EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG);
         assertEquals(number.getNumber(), "911");
         assertEquals(number.getCountryIso(), "us");
+        assertEquals(number.getMnc(), "30");
         assertFalse(number.isInEmergencyServiceCategories(
                 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED));
         assertFalse(number.isInEmergencyServiceCategories(
@@ -123,6 +127,7 @@
         EmergencyNumber number = new EmergencyNumber(
                 "110",
                 "jp",
+                "30",
                 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE
                         | EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE
                         | EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_MIEC,
@@ -131,6 +136,7 @@
                         | EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DEFAULT);
         assertEquals(number.getNumber(), "110");
         assertEquals(number.getCountryIso(), "jp");
+        assertEquals(number.getMnc(), "30");
         assertFalse(number.isInEmergencyServiceCategories(
                 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED));
         assertTrue(number.isInEmergencyServiceCategories(
@@ -186,12 +192,14 @@
         EmergencyNumber numberHighestDisplayPriority = new EmergencyNumber(
                 "911",
                 "us",
+                "30",
                 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
                 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING);
 
         EmergencyNumber numberHigherDisplayPriority = new EmergencyNumber(
                 "922",
                 "us",
+                "30",
                 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE
                         | EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE
                         | EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_MIEC,
@@ -200,6 +208,7 @@
         EmergencyNumber numberLowestDisplayPriority = new EmergencyNumber(
                 "110",
                 "us",
+                "30",
                 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE
                         | EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE
                         | EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_MIEC,
diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java
new file mode 100644
index 0000000..00e68de
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.emergency;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.AsyncResult;
+import android.os.HandlerThread;
+import android.telephony.emergency.EmergencyNumber;
+
+import com.android.internal.telephony.TelephonyTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for EmergencyNumberTracker.java
+ */
+public class EmergencyNumberTrackerTest extends TelephonyTest {
+
+    private EmergencyNumberTracker mEmergencyNumberTrackerMock;
+    private List<EmergencyNumber> mEmergencyNumberListTestSample = new ArrayList<>();
+    private static final long TIMEOUT_MS = 500;
+
+    private class EmergencyNumberTrackerTestHandler extends HandlerThread {
+        private EmergencyNumberTrackerTestHandler(String name) {
+            super(name);
+        }
+        @Override
+        public void onLooperPrepared() {
+            mEmergencyNumberTrackerMock = new EmergencyNumberTracker(mPhone, mSimulatedCommands);
+            mEmergencyNumberTrackerMock.DBG = true;
+            setReady(true);
+        }
+    }
+
+    private EmergencyNumberTrackerTestHandler mHandlerThread;
+
+    @Before
+    public void setUp() throws Exception {
+        logd("EmergencyNumberTrackerTest +Setup!");
+        super.setUp("EmergencyNumberTrackerTest");
+        initializeEmergencyNumberListTestSamples();
+        mHandlerThread = new EmergencyNumberTrackerTestHandler("EmergencyNumberTrackerTestHandler");
+        mHandlerThread.start();
+        waitUntilReady();
+        logd("EmergencyNumberTrackerTest -Setup!");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mHandlerThread.quit();
+        mHandlerThread.join();
+        super.tearDown();
+    }
+
+    private void initializeEmergencyNumberListTestSamples() {
+        EmergencyNumber emergencyNumberForTest = new EmergencyNumber("119", "jp", "30",
+                EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE,
+                EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING);
+        mEmergencyNumberListTestSample.add(emergencyNumberForTest);
+    }
+
+    private void sendEmergencyNumberListFromRadio() {
+        mEmergencyNumberTrackerMock.sendMessage(
+                mEmergencyNumberTrackerMock.obtainMessage(
+                        1 /* EVENT_UNSOL_EMERGENCY_NUMBER_LIST */,
+                        new AsyncResult(null, mEmergencyNumberListTestSample, null)));
+        waitForHandlerAction(mEmergencyNumberTrackerMock, TIMEOUT_MS);
+    }
+
+    @Test
+    public void testEmergencyNumberListFromRadio() throws Exception {
+        sendEmergencyNumberListFromRadio();
+        assertEquals(mEmergencyNumberListTestSample,
+                mEmergencyNumberTrackerMock.getRadioEmergencyNumberList());
+    }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccCardControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccCardControllerTest.java
index f5a079a..a7ba5be 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccCardControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccCardControllerTest.java
@@ -27,10 +27,11 @@
 import android.content.SharedPreferences;
 import android.preference.PreferenceManager;
 import android.provider.Settings;
-import android.support.test.runner.AndroidJUnit4;
 import android.telephony.TelephonyManager;
 import android.telephony.euicc.EuiccManager;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.telephony.uicc.UiccSlot;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccConnectorTest.java b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccConnectorTest.java
index f757388..761a4f0 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccConnectorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccConnectorTest.java
@@ -40,7 +40,8 @@
 import android.service.euicc.EuiccService;
 import android.service.euicc.IEuiccService;
 import android.service.euicc.IGetEidCallback;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.telephony.TelephonyTest;
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java
index aafe865..a8751f4 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java
@@ -49,7 +49,6 @@
 import android.service.euicc.EuiccService;
 import android.service.euicc.GetDefaultDownloadableSubscriptionListResult;
 import android.service.euicc.GetDownloadableSubscriptionMetadataResult;
-import android.support.test.runner.AndroidJUnit4;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.UiccAccessRule;
@@ -57,6 +56,8 @@
 import android.telephony.euicc.EuiccInfo;
 import android.telephony.euicc.EuiccManager;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.euicc.EuiccConnector.GetOtaStatusCommandCallback;
 import com.android.internal.telephony.euicc.EuiccConnector.OtaStatusChangedCallback;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmCellBroadcastHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmCellBroadcastHandlerTest.java
index b117eb1..756c585 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmCellBroadcastHandlerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmCellBroadcastHandlerTest.java
@@ -38,7 +38,8 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Telephony;
-import android.support.test.filters.FlakyTest;
+
+import androidx.test.filters.FlakyTest;
 
 import com.android.internal.telephony.SmsStorageMonitor;
 import com.android.internal.telephony.TelephonyTest;
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 1e29908..e950797 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
@@ -46,10 +46,11 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Telephony;
-import android.support.test.filters.FlakyTest;
-import android.support.test.filters.MediumTest;
 import android.test.mock.MockContentResolver;
 
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.MediumTest;
+
 import com.android.internal.telephony.FakeSmsContentProvider;
 import com.android.internal.telephony.InboundSmsHandler;
 import com.android.internal.telephony.InboundSmsTracker;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java
index a24bdfc..28f5297 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java
@@ -44,12 +44,13 @@
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.provider.Telephony;
-import android.support.test.filters.FlakyTest;
 import android.telephony.SmsManager;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Singleton;
 
+import androidx.test.filters.FlakyTest;
+
 import com.android.internal.telephony.ContextFixture;
 import com.android.internal.telephony.ISub;
 import com.android.internal.telephony.SMSDispatcher;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/FakeProviderWithAsserts.java b/tests/telephonytests/src/com/android/internal/telephony/ims/FakeProviderWithAsserts.java
new file mode 100644
index 0000000..c3df8d0
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/FakeProviderWithAsserts.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.ims;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.test.mock.MockContentProvider;
+
+/**
+ * Mocking/spying ContentProviders break in different ways. Use a fake instead. The
+ * RcsMessageStoreController doesn't care if RcsProvider works as expected (and doesn't have
+ * visibility into it) - so verifying whether we use the correct parameters should suffice.
+ */
+class FakeProviderWithAsserts extends MockContentProvider {
+    private Uri mExpectedUri;
+    private String[] mExpectedProjection;
+    private String mExpectedWhereClause;
+    private String[] mExpectedWhereArgs;
+    private String mExpectedSortOrder;
+    private ContentValues mExpectedContentValues;
+
+    private Cursor mQueryReturnValue;
+    private Uri mInsertReturnValue;
+
+    void setExpectedQueryParameters(Uri uri, String[] projection, String whereClause,
+            String[] whereArgs, String sortOrder) {
+        mExpectedUri = uri;
+        mExpectedProjection = projection;
+        mExpectedWhereClause = whereClause;
+        mExpectedWhereArgs = whereArgs;
+        mExpectedSortOrder = sortOrder;
+    }
+
+    void setExpectedInsertParameters(Uri uri, ContentValues contentValues) {
+        mExpectedUri = uri;
+        mExpectedContentValues = contentValues;
+    }
+
+    void setExpectedUpdateParameters(Uri uri, ContentValues contentValues, String whereClause,
+            String[] whereArgs) {
+        mExpectedUri = uri;
+        mExpectedContentValues = contentValues;
+        mExpectedWhereClause = whereClause;
+        mExpectedWhereArgs = whereArgs;
+    }
+
+    void setInsertReturnValue(Uri returnValue) {
+        mInsertReturnValue = returnValue;
+    }
+
+    void setQueryReturnValue(Cursor cursor) {
+
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String whereClause, String[] whereArgs,
+            String sortOrder) {
+        assertThat(uri).isEqualTo(mExpectedUri);
+        assertThat(projection).isEqualTo(mExpectedProjection);
+        assertThat(whereClause).isEqualTo(mExpectedWhereClause);
+        assertThat(whereArgs).isEqualTo(mExpectedWhereArgs);
+        assertThat(sortOrder).isEqualTo(mExpectedSortOrder);
+        return null;
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues contentValues) {
+        assertThat(uri).isEqualTo(mExpectedUri);
+        assertThat(contentValues).isEqualTo(mExpectedContentValues);
+        return mInsertReturnValue;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues contentValues, String whereClause,
+            String[] whereArgs) {
+        assertThat(uri).isEqualTo(mExpectedUri);
+        assertThat(contentValues).isEqualTo(mExpectedContentValues);
+        assertThat(whereClause).isEqualTo(mExpectedWhereClause);
+        assertThat(whereArgs).isEqualTo(mExpectedWhereArgs);
+        return 0;
+    }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsCallProfileTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsCallProfileTest.java
index 2ea1f28..751db91 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsCallProfileTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsCallProfileTest.java
@@ -24,11 +24,11 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.support.test.runner.AndroidJUnit4;
 import android.telecom.DisconnectCause;
+import android.telephony.ims.ImsCallProfile;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import android.telephony.ims.ImsCallProfile;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java
index 3587b8b..b7c450c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java
@@ -44,13 +44,14 @@
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.os.RemoteException;
-import android.support.test.runner.AndroidJUnit4;
 import android.telephony.CarrierConfigManager;
 import android.telephony.ims.ImsService;
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.stub.ImsFeatureConfiguration;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java
index af2f81b..00e27c2 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java
@@ -36,11 +36,12 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
-import android.support.test.filters.FlakyTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.telephony.ims.ImsService;
 import android.telephony.ims.stub.ImsFeatureConfiguration;
 
+import androidx.test.filters.FlakyTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.ims.internal.IImsServiceFeatureCallback;
 
 import org.junit.After;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsTestBase.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsTestBase.java
index e9fba8e..ad8cd47 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsTestBase.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsTestBase.java
@@ -19,7 +19,8 @@
 import android.content.Context;
 import android.os.Handler;
 import android.os.Looper;
-import android.support.test.InstrumentationRegistry;
+
+import androidx.test.InstrumentationRegistry;
 
 import org.mockito.MockitoAnnotations;
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsVideoProviderWrapperTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsVideoProviderWrapperTest.java
index 338e8a4..beeeefa 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsVideoProviderWrapperTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsVideoProviderWrapperTest.java
@@ -19,10 +19,11 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.when;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.telecom.VideoProfile;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.ims.internal.ImsVideoCallProviderWrapper;
 import com.android.ims.internal.VideoPauseTracker;
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/RcsMessageStoreControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/RcsMessageStoreControllerTest.java
new file mode 100644
index 0000000..8a23e01
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/RcsMessageStoreControllerTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.ims;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doReturn;
+
+import android.content.ContentValues;
+import android.net.Uri;
+import android.telephony.ims.RcsParticipant;
+import android.telephony.ims.RcsThreadQueryParameters;
+import android.test.mock.MockContentResolver;
+
+import com.android.internal.telephony.TelephonyTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+public class RcsMessageStoreControllerTest extends TelephonyTest {
+
+    private RcsMessageStoreController mRcsMessageStoreController;
+    private MockContentResolver mContentResolver;
+    private FakeProviderWithAsserts mFakeRcsProvider;
+    private FakeProviderWithAsserts mFakeMmsSmsProvider;
+
+    @Mock
+    RcsParticipant mMockParticipant;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp("RcsMessageStoreControllerTest");
+        MockitoAnnotations.initMocks(this);
+
+        mFakeRcsProvider = new FakeProviderWithAsserts();
+        mFakeMmsSmsProvider = new FakeProviderWithAsserts();
+        mContentResolver = (MockContentResolver) mContext.getContentResolver();
+        mContentResolver.addProvider("rcs", mFakeRcsProvider);
+        mContentResolver.addProvider("mms-sms", mFakeMmsSmsProvider);
+
+        mRcsMessageStoreController = new RcsMessageStoreController(mContentResolver, null);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    @Test
+    public void testGetRcsThreads() {
+        doReturn(123).when(mMockParticipant).getId();
+        RcsThreadQueryParameters queryParameters =
+                RcsThreadQueryParameters.builder().withParticipant(mMockParticipant).isGroupThread(
+                        true).limitResultsTo(30).sort(true).build();
+
+        mFakeRcsProvider.setExpectedQueryParameters(Uri.parse("content://rcs/thread"),
+                new String[]{"_id"}, null, null, "ASCENDING");
+        mRcsMessageStoreController.getRcsThreads(queryParameters);
+    }
+
+    @Test
+    public void testCreateRcsParticipant() {
+        // verify the first query to existing canonical addresses
+        mFakeMmsSmsProvider.setExpectedQueryParameters(
+                Uri.parse("content://mms-sms/canonical-addresses"), new String[]{"_id"},
+                "address=?", new String[]{"+5551234567"}, null);
+
+        // verify the insert on canonical addresses
+        ContentValues expectedMmsSmsValues = new ContentValues(1);
+        expectedMmsSmsValues.put("address", "+5551234567");
+        mFakeMmsSmsProvider.setInsertReturnValue(
+                Uri.parse("content://mms-sms/canonical-address/456"));
+        mFakeMmsSmsProvider.setExpectedInsertParameters(
+                Uri.parse("content://mms-sms/canonical-addresses"), expectedMmsSmsValues);
+
+        // verify the final insert on rcs participants
+        ContentValues expectedRcsValues = new ContentValues(1);
+        expectedRcsValues.put("canonical_address_id", 456);
+        mFakeRcsProvider.setInsertReturnValue(Uri.parse("content://rcs/participant/1001"));
+        mFakeRcsProvider.setExpectedInsertParameters(Uri.parse("content://rcs/participant"),
+                expectedRcsValues);
+
+        RcsParticipant participant = mRcsMessageStoreController.createRcsParticipant("+5551234567");
+
+        assertThat(participant.getId()).isEqualTo(1001);
+        assertThat(participant.getCanonicalAddress()).isEqualTo("+5551234567");
+    }
+
+    @Test
+    public void testUpdateRcsParticipantAlias() {
+        ContentValues contentValues = new ContentValues(1);
+        contentValues.put("rcs_alias", "New Alias");
+        mFakeRcsProvider.setExpectedUpdateParameters(Uri.parse("content://rcs/participant"),
+                contentValues, "_id=?", new String[]{"551"});
+
+        mRcsMessageStoreController.updateRcsParticipantAlias(551, "New Alias");
+    }
+
+    /**
+     * TODO(sahinc): fix the test once there is an implementation in place
+     */
+    @Test
+    public void testGetMessageCount() {
+        assertEquals(1018, mRcsMessageStoreController.getMessageCount(0));
+    }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsExternalCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsExternalCallTrackerTest.java
index 80be96c..e44d8b1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsExternalCallTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsExternalCallTrackerTest.java
@@ -21,10 +21,11 @@
 import static org.mockito.Mockito.verify;
 
 import android.net.Uri;
-import android.support.test.filters.FlakyTest;
-
 import android.telephony.ims.ImsCallProfile;
 import android.telephony.ims.ImsExternalCallState;
+
+import androidx.test.filters.FlakyTest;
+
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.Connection;
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java
index c602108..f0b93a9 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java
@@ -24,9 +24,10 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import android.support.test.filters.FlakyTest;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.telephony.ims.ImsStreamMediaProfile;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.FlakyTest;
 
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.TelephonyTest;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
index 5728648..e8a002c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
@@ -43,7 +43,6 @@
 import android.os.HandlerThread;
 import android.os.Message;
 import android.os.PersistableBundle;
-import android.support.test.filters.FlakyTest;
 import android.telecom.VideoProfile;
 import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
@@ -60,6 +59,8 @@
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.FlakyTest;
+
 import com.android.ims.ImsCall;
 import com.android.ims.ImsConfig;
 import com.android.ims.ImsException;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
index 97e6691..2555488 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
@@ -49,13 +49,14 @@
 import android.os.Message;
 import android.os.PersistableBundle;
 import android.os.SystemProperties;
-import android.support.test.filters.FlakyTest;
 import android.telephony.CarrierConfigManager;
 import android.telephony.ServiceState;
 import android.telephony.ims.ImsCallProfile;
 import android.telephony.ims.ImsReasonInfo;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.FlakyTest;
+
 import com.android.ims.ImsEcbmStateListener;
 import com.android.ims.ImsManager;
 import com.android.ims.ImsUtInterface;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsRttTextHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsRttTextHandlerTest.java
index 22d9f78..82a3c0c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsRttTextHandlerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsRttTextHandlerTest.java
@@ -18,9 +18,10 @@
 
 import android.os.HandlerThread;
 import android.os.ParcelFileDescriptor;
-import android.support.test.filters.FlakyTest;
 import android.telecom.Connection;
 
+import androidx.test.filters.FlakyTest;
+
 import com.android.internal.telephony.TelephonyTest;
 
 import org.junit.After;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
index ccb3acc..a77588b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
@@ -55,7 +55,6 @@
 import com.android.internal.net.VpnProfile;
 import com.android.internal.util.AsyncChannel;
 import com.android.server.connectivity.NetworkAgentInfo;
-import com.android.server.connectivity.NetworkMonitor;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -262,7 +261,7 @@
             //notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
             //mKeepaliveTracker.handleStopAllKeepalives(nai,
             //       ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
-            nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
+            // nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
             mNetworkAgentInfos.remove(msg.replyTo);
             //updateClat(null, nai.linkProperties, nai);
             //synchronized (mNetworkForNetId) {
@@ -957,12 +956,6 @@
     }
 
     @VisibleForTesting
-    public NetworkMonitor createNetworkMonitor(Context context, Handler handler,
-            NetworkAgentInfo nai, NetworkRequest defaultRequest) {
-        throw new RuntimeException("not implemented");
-    }
-
-    @VisibleForTesting
     public NetworkRequest defaultRequest = null;
     @VisibleForTesting
     public synchronized void addDefaultRequest() {
@@ -991,5 +984,8 @@
         throw new RuntimeException("not implemented");
     }
 
-
+    @Override
+    public NetworkRequest getDefaultRequest() {
+        throw new RuntimeException("not implemented");
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/DcTrackerMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/DcTrackerMock.java
deleted file mode 100644
index c02f68b..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/DcTrackerMock.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.mocks;
-
-import android.net.LinkProperties;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
-import android.os.Handler;
-import android.os.Message;
-import android.util.LocalLog;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.DctConstants;
-import com.android.internal.telephony.dataconnection.DcTracker;
-
-import java.util.ArrayList;
-
-public class DcTrackerMock extends DcTracker {
-    public DcTrackerMock() {
-    }
-    @Override
-    public void registerServiceStateTrackerEvents() {
-        throw new RuntimeException("registerServiceStateTrackerEvents not implemented");
-    }
-    @Override
-    public void unregisterServiceStateTrackerEvents() {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public void setUserDataEnabled(boolean enable) {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public long getSubId() {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public DctConstants.Activity getActivity() {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public LinkProperties getLinkProperties(String apnType) {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public NetworkCapabilities getNetworkCapabilities(String apnType) {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public String[] getActiveApnTypes() {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public String getActiveApnString(String apnType) {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public DctConstants.State getState(String apnType) {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public DctConstants.State getOverallState() {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public boolean hasMatchedTetherApnSetting() {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public boolean getAutoAttachOnCreation() {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public boolean isUserDataEnabled() {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public boolean isDataEnabled() {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public void setDataRoamingEnabledByUser(boolean enabled) {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public boolean getDataRoamingEnabled() {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public boolean isDisconnected() {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public void update() {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public void cleanUpAllConnections(String cause) {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public void updateRecords() {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public void cleanUpAllConnections(String cause, Message disconnectAllCompleteMsg) {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public void registerForAllDataDisconnected(Handler h, int what, Object obj) {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public void unregisterForAllDataDisconnected(Handler h) {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public boolean setInternalDataEnabled(boolean enable) {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public String[] getPcscfAddress(String apnType) {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public void sendStartNetStatPoll(DctConstants.Activity activity) {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
-    public void sendStopNetStatPoll(DctConstants.Activity activity) {
-        throw new RuntimeException("Not Implemented");
-    }
-
-    private final ArrayList<NetworkRequest> mRequestedNetworks = new ArrayList<NetworkRequest>();
-
-    @Override
-    public void requestNetwork(NetworkRequest networkRequest, LocalLog log) {
-        synchronized (mRequestedNetworks) {
-            mRequestedNetworks.add(networkRequest);
-        }
-    }
-
-    @Override
-    public void releaseNetwork(NetworkRequest networkRequest, LocalLog log) {
-        synchronized (mRequestedNetworks) {
-            mRequestedNetworks.remove(networkRequest);
-        }
-    }
-
-    @VisibleForTesting
-    public int getNumberOfLiveRequests() {
-        synchronized (mRequestedNetworks) {
-            return mRequestedNetworks.size();
-        }
-    }
-}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneMock.java
index 8e97481..cf9e72a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneMock.java
@@ -20,7 +20,6 @@
 import android.net.LinkProperties;
 import android.net.NetworkCapabilities;
 import android.os.AsyncResult;
-import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
 import android.os.Registrant;
@@ -1025,7 +1024,7 @@
         throw new RuntimeException("not implemented");
     }
 
-    public void registerForAllDataDisconnected(Handler h, int what, Object obj) {
+    public void registerForAllDataDisconnected(Handler h, int what) {
         throw new RuntimeException("not implemented");
     }
 
@@ -1288,14 +1287,6 @@
         throw new RuntimeException("not implemented");
     }
 
-    public boolean isDataEnabled() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public void setUserDataEnabled(boolean enable) {
-        throw new RuntimeException("not implemented");
-    }
-
     public String getDeviceId() {
         throw new RuntimeException("not implemented");
     }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneSwitcherMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneSwitcherMock.java
index d3ab208..b4293b1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneSwitcherMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneSwitcherMock.java
@@ -27,14 +27,12 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 
 public class PhoneSwitcherMock extends PhoneSwitcher {
-    private final int mNumPhones;
     private final RegistrantList mActivePhoneRegistrants;
     private final AtomicBoolean mIsActive[];
 
     public PhoneSwitcherMock(int numPhones, Looper looper) {
-        super(looper);
+        super(numPhones, looper);
 
-        mNumPhones = numPhones;
         mActivePhoneRegistrants = new RegistrantList();
         mIsActive = new AtomicBoolean[numPhones];
         for(int i = 0; i < numPhones; i++) {
@@ -48,16 +46,11 @@
     }
 
     @Override
-    public boolean shouldApplySpecifiedRequests(int phoneId) {
+    protected boolean isPhoneActive(int phoneId) {
         return mIsActive[phoneId].get();
     }
 
     @Override
-    public boolean shouldApplyUnspecifiedRequests(int phoneId) {
-        return mIsActive[phoneId].get() && phoneId == mPreferredDataPhoneId;
-    }
-
-    @Override
     public void registerForActivePhoneSwitch(Handler h, int what, Object o) {
         Registrant r = new Registrant(h, what, o);
         mActivePhoneRegistrants.add(r);
@@ -69,12 +62,6 @@
         mActivePhoneRegistrants.remove(h);
     }
 
-    private void validatePhoneId(int phoneId) {
-        if (phoneId < 0 || phoneId >= mNumPhones) {
-            throw new IllegalArgumentException("Invalid PhoneId");
-        }
-    }
-
     @VisibleForTesting
     public void setPhoneActive(int phoneId, boolean active) {
         validatePhoneId(phoneId);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
index df5552a..418b46c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
@@ -23,6 +23,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.telephony.CellInfo;
+import android.telephony.DataFailCause;
 import android.telephony.PhoneCapability;
 import android.telephony.PhysicalChannelConfig;
 import android.telephony.ServiceState;
@@ -306,26 +307,26 @@
 
     @Override
     public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
-            String reason, String apn, String apnType, LinkProperties linkProperties,
+            String apn, String apnType, LinkProperties linkProperties,
             NetworkCapabilities networkCapabilities, int networkType, boolean roaming) {
         throw new RuntimeException("Not implemented");
     }
 
     @Override
     public void notifyDataConnectionForSubscriber(int subId, int state,
-            boolean isDataConnectivityPossible, String reason, String apn, String apnType,
+            boolean isDataConnectivityPossible, String apn, String apnType,
             LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
             int networkType, boolean roaming) {
         throw new RuntimeException("Not implemented");
     }
 
     @Override
-    public void notifyDataConnectionFailed(String reason, String apnType) {
+    public void notifyDataConnectionFailed(String apnType) {
         throw new RuntimeException("Not implemented");
     }
 
     @Override
-    public void notifyDataConnectionFailedForSubscriber(int subId, String reason, String apnType) {
+    public void notifyDataConnectionFailedForSubscriber(int subId, String apnType) {
         throw new RuntimeException("Not implemented");
     }
 
@@ -361,6 +362,11 @@
     }
 
     @Override
+    public void notifyEmergencyNumberList() {
+        throw new RuntimeException("Not implemented");
+    }
+
+    @Override
     public void notifyPreciseCallState(int ringingCallState, int foregroundCallState,
             int backgroundCallState) {
         throw new RuntimeException("Not implemented");
@@ -372,8 +378,8 @@
     }
 
     @Override
-    public void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn,
-            String failCause) {
+    public void notifyPreciseDataConnectionFailed(String apnType, String apn,
+                                                  @DataFailCause.FailCause int failCause) {
         throw new RuntimeException("Not implemented");
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/rcs/RcsControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/rcs/RcsControllerTest.java
deleted file mode 100644
index d80b94b..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/rcs/RcsControllerTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.rcs;
-
-import static org.junit.Assert.assertEquals;
-
-import com.android.internal.telephony.RcsController;
-import com.android.internal.telephony.TelephonyTest;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class RcsControllerTest extends TelephonyTest {
-
-    private RcsController mRcsController;
-
-    @Before
-    public void setUp() {
-        mRcsController = new RcsController(mContext, null);
-    }
-
-    /**
-     * TODO(sahinc): fix the test once there is an implementation in place
-     */
-    @Test
-    public void testGetMessageCount() {
-        assertEquals(1018, mRcsController.getMessageCount(0));
-    }
-}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/InstallCarrierAppUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/InstallCarrierAppUtilsTest.java
index bc297a3..867d44f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/InstallCarrierAppUtilsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/InstallCarrierAppUtilsTest.java
@@ -19,7 +19,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java
index 4012e76..dfd2bba 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java
@@ -30,9 +30,11 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
 import android.telephony.TelephonyManager;
+import android.telephony.UiccCardInfo;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.TelephonyTest;
@@ -222,7 +224,7 @@
         doReturn("A1B2C3D4").when(mMockCard).getCardId();
         doReturn(IccCardStatus.CardState.CARDSTATE_PRESENT).when(mMockCard).getCardState();
 
-        // simulate card status loaded
+        // simulate card status loaded so that the UiccController sets the card ID
         IccCardStatus ics = new IccCardStatus();
         ics.setCardState(1 /* present */);
         ics.setUniversalPinState(3 /* disabled */);
@@ -246,7 +248,7 @@
         mUiccControllerUT.mUiccSlots[0] = mMockSlot;
         doReturn(true).when(mMockSlot).isEuicc();
 
-        // simulate slot status loaded
+        // simulate slot status loaded so that the UiccController sets the card ID
         IccSlotStatus iss = new IccSlotStatus();
         iss.setSlotState(1 /* active */);
         iss.eid = "ABADACB";
@@ -259,4 +261,87 @@
         // assert that the card ID was created
         assertEquals(0, mUiccControllerUT.convertToPublicCardId(iss.eid));
     }
+
+    @Test
+    public void testCardIdForDefaultEuicc() {
+        // Give UiccController a real context so it can use shared preferences
+        mUiccControllerUT.mContext = InstrumentationRegistry.getContext();
+
+        // Mock out UiccSlots
+        mUiccControllerUT.mUiccSlots[0] = mMockSlot;
+        doReturn(true).when(mMockSlot).isEuicc();
+
+        // simulate slot status loaded so that the UiccController sets the card ID
+        IccSlotStatus iss = new IccSlotStatus();
+        iss.setSlotState(1 /* active */);
+        iss.eid = "ABADACB";
+        ArrayList<IccSlotStatus> status = new ArrayList<IccSlotStatus>();
+        status.add(iss);
+        AsyncResult ar = new AsyncResult(null, status, null);
+        Message msg = Message.obtain(mUiccControllerUT, EVENT_GET_SLOT_STATUS_DONE, ar);
+        mUiccControllerUT.handleMessage(msg);
+
+        // assert that the default cardId is the slot with the lowest slot index, even if inactive
+        assertEquals(mUiccControllerUT.convertToPublicCardId(iss.eid),
+                mUiccControllerUT.getCardIdForDefaultEuicc());
+    }
+
+    @Test
+    public void testGetAllUiccCardInfos() {
+        // Give UiccController a real context so it can use shared preferences
+        mUiccControllerUT.mContext = InstrumentationRegistry.getContext();
+
+        // Mock out UiccSlots
+        mUiccControllerUT.mUiccSlots[0] = mMockSlot;
+        doReturn(true).when(mMockSlot).isEuicc();
+        doReturn(mMockCard).when(mMockSlot).getUiccCard();
+        doReturn("A1B2C3D4").when(mMockCard).getCardId();
+        doReturn("123451234567890").when(mMockCard).getIccId();
+        doReturn(IccCardStatus.CardState.CARDSTATE_PRESENT).when(mMockCard).getCardState();
+
+        // simulate card status loaded so that the UiccController sets the card ID
+        IccCardStatus ics = new IccCardStatus();
+        ics.setCardState(1 /* present */);
+        ics.setUniversalPinState(3 /* disabled */);
+        ics.atr = "abcdef0123456789abcdef";
+        ics.iccid = "123451234567890";
+        ics.eid = "A1B2C3D4";
+        AsyncResult ar = new AsyncResult(null, ics, null);
+        Message msg = Message.obtain(mUiccControllerUT, EVENT_GET_ICC_STATUS_DONE, ar);
+        mUiccControllerUT.handleMessage(msg);
+
+        // assert that the default cardId is the slot with the lowest slot index, even if inactive
+        UiccCardInfo uiccCardInfo = new UiccCardInfo(
+                true,      // isEuicc
+                0,         // cardId
+                ics.eid,   // eid
+                ics.iccid, // iccid is unknown
+                0);        // slotIndex
+        assertEquals(uiccCardInfo, mUiccControllerUT.getAllUiccCardInfos().get(0));
+    }
+
+    @Test
+    public void testGetAllUiccCardInfosNullCard() {
+        // Give UiccController a real context so it can use shared preferences
+        mUiccControllerUT.mContext = InstrumentationRegistry.getContext();
+
+        // Mock out UiccSlots
+        mUiccControllerUT.mUiccSlots[0] = mMockSlot;
+        doReturn(true).when(mMockSlot).isEuicc();
+        doReturn(null).when(mMockSlot).getUiccCard();
+
+        // simulate card status loaded so that the UiccController sets the card ID
+        IccCardStatus ics = new IccCardStatus();
+        ics.setCardState(1 /* present */);
+        ics.setUniversalPinState(3 /* disabled */);
+        ics.atr = "abcdef0123456789abcdef";
+        ics.iccid = "123451234567890";
+        ics.eid = "A1B2C3D4";
+        AsyncResult ar = new AsyncResult(null, ics, null);
+        Message msg = Message.obtain(mUiccControllerUT, EVENT_GET_ICC_STATUS_DONE, ar);
+        mUiccControllerUT.handleMessage(msg);
+
+        // assert that the getAllUiccCardInfos returns an empty list without crashing
+        assertEquals(0, mUiccControllerUT.getAllUiccCardInfos().size());
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java
index e99a4e5..1e9b643 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java
@@ -35,9 +35,10 @@
 import android.os.HandlerThread;
 import android.os.Message;
 import android.os.PersistableBundle;
-import android.support.test.filters.SmallTest;
 import android.telephony.CarrierConfigManager;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.cat.CatService;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java
index 457f021..2c55915 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java
@@ -28,7 +28,8 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.TelephonyTest;