Merge "Remove obsolete version of LinkCapacityEstimate" into sc-dev
diff --git a/src/java/com/android/internal/telephony/CarrierInfoManager.java b/src/java/com/android/internal/telephony/CarrierInfoManager.java
index c73214a..00f8c39 100644
--- a/src/java/com/android/internal/telephony/CarrierInfoManager.java
+++ b/src/java/com/android/internal/telephony/CarrierInfoManager.java
@@ -254,7 +254,13 @@
             return;
         }
         mLastAccessResetCarrierKey = now;
-        deleteCarrierInfoForImsiEncryption(context);
+        int[] subIds = context.getSystemService(SubscriptionManager.class)
+                .getSubscriptionIds(mPhoneId);
+        if (subIds == null || subIds.length < 1) {
+            Log.e(LOG_TAG, "Could not reset carrier keys, subscription for mPhoneId=" + mPhoneId);
+            return;
+        }
+        deleteCarrierInfoForImsiEncryption(context, subIds[0]);
         Intent resetIntent = new Intent(TelephonyIntents.ACTION_CARRIER_CERTIFICATE_DOWNLOAD);
         SubscriptionManager.putPhoneIdAndSubIdExtra(resetIntent, mPhoneId);
         context.sendBroadcastAsUser(resetIntent, UserHandle.ALL);
@@ -264,12 +270,12 @@
      * Deletes all the keys for a given Carrier from the device keystore.
      * @param context Context
      */
-    public static void deleteCarrierInfoForImsiEncryption(Context context) {
-        Log.i(LOG_TAG, "deleting carrier key from db");
+    public static void deleteCarrierInfoForImsiEncryption(Context context, int subId) {
+        Log.i(LOG_TAG, "deleting carrier key from db for subId=" + subId);
         String mcc = "";
         String mnc = "";
-        final TelephonyManager telephonyManager =
-                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+        final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class)
+                .createForSubscriptionId(subId);
         String simOperator = telephonyManager.getSimOperator();
         if (!TextUtils.isEmpty(simOperator)) {
             mcc = simOperator.substring(0, 3);
diff --git a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
index 005ee71..64dc7ec 100644
--- a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
@@ -39,6 +39,7 @@
 import android.telephony.TelephonyManager.NetworkTypeBitMask;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.util.ArrayUtils;
 import com.android.internal.telephony.util.NotificationChannelController;
 import com.android.telephony.Rlog;
 
@@ -272,8 +273,9 @@
             Rlog.e(LOG_TAG, "isCarrierConfigEnableNr: Cannot get config " + mPhone.getSubId());
             return false;
         }
-        return config.getInt(CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITY_INT)
-                != CarrierConfigManager.CARRIER_NR_AVAILABILITY_NONE;
+        int[] nrAvailabilities = config.getIntArray(
+                CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY);
+        return !ArrayUtils.isEmpty(nrAvailabilities);
     }
 
     private boolean checkSupportedBitmask(@NetworkTypeBitMask long supportedBitmask,
diff --git a/src/java/com/android/internal/telephony/CellBroadcastServiceManager.java b/src/java/com/android/internal/telephony/CellBroadcastServiceManager.java
index a991153..7045171 100644
--- a/src/java/com/android/internal/telephony/CellBroadcastServiceManager.java
+++ b/src/java/com/android/internal/telephony/CellBroadcastServiceManager.java
@@ -74,11 +74,27 @@
         mPhone = phone;
     }
 
+    private boolean cbMessagesDisabledByOem() {
+        if (mContext != null && mContext.getResources() != null) {
+            return mContext.getResources().getBoolean(
+                    com.android.internal.R.bool.config_disable_all_cb_messages);
+        } else {
+            return false;
+        }
+    }
+
     /**
      * Send a GSM CB message to the CellBroadcastServiceManager's handler.
      * @param m the message
      */
     public void sendGsmMessageToHandler(Message m) {
+        if (cbMessagesDisabledByOem()) {
+            Log.d(TAG, "GSM CB message ignored - CB messages disabled by OEM.");
+            CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_FILTERED,
+                    CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_FILTERED__TYPE__GSM,
+                    CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_FILTERED__FILTER__DISABLED_BY_OEM);
+            return;
+        }
         m.what = EVENT_NEW_GSM_SMS_CB;
         mModuleCellBroadcastHandler.sendMessage(m);
     }
@@ -88,6 +104,13 @@
      * @param sms the SmsMessage to forward
      */
     public void sendCdmaMessageToHandler(SmsMessage sms) {
+        if (cbMessagesDisabledByOem()) {
+            Log.d(TAG, "CDMA CB message ignored - CB messages disabled by OEM.");
+            CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_FILTERED,
+                    CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_FILTERED__TYPE__CDMA,
+                    CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_FILTERED__FILTER__DISABLED_BY_OEM);
+            return;
+        }
         Message m = Message.obtain();
         m.what = EVENT_NEW_CDMA_SMS_CB;
         m.obj = sms;
@@ -99,6 +122,13 @@
      * @param sms the SCP message
      */
     public void sendCdmaScpMessageToHandler(SmsMessage sms, RemoteCallback callback) {
+        if (cbMessagesDisabledByOem()) {
+            Log.d(TAG, "CDMA SCP CB message ignored - CB messages disabled by OEM.");
+            CellBroadcastStatsLog.write(CellBroadcastStatsLog.CB_MESSAGE_FILTERED,
+                    CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_FILTERED__TYPE__CDMA_SPC,
+                    CellBroadcastStatsLog.CELL_BROADCAST_MESSAGE_FILTERED__FILTER__DISABLED_BY_OEM);
+            return;
+        }
         Message m = Message.obtain();
         m.what = EVENT_NEW_CDMA_SCP_MESSAGE;
         m.obj = Pair.create(sms, callback);
diff --git a/src/java/com/android/internal/telephony/CellularNetworkService.java b/src/java/com/android/internal/telephony/CellularNetworkService.java
index 902ccd6..afbd381 100644
--- a/src/java/com/android/internal/telephony/CellularNetworkService.java
+++ b/src/java/com/android/internal/telephony/CellularNetworkService.java
@@ -33,9 +33,11 @@
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.NetworkService;
 import android.telephony.NetworkServiceCallback;
+import android.telephony.NrVopsSupportInfo;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.VopsSupportInfo;
 import android.text.TextUtils;
 
 import com.android.telephony.Rlog;
@@ -476,9 +478,7 @@
             boolean isEndcAvailable = false;
             boolean isNrAvailable = false;
             boolean isDcNrRestricted = false;
-            LteVopsSupportInfo vopsInfo = new LteVopsSupportInfo(
-                    LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE,
-                    LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE);
+            VopsSupportInfo vopsInfo = null;
 
             android.hardware.radio.V1_6.RegStateResult.AccessTechnologySpecificInfo info =
                     regResult.accessTechnologySpecificInfo;
@@ -498,6 +498,13 @@
                             info.eutranInfo().lteVopsInfo.isVopsSupported,
                             info.eutranInfo().lteVopsInfo.isEmcBearerSupported);
                     break;
+                case AccessTechnologySpecificInfo.hidl_discriminator.ngranInfo:
+                    android.hardware.radio.V1_6.RegStateResult
+                            .AccessTechnologySpecificInfo.NgranRegistrationInfo ngranInfo =
+                                    regResult.accessTechnologySpecificInfo.ngranInfo();
+                    vopsInfo = new NrVopsSupportInfo(ngranInfo.nrVopsInfo.vopsSupported,
+                            ngranInfo.nrVopsInfo.emcSupported, ngranInfo.nrVopsInfo.emfSupported);
+                    break;
                 case AccessTechnologySpecificInfo.hidl_discriminator.geranInfo:
                     android.hardware.radio.V1_6.RegStateResult
                             .AccessTechnologySpecificInfo.GeranRegistrationInfo geranInfo =
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index 7c192ec..6ae0b1f 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -2649,4 +2649,12 @@
      */
     default void setDataThrottling(Message result, WorkSource workSource,
             int dataThrottlingAction, long completionWindowMillis) {};
+
+    /**
+     * Request to get the current slicing configuration including URSP rules and
+     * NSSAIs (configured, allowed and rejected).
+     *
+     * @param result Message that will be sent back to handler.
+     */
+    default void getSlicingConfig(Message result) {};
 }
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index ae12749..494ca06 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -1889,7 +1889,7 @@
 
     @Override
     public void deleteCarrierInfoForImsiEncryption() {
-        CarrierInfoManager.deleteCarrierInfoForImsiEncryption(mContext);
+        CarrierInfoManager.deleteCarrierInfoForImsiEncryption(mContext, getSubId());
     }
 
     @Override
@@ -4622,10 +4622,9 @@
             loge("didn't get the carrier_nr_availability_int from the carrier config.");
             return;
         }
-        mIsCarrierNrSupported = config.getInt(
-                CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITY_INT,
-                CarrierConfigManager.CARRIER_NR_AVAILABILITY_NSA)
-                != CarrierConfigManager.CARRIER_NR_AVAILABILITY_NONE;
+        int[] nrAvailabilities = config.getIntArray(
+                CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY);
+        mIsCarrierNrSupported = !ArrayUtils.isEmpty(nrAvailabilities);
     }
 
     private void updateCdmaRoamingSettingsAfterCarrierConfigChanged(PersistableBundle config) {
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index a12fec5..9d7444d 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -2698,6 +2698,18 @@
         mCi.nvResetConfig(2 /* erase NV */, response);
     }
 
+    /**
+     * Erase data saved in the SharedPreference. Used for network reset
+     *
+     */
+    public boolean eraseDataInSharedPreferences() {
+        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
+        SharedPreferences.Editor editor = sp.edit();
+        Rlog.d(LOG_TAG, "Erase all data saved in SharedPreferences");
+        editor.clear();
+        return editor.commit();
+    }
+
     public void setSystemSelectionChannels(List<RadioAccessSpecifier> specifiers,
             Message response) {
         mCi.setSystemSelectionChannels(specifiers, response);
@@ -4763,6 +4775,14 @@
         return mLinkBandwidthEstimator;
     }
 
+    /**
+     * Request to get the current slicing configuration including URSP rules and
+     * NSSAIs (configured, allowed and rejected).
+     */
+    public void getSlicingConfig(Message response) {
+        mCi.getSlicingConfig(response);
+    }
+
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("Phone: subId=" + getSubId());
         pw.println(" mPhoneId=" + mPhoneId);
diff --git a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
index 82cf5fe..d92f96d 100644
--- a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
+++ b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
@@ -312,7 +312,7 @@
     }
 
     public int getNumberOfModemsWithSimultaneousDataConnections() {
-        return mStaticCapability.getMaxActiveInternetData();
+        return mStaticCapability.getMaxActiveDataSubscriptions();
     }
 
     private void notifyCapabilityChanged() {
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 9d02918..53f876c 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -1595,7 +1595,18 @@
             if (RILJ_LOGD) {
                 riljLog("getVoiceRegistrationState: overrideHalVersion=" + overrideHalVersion);
             }
+
             if ((overrideHalVersion == null
+                        || overrideHalVersion.greaterOrEqual(RADIO_HAL_VERSION_1_6))
+                    && mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_6)) {
+                final android.hardware.radio.V1_6.IRadio radioProxy16 =
+                        (android.hardware.radio.V1_6.IRadio) radioProxy;
+                try {
+                    radioProxy16.getVoiceRegistrationState_1_6(rr.mSerial);
+                } catch (RemoteException | RuntimeException e) {
+                    handleRadioProxyExceptionForRR(rr, "getVoiceRegistrationState_1_6", e);
+                }
+            } else if ((overrideHalVersion == null
                         || overrideHalVersion.greaterOrEqual(RADIO_HAL_VERSION_1_5))
                     && mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_5)) {
                 final android.hardware.radio.V1_5.IRadio radioProxy15 =
@@ -1628,7 +1639,18 @@
             if (RILJ_LOGD) {
                 riljLog("getDataRegistrationState: overrideHalVersion=" + overrideHalVersion);
             }
+
             if ((overrideHalVersion == null
+                        || overrideHalVersion.greaterOrEqual(RADIO_HAL_VERSION_1_6))
+                    && mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_6)) {
+                final android.hardware.radio.V1_6.IRadio radioProxy16 =
+                        (android.hardware.radio.V1_6.IRadio) radioProxy;
+                try {
+                    radioProxy16.getDataRegistrationState_1_6(rr.mSerial);
+                } catch (RemoteException | RuntimeException e) {
+                    handleRadioProxyExceptionForRR(rr, "getDataRegistrationState_1_6", e);
+                }
+            } else if ((overrideHalVersion == null
                         || overrideHalVersion.greaterOrEqual(RADIO_HAL_VERSION_1_5))
                     && mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_5)) {
                 final android.hardware.radio.V1_5.IRadio radioProxy15 =
@@ -1935,8 +1957,8 @@
                 new android.hardware.radio.V1_6.TrafficDescriptor();
 
         OptionalDnn optionalDnn = new OptionalDnn();
-        if (trafficDescriptor.getDnn() != null) {
-            optionalDnn.value(trafficDescriptor.getDnn());
+        if (trafficDescriptor.getDataNetworkName() != null) {
+            optionalDnn.value(trafficDescriptor.getDataNetworkName());
         }
         td.dnn = optionalDnn;
 
@@ -5955,6 +5977,32 @@
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void getSlicingConfig(Message result) {
+        android.hardware.radio.V1_6.IRadio radioProxy16 = getRadioV16(result);
+
+        if (radioProxy16 != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_GET_SLICING_CONFIG, result,
+                    mRILDefaultWorkSource);
+
+            if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+            try {
+                radioProxy16.getSlicingConfig(rr.mSerial);
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "getSlicingConfig", e);
+            }
+        } else {
+            if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "getSlicingConfig: REQUEST_NOT_SUPPORTED");
+            AsyncResult.forMessage(result, null,
+                    CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+            result.sendToTarget();
+        }
+    }
+
     //***** Private Methods
     /** Helper that gets V1.6 of the radio interface OR sends back REQUEST_NOT_SUPPORTED */
     @Nullable private android.hardware.radio.V1_6.IRadio getRadioV16(Message msg) {
@@ -6932,6 +6980,8 @@
                 return "RIL_REQUEST_SET_ALLOWED_NETWORK_TYPE_BITMAP";
             case RIL_REQUEST_GET_ALLOWED_NETWORK_TYPES_BITMAP:
                 return "RIL_REQUEST_GET_ALLOWED_NETWORK_TYPE_BITMAP";
+            case RIL_REQUEST_GET_SLICING_CONFIG:
+                return "RIL_REQUEST_GET_SLICING_CONFIG";
             default: return "<unknown request>";
         }
     }
@@ -7659,7 +7709,14 @@
                 ? null : td.dnn.value();
         String osAppId = td.osAppId.getDiscriminator() == OptionalOsAppId.hidl_discriminator.noinit
                 ? null : new String(arrayListToPrimitiveArray(td.osAppId.value().osAppId));
-        return new TrafficDescriptor(dnn, osAppId);
+        TrafficDescriptor.Builder builder = new TrafficDescriptor.Builder();
+        if (dnn != null) {
+            builder.setDataNetworkName(dnn);
+        }
+        if (osAppId != null) {
+            builder.setOsAppId(osAppId);
+        }
+        return builder.build();
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/RadioConfig.java b/src/java/com/android/internal/telephony/RadioConfig.java
index 4cb61dc..32b24fe 100644
--- a/src/java/com/android/internal/telephony/RadioConfig.java
+++ b/src/java/com/android/internal/telephony/RadioConfig.java
@@ -16,7 +16,6 @@
 
 package com.android.internal.telephony;
 
-import static android.telephony.PhoneCapability.DEVICE_NR_CAPABILITY_NONE;
 import static android.telephony.PhoneCapability.DEVICE_NR_CAPABILITY_NSA;
 import static android.telephony.PhoneCapability.DEVICE_NR_CAPABILITY_SA;
 
@@ -34,7 +33,6 @@
 import android.hardware.radio.V1_0.RadioResponseType;
 import android.hardware.radio.config.V1_0.IRadioConfig;
 import android.hardware.radio.config.V1_1.ModemsConfig;
-import android.net.ConnectivityManager;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.HwBinder;
@@ -42,6 +40,7 @@
 import android.os.Registrant;
 import android.os.RemoteException;
 import android.os.WorkSource;
+import android.telephony.TelephonyManager;
 import android.util.SparseArray;
 
 import com.android.internal.telephony.uicc.IccSlotStatus;
@@ -49,6 +48,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.concurrent.atomic.AtomicLong;
 
@@ -81,7 +81,7 @@
     private final SparseArray<RILRequest> mRequestList = new SparseArray<RILRequest>();
     /* default work source which will blame phone process */
     private final WorkSource mDefaultWorkSource;
-    private final int mDeviceNrCapability;
+    private final int[] mDeviceNrCapabilities;
     private static RadioConfig sRadioConfig;
     private static final Object sLock = new Object();
 
@@ -96,10 +96,16 @@
         }
     }
 
+    private boolean isMobileDataCapable(Context context) {
+        final TelephonyManager tm = context.getSystemService(TelephonyManager.class);
+        if (tm == null) {
+            return false;
+        }
+        return tm.isDataCapable();
+    }
+
     private RadioConfig(Context context, HalVersion radioHalVersion) {
-        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(
-                Context.CONNECTIVITY_SERVICE);
-        mIsMobileNetworkSupported = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+        mIsMobileNetworkSupported = isMobileDataCapable(context);
 
         mRadioConfigResponse = new RadioConfigResponse(this, radioHalVersion);
         mRadioConfigIndication = new RadioConfigIndication(this);
@@ -112,9 +118,19 @@
                 com.android.internal.R.bool.config_telephony5gStandalone);
         boolean is5gNonStandalone = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_telephony5gNonStandalone);
-        mDeviceNrCapability =
-                (is5gStandalone ? DEVICE_NR_CAPABILITY_SA : DEVICE_NR_CAPABILITY_NONE) | (
-                        is5gNonStandalone ? DEVICE_NR_CAPABILITY_NSA : DEVICE_NR_CAPABILITY_NONE);
+
+        if (!is5gStandalone && !is5gNonStandalone) {
+            mDeviceNrCapabilities = new int[0];
+        } else {
+            List<Integer> list = new ArrayList<>();
+            if (is5gNonStandalone) {
+                list.add(DEVICE_NR_CAPABILITY_NSA);
+            }
+            if (is5gStandalone) {
+                list.add(DEVICE_NR_CAPABILITY_SA);
+            }
+            mDeviceNrCapabilities = list.stream().mapToInt(Integer::valueOf).toArray();
+        }
     }
 
     /**
@@ -573,8 +589,8 @@
     /**
      * Returns the device's nr capability.
      */
-    public int getDeviceNrCapability() {
-        return mDeviceNrCapability;
+    public int[] getDeviceNrCapabilities() {
+        return mDeviceNrCapabilities;
     }
 
     static ArrayList<IccSlotStatus> convertHalSlotStatus(
diff --git a/src/java/com/android/internal/telephony/RadioConfigResponse.java b/src/java/com/android/internal/telephony/RadioConfigResponse.java
index a640cb7..88e5e80 100644
--- a/src/java/com/android/internal/telephony/RadioConfigResponse.java
+++ b/src/java/com/android/internal/telephony/RadioConfigResponse.java
@@ -20,6 +20,8 @@
 import static android.telephony.TelephonyManager
         .CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE;
 import static android.telephony.TelephonyManager.CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE;
+import static android.telephony.TelephonyManager.CAPABILITY_SLICING_CONFIG_SUPPORTED;
+import static android.telephony.TelephonyManager.CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING;
 import static android.telephony.TelephonyManager.RadioInterfaceCapability;
 
 import android.hardware.radio.V1_0.RadioError;
@@ -141,7 +143,7 @@
         }
 
         return new PhoneCapability(maxActiveVoiceCalls, maxActiveData, logicalModemList,
-                validationBeforeSwitchSupported, mRadioConfig.getDeviceNrCapability());
+                validationBeforeSwitchSupported, mRadioConfig.getDeviceNrCapabilities());
     }
     /**
      * Response function for IRadioConfig.getPhoneCapability().
@@ -306,6 +308,10 @@
                 Rlog.d(TAG, "CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE");
                 caps.add(CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE);
                 Rlog.d(TAG, "CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE");
+                caps.add(CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING);
+                Rlog.d(TAG, "CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING");
+                caps.add(CAPABILITY_SLICING_CONFIG_SUPPORTED);
+                Rlog.d(TAG, "CAPABILITY_SLICING_CONFIG_SUPPORTED");
             }
         }
         return caps;
diff --git a/src/java/com/android/internal/telephony/RadioIndication.java b/src/java/com/android/internal/telephony/RadioIndication.java
index e3e188c..16d2fe0 100644
--- a/src/java/com/android/internal/telephony/RadioIndication.java
+++ b/src/java/com/android/internal/telephony/RadioIndication.java
@@ -87,6 +87,7 @@
 import android.hardware.radio.V1_2.CellConnectionStatus;
 import android.hardware.radio.V1_6.IRadioIndication;
 import android.hardware.radio.V1_6.PhysicalChannelConfig.Band;
+import android.hardware.radio.V1_6.PhonebookRecordInfo;
 import android.os.AsyncResult;
 import android.os.RemoteException;
 import android.sysprop.TelephonyProperties;
@@ -1072,6 +1073,26 @@
     }
 
     /**
+     * Indicates when the phonebook is changed.
+     *
+     * @param indicationType RadioIndicationType
+     */
+    public void simPhonebookChanged(int indicationType) {
+
+    }
+
+    /**
+     * Indicates the content of all the used records in the SIM phonebook.
+     *
+     * @param indicationType RadioIndicationType
+     * @param records Content of the SIM phonebook records
+     */
+    public void simPhonebookRecordsReceived(int indicationType, int status,
+            ArrayList<PhonebookRecordInfo> records) {
+
+    }
+
+    /**
      * Indicate that a registration failure has occurred.
      *
      * @param cellIdentity a CellIdentity the CellIdentity of the Cell
diff --git a/src/java/com/android/internal/telephony/RadioResponse.java b/src/java/com/android/internal/telephony/RadioResponse.java
index f86b787..313ef0b 100644
--- a/src/java/com/android/internal/telephony/RadioResponse.java
+++ b/src/java/com/android/internal/telephony/RadioResponse.java
@@ -56,6 +56,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.data.DataCallResponse;
+import android.telephony.data.SlicingConfig;
 import android.text.TextUtils;
 
 import com.android.internal.telephony.dataconnection.KeepaliveStatus;
@@ -1998,6 +1999,31 @@
         return iccCardStatus;
     }
 
+    /**
+     * @param info Response info struct containing response type, serial no. and error.
+     */
+    public void getSimPhonebookRecordsResponse(
+            android.hardware.radio.V1_6.RadioResponseInfo responseInfo) {
+    }
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error.
+     * @param pbCapacity Contains the adn, email, anr capacities in the sim card.
+     */
+    public void getSimPhonebookCapacityResponse(
+            android.hardware.radio.V1_6.RadioResponseInfo responseInfo,
+            android.hardware.radio.V1_6.PhonebookCapacity pbCapacity) {
+    }
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error.
+     * @param updatedRecordIndex The index of the updated record.
+     */
+    public void updateSimPhonebookRecordsResponse(
+            android.hardware.radio.V1_6.RadioResponseInfo responseInfo,
+            int updatedRecordIndex) {
+    }
+
     private void responseIccCardStatus(RadioResponseInfo responseInfo, CardStatus cardStatus) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
@@ -3077,10 +3103,11 @@
         RILRequest rr = mRil.processResponse_1_6(info);
 
         if (rr != null) {
+            SlicingConfig ret = new SlicingConfig(slicingConfig);
             if (info.error == RadioError.NONE) {
-                sendMessageResponse(rr.mResult, slicingConfig);
+                sendMessageResponse(rr.mResult, ret);
             }
-            mRil.processResponseDone_1_6(rr, info, slicingConfig);
+            mRil.processResponseDone_1_6(rr, info, ret);
         }
     }
 }
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index 9ba46cf..5807b54 100755
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -431,7 +431,6 @@
             Context context = mPhone.getContext();
 
             mPhone.notifyPhoneStateChanged();
-            mPhone.notifyCallForwardingIndicator();
 
             if (!SubscriptionManager.isValidSubscriptionId(mPrevSubId)) {
                 // just went from invalid to valid subId, so notify with current service
@@ -5073,6 +5072,7 @@
         updateReportingCriteria(config);
         updateOperatorNamePattern(config);
         mCdnr.updateEfFromCarrierConfig(config);
+        mPhone.notifyCallForwardingIndicator();
 
         // Sometimes the network registration information comes before carrier config is ready.
         // For some cases like roaming/non-roaming overriding, we need carrier config. So it's
diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java
index 781d4d1..1044169 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -1352,8 +1352,6 @@
                         setDisplayName = true;
                         Uri uri = insertEmptySubInfoRecord(uniqueId, slotIndex);
                         if (DBG) logdl("[addSubInfoRecord] New record created: " + uri);
-                        SubscriptionManager subManager = SubscriptionManager.from(mContext);
-                        subManager.restoreSimSpecificSettingsForIccIdFromBackup(uniqueId);
                     } else { // there are matching records in the database for the given ICC_ID
                         int subId = cursor.getInt(0);
                         int oldSimInfoId = cursor.getInt(1);
@@ -2139,6 +2137,45 @@
         }
     }
 
+    /**
+     * Set contacts that allow device to device status sharing.
+     * @param contacts contacts to set
+     * @param subscriptionId
+     * @return the number of records updated
+     */
+    @Override
+    public int setDeviceToDeviceStatusSharingContacts(String contacts, int subscriptionId) {
+        if (DBG) {
+            logd("[setDeviceToDeviceStatusSharingContacts]- contacts:" + contacts
+                    + " subId:" + subscriptionId);
+        }
+
+        enforceModifyPhoneState("setDeviceToDeviceStatusSharingContacts");
+
+        // Now that all security checks passes, perform the operation as ourselves.
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            validateSubId(subscriptionId);
+            ContentValues value = new ContentValues(1);
+            value.put(SubscriptionManager.D2D_STATUS_SHARING_SELECTED_CONTACTS, contacts);
+            if (DBG) {
+                logd("[setDeviceToDeviceStatusSharingContacts]- contacts:" + contacts
+                        + " set");
+            }
+
+            int result = updateDatabase(value, subscriptionId, true);
+
+            // Refresh the Cache of Active Subscription Info List
+            refreshCachedActiveSubscriptionInfoList();
+
+            notifySubscriptionInfoChanged();
+
+            return result;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     public void syncGroupedSetting(int refSubId) {
         logd("syncGroupedSetting");
         try (Cursor cursor = mContext.getContentResolver().query(
@@ -3157,6 +3194,7 @@
                         case SubscriptionManager.ALLOWED_NETWORK_TYPES:
                         case SubscriptionManager.VOIMS_OPT_IN_STATUS:
                         case SubscriptionManager.D2D_STATUS_SHARING:
+                        case SubscriptionManager.D2D_STATUS_SHARING_SELECTED_CONTACTS:
                             resultValue = cursor.getString(0);
                             break;
                         default:
diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
index 717e674..9132e5e 100644
--- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
+++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
@@ -457,8 +457,10 @@
             // At this phase, the subscription list is accessible. Treating NOT_READY
             // as equivalent to ABSENT, once the rest of the system can handle it.
             sIccId[phoneId] = ICCID_STRING_FOR_NO_SIM;
-            updateSubscriptionInfoByIccId(phoneId, false /* updateEmbeddedSubs */);
+        } else {
+            sIccId[phoneId] = null;
         }
+        updateSubscriptionInfoByIccId(phoneId, false /* updateEmbeddedSubs */);
 
         broadcastSimStateChanged(phoneId, IccCardConstants.INTENT_VALUE_ICC_NOT_READY,
                 null);
@@ -579,15 +581,26 @@
          *  2. ACTION_SIM_STATE_CHANGED/ACTION_SIM_CARD_STATE_CHANGED
          *  /ACTION_SIM_APPLICATION_STATE_CHANGED
          *  3. ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED
-         *  4. ACTION_CARRIER_CONFIG_CHANGED
+         *  4. restore sim-specific settings
+         *  5. ACTION_CARRIER_CONFIG_CHANGED
          */
         broadcastSimStateChanged(phoneId, IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
         broadcastSimCardStateChanged(phoneId, TelephonyManager.SIM_STATE_PRESENT);
         broadcastSimApplicationStateChanged(phoneId, TelephonyManager.SIM_STATE_LOADED);
         updateSubscriptionCarrierId(phoneId, IccCardConstants.INTENT_VALUE_ICC_LOADED);
+        /* Sim-specific settings restore depends on knowing both the mccmnc and the carrierId of the
+        sim which is why it must be done after #updateSubscriptionCarrierId(). It is done before
+        carrier config update to avoid any race conditions with user settings that depend on
+        carrier config*/
+        restoreSimSpecificSettingsForPhone(phoneId);
         updateCarrierServices(phoneId, IccCardConstants.INTENT_VALUE_ICC_LOADED);
     }
 
+    private void restoreSimSpecificSettingsForPhone(int phoneId) {
+        SubscriptionManager subManager = SubscriptionManager.from(sContext);
+        subManager.restoreSimSpecificSettingsForIccIdFromBackup(sIccId[phoneId]);
+    }
+
     private void updateCarrierServices(int phoneId, String simState) {
         CarrierConfigManager configManager =
                 (CarrierConfigManager) sContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
@@ -707,7 +720,7 @@
         mSubscriptionController.clearSubInfoRecord(phoneId);
 
         // If SIM is not absent, insert new record or update existing record.
-        if (!ICCID_STRING_FOR_NO_SIM.equals(sIccId[phoneId])) {
+        if (!ICCID_STRING_FOR_NO_SIM.equals(sIccId[phoneId]) && sIccId[phoneId] != null) {
             logd("updateSubscriptionInfoByIccId: adding subscription info record: iccid: "
                     + sIccId[phoneId] + ", phoneId:" + phoneId);
             mSubscriptionManager.addSubscriptionInfoRecord(sIccId[phoneId], phoneId);
diff --git a/src/java/com/android/internal/telephony/d2d/MessageTypeAndValueHelper.java b/src/java/com/android/internal/telephony/d2d/MessageTypeAndValueHelper.java
new file mode 100644
index 0000000..2d36051
--- /dev/null
+++ b/src/java/com/android/internal/telephony/d2d/MessageTypeAndValueHelper.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2021 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.d2d;
+
+import android.telecom.Connection;
+import android.telecom.DiagnosticCall;
+import android.telephony.TelephonyManager;
+
+import com.android.internal.telephony.BiMap;
+
+/**
+ * Helper class to map between the message types and values used in {@link Communicator} and those
+ * defined in the public API in {@link DiagnosticCall}.
+ */
+public class MessageTypeAndValueHelper {
+    // Maps between the local message and value types defined here and those defined in the
+    // DiagnosticCall class as part of the actual API.
+
+    /**
+     * Convert between the local message type (e.g.
+     * {@link Communicator#MESSAGE_CALL_RADIO_ACCESS_TYPE})
+     * and
+     * the ones referred to in {@link DiagnosticCall}.
+     */
+    public static final BiMap<Integer, Integer> MSG_TYPE_TO_DC_MSG_TYPE = new BiMap<>();
+
+    /**
+     * Convert between the local RAT type (e.g. {@link Communicator#RADIO_ACCESS_TYPE_IWLAN}) and
+     * the ones
+     * referred to by {@link DiagnosticCall#MESSAGE_CALL_NETWORK_TYPE}.
+     */
+    public static final BiMap<Integer, Integer> RAT_TYPE_TO_DC_NETWORK_TYPE = new BiMap<>();
+
+    /**
+     * Convert between the local codec (e.g. {@link Communicator#AUDIO_CODEC_AMR_WB}) and the ones
+     * referred to by {@link DiagnosticCall#MESSAGE_CALL_AUDIO_CODEC}.
+     */
+    public static final BiMap<Integer, Integer> CODEC_TO_DC_CODEC = new BiMap<>();
+
+    /**
+     * Convert between the local battery state (e.g. {@link Communicator#BATTERY_STATE_GOOD}) and
+     * the ones referred to by {@link DiagnosticCall#MESSAGE_DEVICE_BATTERY_STATE}.
+     */
+    public static final BiMap<Integer, Integer> BATTERY_STATE_TO_DC_BATTERY_STATE = new BiMap();
+
+    /**
+     * Convert between the local battery state (e.g. {@link Communicator#COVERAGE_GOOD}) and the
+     * ones referred to by {@link DiagnosticCall#MESSAGE_DEVICE_NETWORK_COVERAGE}.
+     */
+    public static final BiMap<Integer, Integer> COVERAGE_TO_DC_COVERAGE = new BiMap();
+
+    static {
+        MSG_TYPE_TO_DC_MSG_TYPE.put(Communicator.MESSAGE_CALL_RADIO_ACCESS_TYPE,
+                DiagnosticCall.MESSAGE_CALL_NETWORK_TYPE);
+        MSG_TYPE_TO_DC_MSG_TYPE.put(Communicator.MESSAGE_CALL_AUDIO_CODEC,
+                DiagnosticCall.MESSAGE_CALL_AUDIO_CODEC);
+        MSG_TYPE_TO_DC_MSG_TYPE.put(Communicator.MESSAGE_DEVICE_BATTERY_STATE,
+                DiagnosticCall.MESSAGE_DEVICE_BATTERY_STATE);
+        MSG_TYPE_TO_DC_MSG_TYPE.put(Communicator.MESSAGE_DEVICE_NETWORK_COVERAGE,
+                DiagnosticCall.MESSAGE_DEVICE_NETWORK_COVERAGE);
+
+        RAT_TYPE_TO_DC_NETWORK_TYPE.put(Communicator.RADIO_ACCESS_TYPE_LTE,
+                TelephonyManager.NETWORK_TYPE_LTE);
+        RAT_TYPE_TO_DC_NETWORK_TYPE.put(Communicator.RADIO_ACCESS_TYPE_IWLAN,
+                TelephonyManager.NETWORK_TYPE_IWLAN);
+        RAT_TYPE_TO_DC_NETWORK_TYPE.put(Communicator.RADIO_ACCESS_TYPE_NR,
+                TelephonyManager.NETWORK_TYPE_NR);
+
+        CODEC_TO_DC_CODEC.put(Communicator.AUDIO_CODEC_EVS, Connection.AUDIO_CODEC_EVS_WB);
+        CODEC_TO_DC_CODEC.put(Communicator.AUDIO_CODEC_AMR_WB, Connection.AUDIO_CODEC_AMR_WB);
+        CODEC_TO_DC_CODEC.put(Communicator.AUDIO_CODEC_AMR_NB, Connection.AUDIO_CODEC_AMR);
+
+        BATTERY_STATE_TO_DC_BATTERY_STATE.put(Communicator.BATTERY_STATE_LOW,
+                DiagnosticCall.BATTERY_STATE_LOW);
+        BATTERY_STATE_TO_DC_BATTERY_STATE.put(Communicator.BATTERY_STATE_GOOD,
+                DiagnosticCall.BATTERY_STATE_GOOD);
+        BATTERY_STATE_TO_DC_BATTERY_STATE.put(Communicator.BATTERY_STATE_CHARGING,
+                DiagnosticCall.BATTERY_STATE_CHARGING);
+
+        COVERAGE_TO_DC_COVERAGE.put(Communicator.COVERAGE_POOR, DiagnosticCall.COVERAGE_POOR);
+        COVERAGE_TO_DC_COVERAGE.put(Communicator.COVERAGE_GOOD, DiagnosticCall.COVERAGE_GOOD);
+    }
+}
diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
index f0e9f12..eeb4bd3 100644
--- a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
+++ b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
@@ -450,12 +450,10 @@
         synchronized (mRefCountLock) {
             for (NetworkRequest nr : mNetworkRequests) {
                 if (excludeDun &&
-                        nr.networkCapabilities.hasCapability(
-                        NetworkCapabilities.NET_CAPABILITY_DUN)) {
+                        nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) {
                     continue;
                 }
-                if (!nr.networkCapabilities.hasCapability(
-                        NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)) {
+                if (!nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)) {
                     return true;
                 }
             }
@@ -534,10 +532,9 @@
     }
 
     static @ApnType int getApnTypeFromNetworkRequest(NetworkRequest nr) {
-        NetworkCapabilities nc = nr.networkCapabilities;
         // For now, ignore the bandwidth stuff
-        if (nc.getTransportTypes().length > 0 &&
-                nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == false) {
+        if (nr.getTransportTypes().length > 0
+                && !nr.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
             return ApnSetting.TYPE_NONE;
         }
 
@@ -546,50 +543,50 @@
         int apnType = ApnSetting.TYPE_NONE;
         boolean error = false;
 
-        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
+        if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
             apnType = ApnSetting.TYPE_DEFAULT;
         }
-        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
+        if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
             if (apnType != ApnSetting.TYPE_NONE) error = true;
             apnType = ApnSetting.TYPE_MMS;
         }
-        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
+        if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
             if (apnType != ApnSetting.TYPE_NONE) error = true;
             apnType = ApnSetting.TYPE_SUPL;
         }
-        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) {
+        if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) {
             if (apnType != ApnSetting.TYPE_NONE) error = true;
             apnType = ApnSetting.TYPE_DUN;
         }
-        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)) {
+        if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)) {
             if (apnType != ApnSetting.TYPE_NONE) error = true;
             apnType = ApnSetting.TYPE_FOTA;
         }
-        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) {
+        if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) {
             if (apnType != ApnSetting.TYPE_NONE) error = true;
             apnType = ApnSetting.TYPE_IMS;
         }
-        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
+        if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
             if (apnType != ApnSetting.TYPE_NONE) error = true;
             apnType = ApnSetting.TYPE_CBS;
         }
-        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_IA)) {
+        if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_IA)) {
             if (apnType != ApnSetting.TYPE_NONE) error = true;
             apnType = ApnSetting.TYPE_IA;
         }
-        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)) {
+        if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)) {
             if (apnType != ApnSetting.TYPE_NONE) error = true;
             apnType = ApnSetting.TYPE_EMERGENCY;
         }
-        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_MCX)) {
+        if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_MCX)) {
             if (apnType != ApnSetting.TYPE_NONE) error = true;
             apnType = ApnSetting.TYPE_MCX;
         }
-        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)) {
+        if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)) {
             if (apnType != ApnSetting.TYPE_NONE) error = true;
             apnType = ApnSetting.TYPE_XCAP;
         }
-        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)) {
+        if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)) {
             if (apnType != ApnSetting.TYPE_NONE) error = true;
             apnType = ApnSetting.TYPE_ENTERPRISE;
         }
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index 0737ab3..c2ae9ce 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -99,6 +99,7 @@
 import com.android.internal.util.Protocol;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
+import com.android.net.module.util.NetworkCapabilitiesUtils;
 import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
@@ -111,6 +112,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -570,7 +572,9 @@
         ERROR_RADIO_NOT_AVAILABLE,
         ERROR_INVALID_ARG,
         ERROR_STALE,
-        ERROR_DATA_SERVICE_SPECIFIC_ERROR;
+        ERROR_DATA_SERVICE_SPECIFIC_ERROR,
+        ERROR_DUPLICATE_CID,
+        ERROR_NO_DEFAULT_CONNECTION;
 
         public int mFailCause;
 
@@ -643,7 +647,7 @@
     public void updateQosParameters(final @Nullable DataCallResponse response) {
         if (response == null) {
             mDefaultQos = null;
-            mQosBearerSessions = null;
+            mQosBearerSessions.clear();
             return;
         }
 
@@ -886,8 +890,8 @@
         String dnn = null;
         String osAppId = null;
         if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) {
-            // TODO: update osAppId to use NetworkCapability API once it's available
-            osAppId = ApnSetting.getApnTypesStringFromBitmask(mApnSetting.getApnTypeBitmask());
+            osAppId = NetworkCapabilities.getCapabilityCarrierName(
+                    NetworkCapabilities.NET_CAPABILITY_ENTERPRISE);
         } else {
             dnn = mApnSetting.getApnName();
         }
@@ -1316,6 +1320,7 @@
         mApnContexts.clear();
         mApnSetting = null;
         mUnmeteredUseOnly = false;
+        mEnterpriseUse = false;
         mRestrictedNetworkOverride = false;
         mDcFailCause = DataFailCause.NONE;
         mDisabledApnTypeBitMask = 0;
@@ -1327,6 +1332,10 @@
         mIsSuspended = false;
         mHandoverState = HANDOVER_STATE_IDLE;
         mHandoverFailureMode = DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN;
+        mSliceInfo = null;
+        mDefaultQos = null;
+        mQosBearerSessions.clear();
+        mTrafficDescriptors.clear();
     }
 
     /**
@@ -1359,6 +1368,14 @@
                 result = SetupResult.ERROR_DATA_SERVICE_SPECIFIC_ERROR;
                 result.mFailCause = DataFailCause.getFailCause(response.getCause());
             }
+        } else if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE
+                && mDcController.getActiveDcByCid(response.getId()) != null) {
+            if (DBG) log("DataConnection already exists for cid: " + response.getId());
+            result = SetupResult.ERROR_DUPLICATE_CID;
+        } else if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE
+                && !mDcController.isDefaultDataActive()) {
+            if (DBG) log("No default data connection currently active");
+            result = SetupResult.ERROR_NO_DEFAULT_CONNECTION;
         } else {
             if (DBG) log("onSetupConnectionCompleted received successful DataCallResponse");
             mCid = response.getId();
@@ -1580,9 +1597,20 @@
             log("updateLinkBandwidthsFromBandwidthEstimator, UL= "
                     + uplinkBandwidthKbps + " DL= " + downlinkBandwidthKbps);
         }
-        mDownlinkBandwidth = downlinkBandwidthKbps;
-        mUplinkBandwidth = uplinkBandwidthKbps;
+        boolean downlinkUpdated = false;
+        boolean uplinkUpdated = false;
+        if (downlinkBandwidthKbps > 0) {
+            mDownlinkBandwidth = downlinkBandwidthKbps;
+            downlinkUpdated = true;
+        }
+        if (uplinkBandwidthKbps > 0) {
+            mUplinkBandwidth = uplinkBandwidthKbps;
+            uplinkUpdated = true;
+        }
 
+        if (!downlinkUpdated || !uplinkUpdated) {
+            fallBackToCarrierConfigValues(downlinkUpdated, uplinkUpdated);
+        }
         if (mNetworkAgent != null) {
             mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), DataConnection.this);
         }
@@ -1648,13 +1676,20 @@
     private boolean mRestrictedNetworkOverride = false;
 
     /**
+     * Indicates if this data connection supports enterprise use. Note that this flag should be
+     * populated when data becomes active. Once it is set, the value cannot be changed because
+     * setting it will cause this data connection to lose immutable network capabilities, which can
+     * cause issues in connectivity service.
+     */
+    private boolean mEnterpriseUse = false;
+
+    /**
      * Check if this data connection should be restricted. We should call this when data connection
      * becomes active, or when we want to re-evaluate the conditions to decide if we need to
      * unstrict the data connection.
      *
      * @return True if this data connection needs to be restricted.
      */
-
     private boolean shouldRestrictNetwork() {
         // first, check if there is any network request that containing restricted capability
         // (i.e. Do not have NET_CAPABILITY_NOT_RESTRICTED in the request)
@@ -1725,6 +1760,25 @@
     }
 
     /**
+     * Check if this data connection supports enterprise use. We call this when the data connection
+     * becomes active or when we want to reevaluate the conditions to decide if we need to update
+     * the network agent capabilities.
+     *
+     * @return True if this data connection supports enterprise use.
+     */
+    private boolean isEnterpriseUse() {
+        boolean enterpriseTrafficDescriptor = mTrafficDescriptors
+                .stream()
+                .anyMatch(td -> td.getOsAppId() != null && td.getOsAppId().equals(
+                        NetworkCapabilities.getCapabilityCarrierName(
+                                NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)));
+        boolean enterpriseApnContext = mApnContexts.keySet()
+                .stream()
+                .anyMatch(ac -> ac.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE);
+        return enterpriseTrafficDescriptor || enterpriseApnContext;
+    }
+
+    /**
      * Get the network capabilities for this data connection.
      *
      * @return the {@link NetworkCapabilities} of this data connection.
@@ -1733,8 +1787,9 @@
         final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder()
                 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
         boolean hasInternet = false;
+        boolean unmeteredApns = false;
 
-        if (mApnSetting != null) {
+        if (mApnSetting != null && !mEnterpriseUse) {
             final String[] types = ApnSetting.getApnTypesStringFromBitmask(
                     mApnSetting.getApnTypeBitmask() & ~mDisabledApnTypeBitMask).split(",");
             for (String type : types) {
@@ -1808,26 +1863,26 @@
                 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
             }
 
-            // Mark NOT_METERED in the following cases:
-            // 1. All APNs in the APN settings are unmetered.
-            // 2. The non-restricted data is intended for unmetered use only.
-            if ((mUnmeteredUseOnly && !mRestrictedNetworkOverride)
-                    || !ApnSettingUtils.isMetered(mApnSetting, mPhone)) {
-                builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
-            } else {
-                builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
-            }
-
-            // TODO: Need to remove the use of hidden API deduceRestrictedCapability
-            if (builder.build().deduceRestrictedCapability()) {
-                builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+            if (!ApnSettingUtils.isMetered(mApnSetting, mPhone)) {
+                unmeteredApns = true;
             }
         }
 
-        for (ApnContext ctx : mApnContexts.keySet()) {
-            if (ctx.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) {
-                builder.addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE);
-            }
+        // Mark NOT_METERED in the following cases:
+        // 1. All APNs in the APN settings are unmetered.
+        // 2. The non-restricted data is intended for unmetered use only.
+        if (unmeteredApns || (mUnmeteredUseOnly && !mRestrictedNetworkOverride)) {
+            builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+        } else {
+            builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+        }
+
+        if (NetworkCapabilitiesUtils.inferRestrictedCapability(builder.build())) {
+            builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        }
+
+        if (mEnterpriseUse) {
+            builder.addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE);
         }
 
         if (mRestrictedNetworkOverride) {
@@ -1841,6 +1896,7 @@
 
         builder.setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
                 .setSubscriptionId(mSubId).build());
+        builder.setSubIds(Collections.singleton(mSubId));
 
         if (!mPhone.getServiceState().getDataRoaming()) {
             builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
@@ -2560,6 +2616,12 @@
                                     DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN);
                             transitionTo(mInactiveState);
                             break;
+                        case ERROR_DUPLICATE_CID:
+                            // TODO (b/180988471): Properly handle the case when an existing cid is
+                            // returned by tearing down the network agent if enterprise changed.
+                        case ERROR_NO_DEFAULT_CONNECTION:
+                            // TODO (b/180988471): Properly handle the case when a default data
+                            // connection doesn't exist.
                         case ERROR_INVALID_ARG:
                             // The addresses given from the RIL are bad
                             tearDownData(cp);
@@ -2671,6 +2733,9 @@
             final NetworkAgentConfig.Builder configBuilder = new NetworkAgentConfig.Builder();
             configBuilder.setLegacyType(ConnectivityManager.TYPE_MOBILE);
             configBuilder.setLegacyTypeName(NETWORK_TYPE);
+            int networkType = getNetworkType();
+            configBuilder.setLegacySubType(networkType);
+            configBuilder.setLegacySubTypeName(TelephonyManager.getNetworkTypeName(networkType));
             configBuilder.setLegacyExtraInfo(mApnSetting.getApnName());
             final CarrierSignalAgent carrierSignalAgent = mPhone.getCarrierSignalAgent();
             if (carrierSignalAgent.hasRegisteredReceivers(TelephonyManager
@@ -2690,10 +2755,12 @@
             }
 
             mUnmeteredUseOnly = isUnmeteredUseOnly();
+            mEnterpriseUse = isEnterpriseUse();
 
             if (DBG) {
                 log("mRestrictedNetworkOverride = " + mRestrictedNetworkOverride
-                        + ", mUnmeteredUseOnly = " + mUnmeteredUseOnly);
+                        + ", mUnmeteredUseOnly = " + mUnmeteredUseOnly
+                        + ", mEnterpriseUse = " + mEnterpriseUse);
             }
 
             // Always register a VcnNetworkPolicyChangeListener, regardless of whether this is a
@@ -3039,7 +3106,7 @@
                     if (handle < 0) {
                         loge("No slot found for stopSocketKeepalive! " + slotId);
                         mNetworkAgent.sendSocketKeepaliveEvent(
-                                slotId, SocketKeepalive.NO_KEEPALIVE);
+                                slotId, SocketKeepalive.ERROR_NO_SUCH_SLOT);
                         retVal = HANDLED;
                         break;
                     } else {
@@ -3813,6 +3880,7 @@
         pw.println("mUserData=" + mUserData);
         pw.println("mRestrictedNetworkOverride=" + mRestrictedNetworkOverride);
         pw.println("mUnmeteredUseOnly=" + mUnmeteredUseOnly);
+        pw.println("mEnterpriseUse=" + mEnterpriseUse);
         pw.println("mUnmeteredOverride=" + mUnmeteredOverride);
         pw.println("mCongestedOverride=" + mCongestedOverride);
         pw.println("mDownlinkBandwidth" + mDownlinkBandwidth);
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcController.java b/src/java/com/android/internal/telephony/dataconnection/DcController.java
index a4241c7..edf71b3 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcController.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcController.java
@@ -26,6 +26,7 @@
 import android.os.RegistrantList;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.DataFailCause;
+import android.telephony.data.ApnSetting;
 import android.telephony.data.DataCallResponse;
 
 import com.android.internal.telephony.DctConstants;
@@ -161,6 +162,14 @@
         }
     }
 
+    boolean isDefaultDataActive() {
+        synchronized (mDcListAll) {
+            return mDcListActiveByCid.values().stream()
+                    .anyMatch(dc -> dc.getApnContexts().stream()
+                            .anyMatch(apn -> apn.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT));
+        }
+    }
+
     @Override
     public void handleMessage(Message msg) {
         AsyncResult ar;
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java b/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java
index 9ef3569..8d63563 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java
@@ -26,6 +26,7 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkProvider;
 import android.net.QosFilter;
+import android.net.QosSessionAttributes;
 import android.net.SocketKeepalive;
 import android.net.Uri;
 import android.os.Message;
@@ -36,7 +37,7 @@
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
-import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
 import android.telephony.data.QosBearerSession;
 import android.util.ArrayMap;
 import android.util.LocalLog;
@@ -106,9 +107,6 @@
         mNetworkCapabilities = dc.getNetworkCapabilities();
         mTransportType = transportType;
         mDataConnection = dc;
-        int networkType = getNetworkType();
-        setLegacySubtype(networkType, TelephonyManager.getNetworkTypeName(networkType));
-        setLegacyExtraInfo(dc.getApnSetting().getApnName());
         if (dc.getLinkProperties() != null) {
             checkDuplicateInterface(mId, dc.getLinkProperties().getInterfaceName());
             logd("created for data connection " + dc.getName() + ", "
@@ -378,12 +376,13 @@
     }
 
     public void notifyQosSessionAvailable(final int qosCallbackId, final int sessionId,
-            @NonNull final EpsBearerQosSessionAttributes attributes) {
+            @NonNull final QosSessionAttributes attributes) {
         super.sendQosSessionAvailable(qosCallbackId, sessionId, attributes);
     }
 
-    public void notifyQosSessionLost(final int qosCallbackId, final int sessionId) {
-        super.sendQosSessionLost(qosCallbackId, sessionId);
+    public void notifyQosSessionLost(final int qosCallbackId,
+            final int sessionId, final int qosSessionType) {
+        super.sendQosSessionLost(qosCallbackId, sessionId, qosSessionType);
     }
 
     @Override
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index 7f6f306..16fdbb2 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -32,6 +32,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AlarmManager;
+import android.app.Notification;
+import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.ProgressDialog;
 import android.content.ActivityNotFoundException;
@@ -62,6 +64,7 @@
 import android.os.RegistrantList;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.preference.PreferenceManager;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
@@ -99,6 +102,7 @@
 import android.util.SparseArray;
 import android.view.WindowManager;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.DctConstants;
 import com.android.internal.telephony.EventLogTags;
@@ -118,6 +122,7 @@
 import com.android.internal.telephony.metrics.DataStallRecoveryStats;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.telephony.util.ArrayUtils;
+import com.android.internal.telephony.util.NotificationChannelController;
 import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.internal.util.AsyncChannel;
 import com.android.telephony.Rlog;
@@ -149,6 +154,7 @@
     private static final boolean VDBG = false; // STOPSHIP if true
     private static final boolean VDBG_STALL = false; // STOPSHIP if true
     private static final boolean RADIO_TESTS = false;
+    private static final String NOTIFICATION_TAG = DcTracker.class.getSimpleName();
 
     @IntDef(value = {
             REQUEST_TYPE_NORMAL,
@@ -255,6 +261,9 @@
     private static final String INTENT_DATA_STALL_ALARM_EXTRA_TRANSPORT_TYPE =
             "data_stall_alarm_extra_transport_type";
 
+    // Unique id for no data notification on setup data permanently failed.
+    private static final int NO_DATA_NOTIFICATION = 1001;
+
     /** The higher index has higher priority. */
     private static final DctConstants.State[] DATA_CONNECTION_STATE_PRIORITIES = {
             DctConstants.State.IDLE,
@@ -2304,9 +2313,13 @@
 
     protected void startReconnect(long delay, ApnContext apnContext,
             @RequestNetworkType int requestType) {
+        apnContext.setState(DctConstants.State.RETRYING);
         Message msg = obtainMessage(DctConstants.EVENT_DATA_RECONNECT,
                        mPhone.getSubId(), requestType, apnContext);
         cancelReconnect(apnContext);
+
+        // Wait a bit before trying the next APN, so that
+        // we're not tying up the RIL command channel
         sendMessageDelayed(msg, delay);
 
         if (DBG) {
@@ -2919,6 +2932,16 @@
 
         startNetStatPoll();
         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
+
+        PersistableBundle b = getCarrierConfig();
+        if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT
+                && b.getBoolean(CarrierConfigManager
+                .KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL)) {
+            NotificationManager notificationManager = (NotificationManager)
+                    mPhone.getContext().getSystemService(Context.NOTIFICATION_SERVICE);
+            notificationManager.cancel(Integer.toString(mPhone.getSubId()),
+                    NO_DATA_NOTIFICATION);
+        }
     }
 
     /**
@@ -2994,10 +3017,13 @@
                     mPhone.getContext().unregisterReceiver(mProvisionBroadcastReceiver);
                     mProvisionBroadcastReceiver = null;
                 }
+
                 if ((!isProvApn) || mIsProvisioning) {
-                    // Hide any provisioning notification.
-                    cm.setProvisioningNotificationVisible(false, ConnectivityManager.TYPE_MOBILE,
-                            INTENT_PROVISION + ":" + mPhone.getPhoneId());
+                    if (mIsProvisioning) {
+                        // Hide any notification that was showing previously
+                        hideProvisioningNotification();
+                    }
+
                     // Complete the connection normally notifying the world we're connected.
                     // We do this if this isn't a special provisioning apn or if we've been
                     // told its time to provision.
@@ -3021,9 +3047,10 @@
                             mTelephonyManager.getNetworkOperatorName());
                     mPhone.getContext().registerReceiver(mProvisionBroadcastReceiver,
                             new IntentFilter(INTENT_PROVISION));
+
                     // Put up user notification that sign-in is required.
-                    cm.setProvisioningNotificationVisible(true, ConnectivityManager.TYPE_MOBILE,
-                            INTENT_PROVISION + ":" + mPhone.getPhoneId());
+                    showProvisioningNotification();
+
                     // Turn off radio to save battery and avoid wasting carrier resources.
                     // The network isn't usable and network validation will just fail anyhow.
                     setRadio(false);
@@ -3085,6 +3112,34 @@
                 log("cause=" + DataFailCause.toString(cause)
                         + ", mark apn as permanent failed. apn = " + apn);
                 apnContext.markApnPermanentFailed(apn);
+
+                PersistableBundle b = getCarrierConfig();
+                if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT
+                        && b.getBoolean(CarrierConfigManager
+                        .KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL)) {
+                    NotificationManager notificationManager = (NotificationManager)
+                            mPhone.getContext().getSystemService(Context.NOTIFICATION_SERVICE);
+
+                    CharSequence title = mPhone.getContext().getText(
+                            com.android.internal.R.string.RestrictedOnDataTitle);
+                    CharSequence details = mPhone.getContext().getText(
+                            com.android.internal.R.string.RestrictedStateContent);
+
+                    Notification notification = new Notification.Builder(mPhone.getContext(),
+                            NotificationChannelController.CHANNEL_ID_MOBILE_DATA_STATUS)
+                            .setWhen(System.currentTimeMillis())
+                            .setAutoCancel(true)
+                            .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning)
+                            .setTicker(title)
+                            .setColor(mPhone.getContext().getResources().getColor(
+                                    com.android.internal.R.color.system_notification_accent_color))
+                            .setContentTitle(title)
+                            .setStyle(new Notification.BigTextStyle().bigText(details))
+                            .setContentText(details)
+                            .build();
+                    notificationManager.notify(Integer.toString(mPhone.getSubId()),
+                            NO_DATA_NOTIFICATION, notification);
+                }
             }
 
             int newRequestType = calculateNewRetryRequestType(handoverFailureMode, requestType,
@@ -3111,10 +3166,6 @@
                         + ". Request type=" + requestTypeToString(requestType) + ", Retry in "
                         + delay + "ms.");
             }
-            apnContext.setState(DctConstants.State.RETRYING);
-            // Wait a bit before trying the next APN, so that
-            // we're not tying up the RIL command channel
-
             startReconnect(delay, apnContext, requestType);
         } else {
             // If we are not going to retry any APN, set this APN context to failed state.
@@ -4086,10 +4137,6 @@
         for (DataConnection dc : mDataConnections.values()) {
             dc.sendMessage(DataConnection.EVENT_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED);
         }
-        if (mPhone.getLinkBandwidthEstimator() != null) {
-            mPhone.getLinkBandwidthEstimator().sendMessage(obtainMessage(
-                    LinkBandwidthEstimator.MSG_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED));
-        }
     }
 
     /**
@@ -4387,7 +4434,7 @@
         boolean isNrNsa = (networkType == TelephonyManager.NETWORK_TYPE_LTE
                 || networkType == TelephonyManager.NETWORK_TYPE_LTE_CA)
                 && (overrideNetworkType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA
-                || overrideNetworkType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE);
+                || overrideNetworkType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED);
         boolean is5GHysteresisActive = mPhone.getDisplayInfoController().is5GHysteresisActive();
 
         // True if device is on NR SA or NR NSA, or neither but 5G hysteresis is active
@@ -5339,6 +5386,9 @@
                     cleanUpAllConnectionsInternal(false, Phone.REASON_IWLAN_DATA_SERVICE_DIED);
                 }
             }
+        } else {
+            //reset throttling after binding to data service
+            mDataThrottler.reset();
         }
         mDataServiceBound = bound;
     }
@@ -5472,4 +5522,49 @@
     public @NonNull DataThrottler getDataThrottler() {
         return mDataThrottler;
     }
+
+    private void showProvisioningNotification() {
+        final Intent intent = new Intent(DcTracker.INTENT_PROVISION);
+        intent.putExtra(DcTracker.EXTRA_PROVISION_PHONE_ID, mPhone.getPhoneId());
+        final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+                mPhone.getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE);
+
+        final Resources r = mPhone.getContext().getResources();
+        final String title = r.getString(R.string.network_available_sign_in, 0);
+        final String details = mTelephonyManager.getNetworkOperator(mPhone.getSubId());
+        final Notification.Builder builder = new Notification.Builder(mPhone.getContext())
+                .setWhen(System.currentTimeMillis())
+                .setSmallIcon(R.drawable.stat_notify_rssi_in_range)
+                .setChannelId(NotificationChannelController.CHANNEL_ID_MOBILE_DATA_STATUS)
+                .setAutoCancel(true)
+                .setTicker(title)
+                .setColor(mPhone.getContext().getColor(
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setContentTitle(title)
+                .setContentText(details)
+                .setContentIntent(pendingIntent)
+                .setLocalOnly(true)
+                .setOnlyAlertOnce(true);
+
+        final Notification notification = builder.build();
+        try {
+            getNotificationManager().notify(NOTIFICATION_TAG, mPhone.getPhoneId(), notification);
+        } catch (final NullPointerException npe) {
+            Log.e(mLogTag, "showProvisioningNotification: error showing notification", npe);
+        }
+    }
+
+    private void hideProvisioningNotification() {
+        try {
+            getNotificationManager().cancel(NOTIFICATION_TAG, mPhone.getPhoneId());
+        } catch (final NullPointerException npe) {
+            Log.e(mLogTag, "hideProvisioningNotification: error hiding notification", npe);
+        }
+    }
+
+    private NotificationManager getNotificationManager() {
+        return (NotificationManager) mPhone.getContext()
+                .createContextAsUser(UserHandle.ALL, 0 /* flags */)
+                .getSystemService(Context.NOTIFICATION_SERVICE);
+    }
 }
diff --git a/src/java/com/android/internal/telephony/dataconnection/LinkBandwidthEstimator.java b/src/java/com/android/internal/telephony/dataconnection/LinkBandwidthEstimator.java
index c60759e..100b1b9 100644
--- a/src/java/com/android/internal/telephony/dataconnection/LinkBandwidthEstimator.java
+++ b/src/java/com/android/internal/telephony/dataconnection/LinkBandwidthEstimator.java
@@ -21,14 +21,17 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.SharedPreferences;
 import android.hardware.display.DisplayManager;
 import android.net.ConnectivityManager;
 import android.net.Network;
 import android.net.NetworkCapabilities;
+import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.Message;
 import android.os.OutcomeReceiver;
+import android.preference.PreferenceManager;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.CellIdentity;
 import android.telephony.CellIdentityGsm;
@@ -81,7 +84,6 @@
     static final int MSG_NR_FREQUENCY_CHANGED = 6;
     @VisibleForTesting
     static final int MSG_NR_STATE_CHANGED = 7;
-    static final int MSG_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED = 8;
 
     // TODO: move the following parameters to xml file
     private static final int TRAFFIC_STATS_POLL_INTERVAL_MS = 1_000;
@@ -91,8 +93,10 @@
     private static final int BYTE_DELTA_ACC_THRESHOLD_MAX_KB = 5_000;
     private static final int MODEM_POLL_TIME_DELTA_MAX_MS = 15_000;
     private static final int FILTER_UPDATE_MAX_INTERVAL_MS = 5_100;
+    // BW samples with Tx or Rx time below the following value is ignored.
+    private static final int TX_RX_TIME_MIN_MS = 200;
     // The large time constant used in BW filter
-    private static final int TIME_CONSTANT_LARGE_SEC = 30;
+    private static final int TIME_CONSTANT_LARGE_SEC = 6;
     // The small time constant used in BW filter
     private static final int TIME_CONSTANT_SMALL_SEC = 6;
     // If RSSI changes by more than the below value, update BW filter with small time constant
@@ -105,20 +109,32 @@
     // over Rx time ratio is above the following value, use Tx time + Rx time as Rx time.
     private static final int TX_OVER_RX_TIME_RATIO_THRESHOLD_NUM = 3;
     private static final int TX_OVER_RX_TIME_RATIO_THRESHOLD_DEN = 2;
-    // Default Link bandwidth value if the RAT entry is not found in carrier config table.
+    // Default Link bandwidth value if the RAT entry is not found in static BW table.
     private static final int DEFAULT_LINK_BAND_WIDTH_KBPS = 14;
     // If Tx or Rx link bandwidth change is above the following value, send the BW update
-    private static final int BW_UPDATE_THRESHOLD_PERCENT = 40;
+    private static final int BW_UPDATE_THRESHOLD_PERCENT = 15;
 
     // To be used in link bandwidth estimation, each TrafficStats poll sample needs to be above
     // a predefine threshold.
-    // For RAT with carrier config above HIGH_BANDWIDTH_THRESHOLD_KBPS, it uses the following table.
-    // For others RATs, the thresholds are derived from the default carrier config BW values.
+    // For RAT with static BW above HIGH_BANDWIDTH_THRESHOLD_KBPS, it uses the following table.
+    // For others RATs, the thresholds are derived from the static BW values.
     // The following table is defined per signal level, int [NUM_SIGNAL_LEVEL].
-    static final int HIGH_BANDWIDTH_THRESHOLD_KBPS = 5000;
-    static final int[] LINK_BANDWIDTH_BYTE_DELTA_THRESHOLD_KB = {250, 500, 750, 1000, 1000};
+    private static final int HIGH_BANDWIDTH_THRESHOLD_KBPS = 5000;
+    //Array dimension : int [NUM_LINK_DIRECTION][NUM_SIGNAL_LEVEL]
+    private static final int[][] BYTE_DELTA_THRESHOLD_KB =
+            {{200, 300, 400, 600, 1000}, {400, 600, 800, 1000, 1000}};
     // Used to derive byte count threshold from avg BW
-    static final int AVG_BW_TO_LOW_BW_RATIO = 4;
+    private static final int AVG_BW_TO_LOW_BW_RATIO = 4;
+    private static final int BYTE_DELTA_THRESHOLD_MIN_KB = 10;
+    private static final int MAX_ERROR_PERCENT = 100 * 100;
+    private static final String[] AVG_BW_PER_RAT = {
+            "GPRS:24,24", "EDGE:70,18", "UMTS:115,115", "CDMA:14,14",
+            "CDMA - 1xRTT:30,30", "CDMA - EvDo rev. 0:750,48", "CDMA - EvDo rev. A:950,550",
+            "HSDPA:4300,620", "HSUPA:4300,1800", "HSPA:4300,1800", "CDMA - EvDo rev. B:1500,550",
+            "CDMA - eHRPD:750,48", "HSPA+:13000,3400", "TD_SCDMA:115,115",
+            "LTE:30000,15000", "NR_NSA:47000,18000",
+            "NR_NSA_MMWAVE:145000,60000", "NR:145000,60000"};
+    private static final Map<String, Pair<Integer, Integer>> AVG_BW_PER_RAT_MAP = new ArrayMap<>();
 
     // To be used in the long term avg, each count needs to be above the following value
     static final int BW_STATS_COUNT_THRESHOLD = 5;
@@ -135,7 +151,7 @@
     private boolean mScreenOn = false;
     private boolean mIsOnDefaultRoute = false;
     private long mLastModemPollTimeMs;
-
+    private boolean mLastTrafficValid = true;
     private long mLastMobileTxBytes;
     private long mLastMobileRxBytes;
     private long mTxBytesDeltaAcc;
@@ -154,18 +170,40 @@
     private long mFilterUpdateTimeMs;
 
     private int mBandwidthUpdateSignalDbm = -1;
+    private int mBandwidthUpdateSignalLevel = -1;
     private int mBandwidthUpdateDataRat = TelephonyManager.NETWORK_TYPE_UNKNOWN;
     private String mBandwidthUpdatePlmn = "";
     private BandwidthState mTxState = new BandwidthState(LINK_TX);
     private BandwidthState mRxState = new BandwidthState(LINK_RX);
 
+    private static void initAvgBwPerRatTable() {
+        for (String config : AVG_BW_PER_RAT) {
+            int rxKbps = 14;
+            int txKbps = 14;
+            String[] kv = config.split(":");
+            if (kv.length == 2) {
+                String[] split = kv[1].split(",");
+                if (split.length == 2) {
+                    try {
+                        rxKbps = Integer.parseInt(split[0]);
+                        txKbps = Integer.parseInt(split[1]);
+                    } catch (NumberFormatException ignored) {
+                    }
+                }
+                AVG_BW_PER_RAT_MAP.put(kv[0], new Pair<>(rxKbps, txKbps));
+            }
+        }
+    }
+
     private final DisplayManager.DisplayListener mDisplayListener =
             new DisplayManager.DisplayListener() {
                 @Override
-                public void onDisplayAdded(int displayId) { }
+                public void onDisplayAdded(int displayId) {
+                }
 
                 @Override
-                public void onDisplayRemoved(int displayId) { }
+                public void onDisplayRemoved(int displayId) {
+                }
 
                 @Override
                 public void onDisplayChanged(int displayId) {
@@ -215,12 +253,14 @@
         mConnectivityManager.registerDefaultNetworkCallback(mDefaultNetworkCallback, this);
         mTelephonyManager.registerTelephonyCallback(new HandlerExecutor(this),
                 mTelephonyCallback);
-        mPlaceholderNetwork = new NetworkBandwidth("", "");
+        mPlaceholderNetwork = new NetworkBandwidth("");
+        initAvgBwPerRatTable();
         registerDataServiceState();
     }
 
     @Override
     public void handleMessage(Message msg) {
+        AsyncResult ar;
         switch (msg.what) {
             case MSG_SCREEN_STATE_CHANGED:
                 handleScreenStateChanged((boolean) msg.obj);
@@ -240,9 +280,7 @@
             case MSG_NR_FREQUENCY_CHANGED:
                 // fall through
             case MSG_NR_STATE_CHANGED:
-                // fall through
-            case MSG_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED:
-                checkUpdateColdStartValueResetFilter();
+                updateStaticBwValueResetFilter();
                 break;
             default:
                 Rlog.e(TAG, "invalid message " + msg.what);
@@ -312,13 +350,24 @@
         long mobileRxBytes = mTelephonyFacade.getMobileRxBytes();
         long txBytesDelta = mobileTxBytes - mLastMobileTxBytes;
         long rxBytesDelta = mobileRxBytes - mLastMobileRxBytes;
-        mLastMobileTxBytes = mobileTxBytes;
-        mLastMobileRxBytes = mobileRxBytes;
-        mTxBytesDeltaAcc += txBytesDelta;
-        mRxBytesDeltaAcc += rxBytesDelta;
+
         // Schedule the next traffic stats poll
         sendEmptyMessageDelayed(MSG_TRAFFIC_STATS_POLL, TRAFFIC_STATS_POLL_INTERVAL_MS);
 
+        mLastMobileTxBytes = mobileTxBytes;
+        mLastMobileRxBytes = mobileRxBytes;
+        // Sometimes TrafficStats byte counts return invalid values
+        // Ignore two polls if it happens
+        boolean trafficValid = txBytesDelta >= 0 && rxBytesDelta >= 0;
+        if (!mLastTrafficValid || !trafficValid) {
+            mLastTrafficValid = trafficValid;
+            Rlog.e(TAG, " run into invalid traffic count");
+            return;
+        }
+
+        mTxBytesDeltaAcc += txBytesDelta;
+        mRxBytesDeltaAcc += rxBytesDelta;
+
         boolean doModemPoll = true;
         // Check if it meets the requirement to request modem activity
         long txByteDeltaThr = Math.min(mTxState.mByteDeltaAccThr / TRAFFIC_MODEM_POLL_BYTE_RATIO,
@@ -339,10 +388,10 @@
 
         if (doModemPoll) {
             StringBuilder sb = new StringBuilder();
-            logd(sb.append("TxByteDelta ").append(txBytesDelta)
-                    .append(" RxByteDelta ").append(rxBytesDelta)
-                    .append("TxByteDeltaAcc ").append(mTxBytesDeltaAcc)
-                    .append(" RxByteDeltaAcc ").append(mRxBytesDeltaAcc)
+            logd(sb.append("txByteDelta ").append(txBytesDelta)
+                    .append(" rxByteDelta ").append(rxBytesDelta)
+                    .append(" txByteDeltaAcc ").append(mTxBytesDeltaAcc)
+                    .append(" rxByteDeltaAcc ").append(mRxBytesDeltaAcc)
                     .append(" trigger modem activity request").toString());
             updateDataRatCellIdentity();
             // Filter update will happen after the request
@@ -368,7 +417,9 @@
         updateBandwidthTxRxSamples(result);
         updateTxRxBandwidthFilterSendToDataConnection();
         mLastModemActivityInfo = result;
+        // Update for next poll
         resetByteDeltaAcc();
+        invalidateTxRxSamples();
     }
 
     private void resetByteDeltaAcc() {
@@ -376,9 +427,12 @@
         mRxBytesDeltaAcc = 0;
     }
 
+    private void invalidateTxRxSamples() {
+        mTxState.mBwSampleValid = false;
+        mRxState.mBwSampleValid = false;
+    }
+
     private void updateBandwidthTxRxSamples(ModemActivityInfo modemActivityInfo) {
-        mTxState.mBandwidthSampleValid = false;
-        mRxState.mBandwidthSampleValid = false;
         if (mLastModemActivityInfo == null || modemActivityInfo == null
                 || mNetworkCapabilities == null) {
             return;
@@ -404,25 +458,24 @@
         mTxState.updateBandwidthSample(mTxBytesDeltaAcc, txTimeDeltaMs);
         mRxState.updateBandwidthSample(mRxBytesDeltaAcc, rxTimeBwEstMs);
 
-        int l2TxTputKbps = mNetworkCapabilities.getLinkUpstreamBandwidthKbps();
-        int l2RxTputKbps = mNetworkCapabilities.getLinkDownstreamBandwidthKbps();
+        int reportedTxTputKbps = mNetworkCapabilities.getLinkUpstreamBandwidthKbps();
+        int reportedRxTputKbps = mNetworkCapabilities.getLinkDownstreamBandwidthKbps();
 
         StringBuilder sb = new StringBuilder();
-        logd(sb.append(" dBm=").append(mSignalStrengthDbm)
-                .append(" level=").append(mSignalLevel)
-                .append(" rat=").append(getDataRatName(mDataRat))
-                .append(" plmn=").append(mPlmn)
-                .append(" tac=").append(mTac)
-                .append(" l2TxKbps=").append(l2TxTputKbps)
-                .append(" l2RxKbps=").append(l2RxTputKbps)
-                .append(" txMs=").append(txTimeDeltaMs)
-                .append(" rxMs=").append(rxTimeDeltaMs)
-                .append(" txKB=").append(mTxBytesDeltaAcc / 1024)
-                .append(" rxKB=").append(mRxBytesDeltaAcc / 1024)
-                .append(" TxMbps=").append(mTxState.mBandwidthSampleKbps / 1024)
-                .append(" RxMbps=").append(mRxState.mBandwidthSampleKbps / 1024)
-                .append(" TxValid=").append(mTxState.mBandwidthSampleValid)
-                .append(" RxValid=").append(mRxState.mBandwidthSampleValid)
+        logd(sb.append("UpdateBwSample")
+                .append(" dBm ").append(mSignalStrengthDbm)
+                .append(" level ").append(mSignalLevel)
+                .append(" rat ").append(getDataRatName(mDataRat))
+                .append(" plmn ").append(mPlmn)
+                .append(" tac ").append(mTac)
+                .append(" reportedTxKbps ").append(reportedTxTputKbps)
+                .append(" reportedRxKbps ").append(reportedRxTputKbps)
+                .append(" txMs ").append(txTimeDeltaMs)
+                .append(" rxMs ").append(rxTimeDeltaMs)
+                .append(" txKB ").append(mTxBytesDeltaAcc / 1024)
+                .append(" rxKB ").append(mRxBytesDeltaAcc / 1024)
+                .append(" txKBThr ").append(mTxState.mByteDeltaAccThr / 1024)
+                .append(" rxKBThr ").append(mRxState.mByteDeltaAccThr / 1024)
                 .toString());
     }
 
@@ -439,65 +492,112 @@
         mTxState.updateBandwidthFilter();
         mRxState.updateBandwidthFilter();
 
-        int txDeltaKbps = Math.abs(mTxState.mLastReportedBwKbps - mTxState.mFilterKbps);
-        int rxDeltaKbps = Math.abs(mRxState.mLastReportedBwKbps - mRxState.mFilterKbps);
-        if ((txDeltaKbps * 100  >  BW_UPDATE_THRESHOLD_PERCENT * mTxState.mLastReportedBwKbps)
-                || (rxDeltaKbps * 100  >  BW_UPDATE_THRESHOLD_PERCENT
-                * mRxState.mLastReportedBwKbps)
+        if (mTxState.hasLargeBwChange()
+                || mRxState.hasLargeBwChange()
                 || mBandwidthUpdateDataRat != mDataRat
+                || mBandwidthUpdateSignalLevel != mSignalLevel
                 || !mBandwidthUpdatePlmn.equals(mPlmn)) {
-            sendLinkBandwidthToDataConnection(mTxState.mFilterKbps, mRxState.mFilterKbps);
-            mTxState.mLastReportedBwKbps = mTxState.mFilterKbps;
-            mRxState.mLastReportedBwKbps = mRxState.mFilterKbps;
+            mTxState.mLastReportedBwKbps = mTxState.mAvgUsedKbps < 0 ? -1 : mTxState.mFilterKbps;
+            mRxState.mLastReportedBwKbps  = mRxState.mAvgUsedKbps < 0 ? -1 : mRxState.mFilterKbps;
+            sendLinkBandwidthToDataConnection(
+                    mTxState.mLastReportedBwKbps,
+                    mRxState.mLastReportedBwKbps);
         }
         mBandwidthUpdateSignalDbm = mSignalStrengthDbm;
+        mBandwidthUpdateSignalLevel = mSignalLevel;
         mBandwidthUpdateDataRat = mDataRat;
         mBandwidthUpdatePlmn = mPlmn;
+
+        mTxState.calculateError();
+        mRxState.calculateError();
     }
 
     private class BandwidthState {
         private final int mLink;
         int mFilterKbps;
-        int mByteDeltaAccThr;
-        int mBandwidthSampleKbps;
-        boolean mBandwidthSampleValid;
-        long mBandwidthSampleValidTimeMs;
-        int mBandwidthColdStartKbps;
+        int mByteDeltaAccThr = BYTE_DELTA_THRESHOLD_KB[0][0];
+        int mAvgUsedKbps;
+        int mBwSampleKbps;
+        boolean mBwSampleValid;
+        long mBwSampleValidTimeMs;
+        int mStaticBwKbps;
         int mLastReportedBwKbps;
+        private final Map<String, EstimationError> mErrorMap = new ArrayMap<>();
+
+        private class EstimationError {
+            final String mRatName;
+            final long[] mBwEstIntNse = new long[NUM_SIGNAL_LEVEL];
+            final long[] mBwEstExtNse = new long[NUM_SIGNAL_LEVEL];
+            final long[] mStaticBwNse = new long[NUM_SIGNAL_LEVEL];
+            final int[] mCount = new int[NUM_SIGNAL_LEVEL];
+
+            EstimationError(String ratName) {
+                mRatName = ratName;
+            }
+
+            @Override
+            public String toString() {
+                StringBuilder sb = new StringBuilder();
+                return sb.append(mRatName)
+                        .append("\n Internal\n").append(printAvgError(mBwEstIntNse, mCount))
+                        .append("\n External\n").append(printAvgError(mBwEstExtNse, mCount))
+                        .append("\n StaticBw\n").append(printAvgError(mStaticBwNse, mCount))
+                        .toString();
+            }
+
+            private String printAvgError(long[] stats, int[] count) {
+                StringBuilder sb = new StringBuilder();
+                for (int k = 0; k < NUM_SIGNAL_LEVEL; k++) {
+                    int avgStat = (count[k] >= BW_STATS_COUNT_THRESHOLD && stats[k] >= 0)
+                            ? (int) Math.sqrt(stats[k] / count[k]) : 0;
+                    sb.append(" " + avgStat);
+                }
+                return sb.toString();
+            }
+        }
 
         BandwidthState(int link) {
             mLink = link;
         }
 
+        private EstimationError lookupEstimationError(String dataRatName) {
+            EstimationError ans = mErrorMap.get(dataRatName);
+            if (ans == null) {
+                ans = new EstimationError(dataRatName);
+                mErrorMap.put(dataRatName, ans);
+            }
+            return ans;
+        }
+
         private void updateBandwidthSample(long bytesDelta, long timeDeltaMs) {
             if (bytesDelta < mByteDeltaAccThr) {
                 return;
             }
-            if (timeDeltaMs <= 0) {
+            if (timeDeltaMs < TX_RX_TIME_MIN_MS) {
                 return;
             }
             int linkBandwidthKbps = (int) (bytesDelta * 8 * 1000 / timeDeltaMs / 1024);
-            mBandwidthSampleValid = true;
-            mBandwidthSampleKbps = linkBandwidthKbps;
+            mBwSampleValid = true;
+            mBwSampleKbps = linkBandwidthKbps;
 
             String dataRatName = getDataRatName(mDataRat);
             NetworkBandwidth network = lookupNetwork(mPlmn, dataRatName);
             // Update per RAT stats of all TAC
-            network.linkBandwidthStats.increment(linkBandwidthKbps, mLink, mSignalLevel);
+            network.update(linkBandwidthKbps, mLink, mSignalLevel);
 
             // Update per TAC stats
-            LocalAreaNetworkBandwidth localNetwork = lookupLocalNetwork(mPlmn, mTac, dataRatName);
-            localNetwork.linkBandwidthStats.increment(linkBandwidthKbps, mLink, mSignalLevel);
+            network = lookupNetwork(mPlmn, mTac, dataRatName);
+            network.update(linkBandwidthKbps, mLink, mSignalLevel);
         }
 
         private void updateBandwidthFilter() {
             int avgKbps = getAvgLinkBandwidthKbps();
             // Feed the filter with the long term avg if there is no valid BW sample so that filter
             // will gradually converge the long term avg.
-            int filterInKbps = mBandwidthSampleValid ? mBandwidthSampleKbps : avgKbps;
+            int filterInKbps = mBwSampleValid ? mBwSampleKbps : avgKbps;
 
             long currTimeMs = mTelephonyFacade.getElapsedSinceBootMillis();
-            int timeDeltaSec = (int) (currTimeMs - mBandwidthSampleValidTimeMs) / 1000;
+            int timeDeltaSec = (int) (currTimeMs - mBwSampleValidTimeMs) / 1000;
 
             // If the operation condition changes significantly since the last update
             // or the sample has higher BW, use a faster filter. Otherwise, use a slow filter
@@ -505,19 +605,18 @@
             if (Math.abs(mBandwidthUpdateSignalDbm - mSignalStrengthDbm) > RSSI_DELTA_THRESHOLD_DB
                     || !mBandwidthUpdatePlmn.equals(mPlmn)
                     || mBandwidthUpdateDataRat != mDataRat
-                    || (mBandwidthSampleValid && mBandwidthSampleKbps > avgKbps)) {
+                    || (mBwSampleValid && mBwSampleKbps > avgKbps)) {
                 timeConstantSec = TIME_CONSTANT_SMALL_SEC;
             } else {
                 timeConstantSec = TIME_CONSTANT_LARGE_SEC;
             }
             // Update timestamp for next iteration
-            if (mBandwidthSampleValid) {
-                mBandwidthSampleValidTimeMs = currTimeMs;
-                mBandwidthSampleValid = false;
+            if (mBwSampleValid) {
+                mBwSampleValidTimeMs = currTimeMs;
             }
 
             if (filterInKbps == mFilterKbps) {
-                logd(mLink + " skip filter because the same input / current = " + filterInKbps);
+                logv(mLink + " skip filter because the same input / current = " + filterInKbps);
                 return;
             }
 
@@ -526,7 +625,7 @@
             mFilterKbps = alpha == 0 ? filterInKbps : ((mFilterKbps * alpha
                     + filterInKbps * FILTER_SCALE - filterInKbps * alpha) / FILTER_SCALE);
             StringBuilder sb = new StringBuilder();
-            logd(sb.append(mLink)
+            logv(sb.append(mLink)
                     .append(" lastSampleWeight=").append(alpha)
                     .append("/").append(FILTER_SCALE)
                     .append(" filterInKbps=").append(filterInKbps)
@@ -538,31 +637,35 @@
         private int getAvgUsedLinkBandwidthKbps() {
             // Check if current TAC/RAT/level has enough stats
             String dataRatName = getDataRatName(mDataRat);
-            LinkBandwidthStats linkBandwidthStats =
-                    lookupLocalNetwork(mPlmn, mTac, dataRatName).linkBandwidthStats;
-            int count = linkBandwidthStats.getCount(mLink, mSignalLevel);
+            NetworkBandwidth network = lookupNetwork(mPlmn, mTac, dataRatName);
+            int count = network.getCount(mLink, mSignalLevel);
             if (count >= BW_STATS_COUNT_THRESHOLD) {
-                return (int) (linkBandwidthStats.getValue(mLink, mSignalLevel) / count);
+                return (int) (network.getValue(mLink, mSignalLevel) / count);
             }
 
             // Check if current RAT/level has enough stats
-            linkBandwidthStats = lookupNetwork(mPlmn, dataRatName).linkBandwidthStats;
-            count = linkBandwidthStats.getCount(mLink, mSignalLevel);
+            network = lookupNetwork(mPlmn, dataRatName);
+            count = network.getCount(mLink, mSignalLevel);
             if (count >= BW_STATS_COUNT_THRESHOLD) {
-                return (int) (linkBandwidthStats.getValue(mLink, mSignalLevel) / count);
+                return (int) (network.getValue(mLink, mSignalLevel) / count);
             }
             return -1;
         }
 
-        /** get a long term avg value (PLMN/RAT/TAC/level dependent) or carrier config value */
-        private int getAvgLinkBandwidthKbps() {
-            int avgUsagKbps = getAvgUsedLinkBandwidthKbps();
+        private int getCurrentCount() {
+            String dataRatName = getDataRatName(mDataRat);
+            NetworkBandwidth network = lookupNetwork(mPlmn, dataRatName);
+            return network.getCount(mLink, mSignalLevel);
+        }
 
-            if (avgUsagKbps > 0) {
-                return avgUsagKbps;
+        /** get a long term avg value (PLMN/RAT/TAC/level dependent) or static value */
+        private int getAvgLinkBandwidthKbps() {
+            mAvgUsedKbps = getAvgUsedLinkBandwidthKbps();
+            if (mAvgUsedKbps > 0) {
+                return mAvgUsedKbps;
             }
-            // Fall back to cold start value
-            return mBandwidthColdStartKbps;
+            // Fall back to static value
+            return mStaticBwKbps;
         }
 
         private void resetBandwidthFilter() {
@@ -571,11 +674,11 @@
 
         private void updateByteCountThr() {
             // For high BW RAT cases, use predefined value + threshold derived from avg usage BW
-            if (mBandwidthColdStartKbps > HIGH_BANDWIDTH_THRESHOLD_KBPS) {
+            if (mStaticBwKbps > HIGH_BANDWIDTH_THRESHOLD_KBPS) {
                 int lowBytes = calculateByteCountThreshold(getAvgUsedLinkBandwidthKbps(),
                         MODEM_POLL_MIN_INTERVAL_MS);
                 // Start with a predefined value
-                mByteDeltaAccThr = LINK_BANDWIDTH_BYTE_DELTA_THRESHOLD_KB[mSignalLevel] * 1024;
+                mByteDeltaAccThr = BYTE_DELTA_THRESHOLD_KB[mLink][mSignalLevel] * 1024;
                 if (lowBytes > 0) {
                     // Raise the threshold if the avg usage BW is high
                     mByteDeltaAccThr = Math.max(lowBytes, mByteDeltaAccThr);
@@ -584,43 +687,75 @@
                 }
                 return;
             }
-            // For low BW RAT cases, derive the threshold from carrier config BW values
-            mByteDeltaAccThr = calculateByteCountThreshold(mBandwidthColdStartKbps,
+            // For low BW RAT cases, derive the threshold from avg BW values
+            mByteDeltaAccThr = calculateByteCountThreshold(mStaticBwKbps,
                     MODEM_POLL_MIN_INTERVAL_MS);
+
+            mByteDeltaAccThr = Math.max(mByteDeltaAccThr, BYTE_DELTA_THRESHOLD_MIN_KB * 1024);
             // Low BW RAT threshold value should be no more than high BW one.
-            mByteDeltaAccThr = Math.min(mByteDeltaAccThr,
-                    LINK_BANDWIDTH_BYTE_DELTA_THRESHOLD_KB[0] * 1024);
+            mByteDeltaAccThr = Math.min(mByteDeltaAccThr, BYTE_DELTA_THRESHOLD_KB[mLink][0] * 1024);
         }
 
         // Calculate a byte count threshold for the given avg BW and observation window size
         private int calculateByteCountThreshold(int avgBwKbps, int durationMs) {
             return avgBwKbps / 8 * durationMs / AVG_BW_TO_LOW_BW_RATIO;
         }
+
+        public boolean hasLargeBwChange() {
+            int deltaKbps = Math.abs(mLastReportedBwKbps - mFilterKbps);
+            return mAvgUsedKbps > 0
+                    && deltaKbps * 100 > BW_UPDATE_THRESHOLD_PERCENT * mLastReportedBwKbps;
+        }
+
+        public void calculateError() {
+            if (!mBwSampleValid || getCurrentCount() <= BW_STATS_COUNT_THRESHOLD + 1) {
+                return;
+            }
+            int bwEstExtErrPercent = calculateErrorPercent(mLastReportedBwKbps, mBwSampleKbps);
+            int bwEstAvgErrPercent = calculateErrorPercent(mAvgUsedKbps, mBwSampleKbps);
+            int bwEstIntErrPercent = calculateErrorPercent(mFilterKbps, mBwSampleKbps);
+            int coldStartErrPercent = calculateErrorPercent(mStaticBwKbps, mBwSampleKbps);
+            EstimationError err = lookupEstimationError(getDataRatName(mDataRat));
+            err.mBwEstIntNse[mSignalLevel] += bwEstIntErrPercent * bwEstIntErrPercent;
+            err.mBwEstExtNse[mSignalLevel] += bwEstExtErrPercent * bwEstExtErrPercent;
+            err.mStaticBwNse[mSignalLevel] += coldStartErrPercent * coldStartErrPercent;
+            err.mCount[mSignalLevel]++;
+            StringBuilder sb = new StringBuilder();
+            logd(sb.append(mLink)
+                    .append(" sampKbps ").append(mBwSampleKbps)
+                    .append(" filtKbps ").append(mFilterKbps)
+                    .append(" reportKbps ").append(mLastReportedBwKbps)
+                    .append(" avgUsedKbps ").append(mAvgUsedKbps)
+                    .append(" csKbps ").append(mStaticBwKbps)
+                    .append(" intErrPercent ").append(bwEstIntErrPercent)
+                    .append(" avgErrPercent ").append(bwEstAvgErrPercent)
+                    .append(" extErrPercent ").append(bwEstExtErrPercent)
+                    .append(" csErrPercent ").append(coldStartErrPercent)
+                    .toString());
+        }
+
+        private int calculateErrorPercent(int inKbps, int bwSampleKbps) {
+            int errorKbps = inKbps - bwSampleKbps;
+            int errorPercent = bwSampleKbps > 0 ? (errorKbps * 100 / bwSampleKbps) : 0;
+            return Math.max(-MAX_ERROR_PERCENT, Math.min(errorPercent, MAX_ERROR_PERCENT));
+        }
     }
 
     /**
      * Update the byte count threshold.
-     * It should be called whenever the RAT, signal level or carrier config is changed.
-     * For the RAT with high BW (4G and beyond), use LINK_BANDWIDTH_BYTE_DELTA_THRESHOLD_KB table.
-     * For other RATs, derive the threshold based on the carrier config avg BW values.
+     * It should be called whenever the RAT or signal level is changed.
+     * For the RAT with high BW (4G and beyond), use BYTE_DELTA_THRESHOLD_KB table.
+     * For other RATs, derive the threshold based on the static BW values.
      */
     private void updateByteCountThr() {
         mTxState.updateByteCountThr();
         mRxState.updateByteCountThr();
-        logd("ByteAccThr tx:" + mTxState.mByteDeltaAccThr + " rx:" + mRxState.mByteDeltaAccThr);
     }
 
-    // Reset BW filter to a long term avg value (PLMN/RAT/TAC dependent) or carrier config value.
-    // It should be called whenever PLMN/RAT/carrier config is changed;
+    // Reset BW filter to a long term avg value (PLMN/RAT/TAC dependent) or static BW value.
+    // It should be called whenever PLMN/RAT or static BW value is changed;
     private void resetBandwidthFilter() {
         StringBuilder sb = new StringBuilder();
-        logd(sb.append("Reset BW filter ")
-                .append(" dBm=").append(mSignalStrengthDbm)
-                .append(" level=").append(mSignalLevel)
-                .append(" rat=").append(getDataRatName(mDataRat))
-                .append(" plmn=").append(mPlmn)
-                .append(" tac=").append(mTac)
-                .toString());
         mTxState.resetBandwidthFilter();
         mRxState.resetBandwidthFilter();
     }
@@ -634,7 +769,7 @@
         if (dc == null) {
             return;
         }
-        logd("Update DC BW, tx " + linkBandwidthTxKps + " rx " + linkBandwidthRxKps);
+        logv("send to DC tx " + linkBandwidthTxKps + " rx " + linkBandwidthRxKps);
         dc.updateLinkBandwidthEstimation(linkBandwidthTxKps, linkBandwidthRxKps);
     }
 
@@ -669,33 +804,37 @@
         return TelephonyManager.getNetworkTypeName(rat);
     }
 
-    // Update BW cold start values.
+    // Update avg BW values.
     // It should be called whenever the RAT could be changed.
-    // return true if cold start value is changed;
-    private boolean updateColdStartValueFromCarrierConfig() {
-        DcTracker dt = mPhone.getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
-        if (dt == null) {
-            return false;
-        }
-        String dataRatName = getDataRatName(mDataRat);
-        Pair<Integer, Integer> values = dt.getLinkBandwidthsFromCarrierConfig(dataRatName);
+    // return true if avg value is changed;
+    private boolean updateStaticBwValue(int dataRat) {
+        Pair<Integer, Integer> values = getStaticAvgBw(dataRat);
         if (values == null) {
-            Rlog.e(TAG, dataRatName + " returns null CarrierConfig BW");
-            mTxState.mBandwidthColdStartKbps = DEFAULT_LINK_BAND_WIDTH_KBPS;
-            mRxState.mBandwidthColdStartKbps = DEFAULT_LINK_BAND_WIDTH_KBPS;
+            mTxState.mStaticBwKbps = DEFAULT_LINK_BAND_WIDTH_KBPS;
+            mRxState.mStaticBwKbps = DEFAULT_LINK_BAND_WIDTH_KBPS;
             return true;
         }
-        if (mTxState.mBandwidthColdStartKbps != values.second
-                || mRxState.mBandwidthColdStartKbps != values.first) {
-            mTxState.mBandwidthColdStartKbps = values.second;
-            mRxState.mBandwidthColdStartKbps = values.first;
+        if (mTxState.mStaticBwKbps != values.second
+                || mRxState.mStaticBwKbps != values.first) {
+            mTxState.mStaticBwKbps = values.second;
+            mRxState.mStaticBwKbps = values.first;
             return true;
         }
         return false;
     }
 
-    private void checkUpdateColdStartValueResetFilter() {
-        if (updateColdStartValueFromCarrierConfig()) {
+    /** get per-RAT static bandwidth value */
+    public Pair<Integer, Integer> getStaticAvgBw(int dataRat) {
+        String dataRatName = getDataRatName(dataRat);
+        Pair<Integer, Integer> values = AVG_BW_PER_RAT_MAP.get(dataRatName);
+        if (values == null) {
+            Rlog.e(TAG, dataRatName + " is not found in Avg BW table");
+        }
+        return values;
+    }
+
+    private void updateStaticBwValueResetFilter() {
+        if (updateStaticBwValue(mDataRat)) {
             updateByteCountThr();
             resetBandwidthFilter();
             updateTxRxBandwidthFilterSendToDataConnection();
@@ -735,7 +874,7 @@
             if (dataRat != mDataRat) {
                 updatedRat = true;
                 mDataRat = dataRat;
-                updateColdStartValueFromCarrierConfig();
+                updateStaticBwValue(mDataRat);
                 updateByteCountThr();
             }
         }
@@ -773,14 +912,19 @@
         }
     }
 
+    void logv(String msg) {
+        if (DBG) Rlog.v(TAG, msg);
+    }
+
     void logd(String msg) {
         if (DBG) Rlog.d(TAG, msg);
         mLocalLog.log(msg);
     }
 
+    @VisibleForTesting
+    static final int UNKNOWN_TAC = -1;
     // Map with NetworkKey as the key and NetworkBandwidth as the value.
     // NetworkKey is specified by the PLMN, data RAT and TAC of network.
-    // If TAC is not available, default TAC value (-1) is used.
     // NetworkBandwidth represents the bandwidth related stats of each network.
     private final Map<NetworkKey, NetworkBandwidth> mNetworkMap = new ArrayMap<>();
     private static class NetworkKey {
@@ -792,11 +936,6 @@
             mTac = tac;
             mDataRat = dataRat;
         }
-        NetworkKey(String plmn, String dataRat) {
-            mPlmn = plmn;
-            mTac = -1;
-            mDataRat = dataRat;
-        }
         @Override
         public boolean equals(@Nullable Object o) {
             if (o == null || !(o instanceof NetworkKey) || hashCode() != o.hashCode()) {
@@ -817,92 +956,110 @@
         public int hashCode() {
             return Objects.hash(mPlmn, mDataRat, mTac);
         }
-
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("Plmn").append(mPlmn)
+                    .append("Rat").append(mDataRat)
+                    .append("Tac").append(mTac)
+                    .toString();
+            return sb.toString();
+        }
     }
+
+    @NonNull
     private NetworkBandwidth lookupNetwork(String plmn, String dataRat) {
-        if (plmn == null) {
+        return lookupNetwork(plmn, UNKNOWN_TAC, dataRat);
+    }
+
+    /** Look up NetworkBandwidth and create a new one if it doesn't exist */
+    @VisibleForTesting
+    @NonNull
+    public NetworkBandwidth lookupNetwork(String plmn, int tac, String dataRat) {
+        if (plmn == null || dataRat.equals(
+                TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_UNKNOWN))) {
             return mPlaceholderNetwork;
         }
-        NetworkKey key = new NetworkKey(plmn, dataRat);
+        NetworkKey key = new NetworkKey(plmn, tac, dataRat);
         NetworkBandwidth ans = mNetworkMap.get(key);
         if (ans == null) {
-            ans = new NetworkBandwidth(plmn, dataRat);
+            ans = new NetworkBandwidth(key.toString());
             mNetworkMap.put(key, ans);
         }
         return ans;
     }
 
-    private static class NetworkBandwidth {
-        protected final String mPlmn;
-        protected final NetworkKey mKey;
-        protected final String mDataRat;
-        public final LinkBandwidthStats linkBandwidthStats;
-        NetworkBandwidth(String plmn, String dataRat) {
-            mKey = new NetworkKey(plmn, dataRat);
-            mPlmn = plmn;
-            mDataRat = dataRat;
-            linkBandwidthStats = new LinkBandwidthStats();
+    /** A class holding link bandwidth related stats */
+    @VisibleForTesting
+    public class NetworkBandwidth {
+        private final String mKey;
+        NetworkBandwidth(String key) {
+            mKey = key;
         }
+
+        /** Update link bandwidth stats */
+        public void update(long value, int link, int level) {
+            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(
+                    mPhone.getContext());
+            String valueKey = getValueKey(link, level);
+            String countKey = getCountKey(link, level);
+            SharedPreferences.Editor editor = sp.edit();
+            long currValue = sp.getLong(valueKey, 0);
+            int currCount = sp.getInt(countKey, 0);
+            editor.putLong(valueKey, currValue + value);
+            editor.putInt(countKey, currCount + 1);
+            editor.apply();
+        }
+
+        private String getValueKey(int link, int level) {
+            return getDataKey(link, level) + "Data";
+        }
+
+        private String getCountKey(int link, int level) {
+            return getDataKey(link, level) + "Count";
+        }
+
+        private String getDataKey(int link, int level) {
+            StringBuilder sb = new StringBuilder();
+            return sb.append(mKey)
+                    .append("Link").append(link)
+                    .append("Level").append(level)
+                    .toString();
+        }
+
+        /** Get the accumulated bandwidth value */
+        public long getValue(int link, int level) {
+            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(
+                    mPhone.getContext());
+            String valueKey = getValueKey(link, level);
+            return sp.getLong(valueKey, 0);
+        }
+
+        /** Get the accumulated bandwidth count */
+        public int getCount(int link, int level) {
+            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(
+                    mPhone.getContext());
+            String countKey = getCountKey(link, level);
+            return sp.getInt(countKey, 0);
+        }
+
         @Override
         public String toString() {
             StringBuilder sb = new StringBuilder();
-            sb.append(" PLMN ").append(mPlmn)
-                    .append(" RAT ").append(mDataRat)
-                    .append(" Stats \n").append(linkBandwidthStats);
-            return sb.toString();
-        }
-    }
-
-    private LocalAreaNetworkBandwidth lookupLocalNetwork(String plmn, int tac, String dataRat) {
-        NetworkKey key = new NetworkKey(plmn, tac, dataRat);
-        LocalAreaNetworkBandwidth ans = (LocalAreaNetworkBandwidth) mNetworkMap.get(key);
-        if (ans == null) {
-            ans = new LocalAreaNetworkBandwidth(plmn, tac, dataRat);
-            mNetworkMap.put(key, ans);
-        }
-        return ans;
-    }
-
-    private static class LocalAreaNetworkBandwidth extends NetworkBandwidth {
-        private final int mTac;
-        LocalAreaNetworkBandwidth(String plmn, int tac, String dataRat) {
-            super(plmn, dataRat);
-            mTac = tac;
-        }
-        @Override
-        public String toString() {
-            StringBuilder sb = new StringBuilder();
-            sb.append(" PLMN ").append(mPlmn)
-                    .append(" RAT ").append(mDataRat)
-                    .append(" TAC ").append(mTac)
-                    .append(" Stats \n").append(linkBandwidthStats);
-            return sb.toString();
-        }
-    }
-
-    private static class LinkBandwidthStats {
-        // Stats per signal level
-        private final long[][] mValue = new long[NUM_LINK_DIRECTION][NUM_SIGNAL_LEVEL];
-        private final int[][] mCount = new int[NUM_LINK_DIRECTION][NUM_SIGNAL_LEVEL];
-        void increment(long value, int link, int level) {
-            mValue[link][level] += value;
-            mCount[link][level]++;
-        }
-        int getCount(int link, int level) {
-            return mCount[link][level];
-        }
-        long getValue(int link, int level) {
-            return mValue[link][level];
-        }
-        @Override
-        public String toString() {
-            StringBuilder sb = new StringBuilder();
-            for (int i = 0; i < NUM_LINK_DIRECTION; i++) {
-                sb.append(" i = " + i);
-                for (int j = 0; j < NUM_SIGNAL_LEVEL; j++) {
-                    sb.append(" j = " + j);
-                    sb.append(" value: " + mValue[i][j]);
-                    sb.append(" count: " + mCount[i][j]);
+            sb.append(mKey);
+            sb.append("\n");
+            for (int link = 0; link < NUM_LINK_DIRECTION; link++) {
+                sb.append((link == 0 ? "tx" : "rx"));
+                sb.append("\n avgKbps");
+                for (int level = 0; level < NUM_SIGNAL_LEVEL; level++) {
+                    int count = getCount(link, level);
+                    int avgKbps = count == 0 ? 0 : (int) (getValue(link, level) / count);
+                    sb.append(" ").append(avgKbps);
+                }
+                sb.append("\n count");
+                for (int level = 0; level < NUM_SIGNAL_LEVEL; level++) {
+                    int count = getCount(link, level);
+                    sb.append(" ").append(count);
                 }
                 sb.append("\n");
             }
@@ -917,11 +1074,21 @@
         IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " ");
         pw.increaseIndent();
         pw.println("current PLMN " + mPlmn + " TAC " + mTac + " RAT " + getDataRatName(mDataRat));
-        pw.println("all recent networks ");
+        pw.println("all networks visited since device boot");
         for (NetworkBandwidth network : mNetworkMap.values()) {
             pw.println(network.toString());
         }
 
+        pw.println("Tx NRMSE");
+        for (BandwidthState.EstimationError err : mTxState.mErrorMap.values()) {
+            pw.println(err.toString());
+        }
+
+        pw.println("Rx NRMSE");
+        for (BandwidthState.EstimationError err : mRxState.mErrorMap.values()) {
+            pw.println(err.toString());
+        }
+
         try {
             mLocalLog.dump(fd, pw, args);
         } catch (Exception e) {
@@ -931,4 +1098,5 @@
         pw.println();
         pw.flush();
     }
+
 }
diff --git a/src/java/com/android/internal/telephony/dataconnection/QosCallbackTracker.java b/src/java/com/android/internal/telephony/dataconnection/QosCallbackTracker.java
index 94055f9..e44f03d 100644
--- a/src/java/com/android/internal/telephony/dataconnection/QosCallbackTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/QosCallbackTracker.java
@@ -19,8 +19,11 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.net.LinkAddress;
+import android.net.QosSession;
 import android.telephony.data.EpsQos;
+import android.telephony.data.NrQos;
 import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
 import android.telephony.data.QosBearerFilter;
 import android.telephony.data.QosBearerSession;
 
@@ -179,25 +182,41 @@
             @NonNull final QosBearerSession session, @NonNull IFilter filter) {
         QosBearerFilter qosBearerFilter = getMatchingQosBearerFilter(session, filter);
         List<InetSocketAddress> remoteAddresses = new ArrayList<>();
-        EpsQos qos = (EpsQos) session.getQos();
         if(qosBearerFilter.getRemoteAddresses().size() > 0) {
             remoteAddresses.add(
                   new InetSocketAddress(qosBearerFilter.getRemoteAddresses().get(0).getAddress(),
                   qosBearerFilter.getRemotePortRange().getStart()));
         }
-        EpsBearerQosSessionAttributes epsBearerAttr =
-                new EpsBearerQosSessionAttributes(qos.getQci(),
-                        qos.getUplinkBandwidth().getMaxBitrateKbps(),
-                        qos.getDownlinkBandwidth().getMaxBitrateKbps(),
-                        qos.getDownlinkBandwidth().getGuaranteedBitrateKbps(),
-                        qos.getUplinkBandwidth().getGuaranteedBitrateKbps(),
-                        remoteAddresses);
-        mDcNetworkAgent.notifyQosSessionAvailable(
-                callbackId, session.getQosBearerSessionId(), epsBearerAttr);
+
+        if (session.getQos() instanceof EpsQos) {
+            EpsQos qos = (EpsQos) session.getQos();
+            EpsBearerQosSessionAttributes epsBearerAttr =
+                    new EpsBearerQosSessionAttributes(qos.getQci(),
+                            qos.getUplinkBandwidth().getMaxBitrateKbps(),
+                            qos.getDownlinkBandwidth().getMaxBitrateKbps(),
+                            qos.getDownlinkBandwidth().getGuaranteedBitrateKbps(),
+                            qos.getUplinkBandwidth().getGuaranteedBitrateKbps(),
+                            remoteAddresses);
+            mDcNetworkAgent.notifyQosSessionAvailable(
+                    callbackId, session.getQosBearerSessionId(), epsBearerAttr);
+        } else {
+            NrQos qos = (NrQos) session.getQos();
+            NrQosSessionAttributes nrQosAttr =
+                    new NrQosSessionAttributes(qos.get5Qi(), qos.getQfi(),
+                            qos.getUplinkBandwidth().getMaxBitrateKbps(),
+                            qos.getDownlinkBandwidth().getMaxBitrateKbps(),
+                            qos.getDownlinkBandwidth().getGuaranteedBitrateKbps(),
+                            qos.getUplinkBandwidth().getGuaranteedBitrateKbps(),
+                            qos.getAveragingWindow(), remoteAddresses);
+            mDcNetworkAgent.notifyQosSessionAvailable(
+                    callbackId, session.getQosBearerSessionId(), nrQosAttr);
+        }
     }
 
     private void sendSessionLost(final int callbackId, @NonNull final QosBearerSession session) {
-        mDcNetworkAgent.notifyQosSessionLost(callbackId, session.getQosBearerSessionId());
+        mDcNetworkAgent.notifyQosSessionLost(callbackId, session.getQosBearerSessionId(),
+                session.getQos() instanceof EpsQos ?
+                QosSession.TYPE_EPS_BEARER : QosSession.TYPE_NR_BEARER);
     }
 
     public interface IFilter {
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index 6228619..d7aad9f 100755
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -3797,6 +3797,15 @@
             }
             cqm.saveCallQuality(callQuality);
             mCallQualityMetrics.put(callId, cqm);
+
+            ImsPhoneConnection conn = findConnection(imsCall);
+            if (conn != null) {
+                Bundle report = new Bundle();
+                report.putParcelable(android.telecom.Connection.EXTRA_CALL_QUALITY_REPORT,
+                        callQuality);
+                conn.onConnectionEvent(android.telecom.Connection.EVENT_CALL_QUALITY_REPORT,
+                        report);
+            }
         }
 
         /**
@@ -4295,7 +4304,7 @@
         // the only thing we can do here is splitting the usage into half rx and half tx.
         // Uid -1 indicates this is for the overall device data usage.
         vtDataUsageSnapshot.combineValues(new NetworkStats.Entry(
-                NetworkStats.IFACE_VT, -1, NetworkStats.SET_FOREGROUND,
+                getVtInterface(), -1, NetworkStats.SET_FOREGROUND,
                 NetworkStats.TAG_NONE, NetworkStats.METERED_YES, isRoaming,
                 NetworkStats.DEFAULT_NETWORK_YES, delta / 2, 0, delta / 2, 0, 0));
         mVtDataUsageSnapshot = vtDataUsageSnapshot;
@@ -4318,12 +4327,17 @@
         // Since the modem only reports the total vt data usage rather than rx/tx separately,
         // the only thing we can do here is splitting the usage into half rx and half tx.
         vtDataUsageUidSnapshot.combineValues(new NetworkStats.Entry(
-                NetworkStats.IFACE_VT, mDefaultDialerUid.get(),
+                getVtInterface(), mDefaultDialerUid.get(),
                 NetworkStats.SET_FOREGROUND, NetworkStats.TAG_NONE, NetworkStats.METERED_YES,
                 isRoaming, NetworkStats.DEFAULT_NETWORK_YES, delta / 2, 0, delta / 2, 0, 0));
         mVtDataUsageUidSnapshot = vtDataUsageUidSnapshot;
     }
 
+    @VisibleForTesting(visibility = PRIVATE)
+    public String getVtInterface() {
+        return NetworkStats.IFACE_VT + mPhone.getSubId();
+    }
+
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     @Override
     protected void log(String msg) {
diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
index a6eaa03..d1e7ad2 100644
--- a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
+++ b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
@@ -275,7 +275,7 @@
      * @param pw Print writer
      * @param args Arguments
      */
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (args != null && args.length > 0) {
             boolean reset = true;
             if (args.length > 1 && "--keep".equals(args[1])) {
@@ -488,10 +488,12 @@
             pw.print("Start time in minutes: " + callSession.startTimeMinutes);
             pw.print(", phone: " + callSession.phoneId);
             if (callSession.eventsDropped) {
-                pw.println(" Events dropped: " + callSession.eventsDropped);
+                pw.println(", events dropped: " + callSession.eventsDropped);
+            } else {
+                pw.println("");
             }
 
-            pw.println(" Events: ");
+            pw.println("Events: ");
             pw.increaseIndent();
             for (TelephonyCallSession.Event event : callSession.events) {
                 pw.print(event.delay);
@@ -544,9 +546,16 @@
             for (SmsSession.Event event : smsSession.events) {
                 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_RECEIVED) {
+                if (event.type == SmsSession.Event.Type.RIL_SERVICE_STATE_CHANGED) {
+                    pw.println(smsSessionEventToString(event.type)
+                            + "(" + "Data RAT " + event.serviceState.dataRat
+                            + " Voice RAT " + event.serviceState.voiceRat
+                            + " Channel Number " + event.serviceState.channelNumber
+                            + " NR Frequency Range " + event.serviceState.nrFrequencyRange
+                            + " NR State " + event.serviceState.nrState
+                            + ")");
+                } else if (event.type == SmsSession.Event.Type.SMS_RECEIVED) {
+                    pw.println(smsSessionEventToString(event.type));
                     pw.increaseIndent();
                     switch (event.smsType) {
                         case SmsSession.Event.SmsType.SMS_TYPE_SMS_PP:
@@ -570,6 +579,7 @@
                     pw.decreaseIndent();
                 } else if (event.type == SmsSession.Event.Type.SMS_SEND
                         || event.type == SmsSession.Event.Type.SMS_SEND_RESULT) {
+                    pw.println(smsSessionEventToString(event.type));
                     pw.increaseIndent();
                     pw.println("ReqId=" + event.rilRequestId);
                     pw.println("E=" + event.errorCode);
@@ -577,6 +587,7 @@
                     pw.println("ImsE=" + event.imsError);
                     pw.decreaseIndent();
                 } else if (event.type == SmsSession.Event.Type.INCOMPLETE_SMS_RECEIVED) {
+                    pw.println(smsSessionEventToString(event.type));
                     pw.increaseIndent();
                     pw.println("Received: " + event.incompleteSms.receivedParts + "/"
                             + event.incompleteSms.totalParts);
@@ -1082,7 +1093,7 @@
         TelephonyServiceState serviceState = mLastServiceState.get(phoneId);
         if (serviceState != null) {
             smsSession.addEvent(smsSession.startElapsedTimeMs, new SmsSessionEventBuilder(
-                    TelephonyCallSession.Event.Type.RIL_SERVICE_STATE_CHANGED)
+                    SmsSession.Event.Type.RIL_SERVICE_STATE_CHANGED)
                     .setServiceState(serviceState));
         }
 
@@ -1136,7 +1147,7 @@
         }
     }
 
-    private SmsSession finishSmsSession(InProgressSmsSession inProgressSmsSession) {
+    private synchronized SmsSession finishSmsSession(InProgressSmsSession inProgressSmsSession) {
         SmsSession smsSession = new SmsSession();
         smsSession.events = new SmsSession.Event[inProgressSmsSession.events.size()];
         inProgressSmsSession.events.toArray(smsSession.events);
@@ -1818,12 +1829,10 @@
      */
     private synchronized void writeOnSmsSolicitedResponse(int phoneId, int rilSerial, int rilError,
                                                           SmsResponse response) {
-
         InProgressSmsSession smsSession = mInProgressSmsSessions.get(phoneId);
         if (smsSession == null) {
             Rlog.e(TAG, "SMS session is missing");
         } else {
-
             int errorCode = SmsResponse.NO_ERROR_CODE;
             long messageId = 0L;
             if (response != null) {
@@ -2441,7 +2450,9 @@
         int smsTech = getSmsTech(smsSource, smsFormat == SmsSession.Event.Format.SMS_FORMAT_3GPP2);
 
         InProgressSmsSession smsSession = startNewSmsSession(phoneId);
-        for (long time : timestamps) {
+
+        long startElapsedTimeMillis = SystemClock.elapsedRealtime();
+        for (int i = 0; i < timestamps.length; i++) {
             SmsSessionEventBuilder eventBuilder =
                     new SmsSessionEventBuilder(SmsSession.Event.Type.SMS_RECEIVED)
                         .setFormat(smsFormat)
@@ -2450,7 +2461,8 @@
                         .setSmsType(type)
                         .setBlocked(blocked)
                         .setMessageId(messageId);
-            smsSession.addEvent(time, eventBuilder);
+            long interval = (i > 0) ? timestamps[i] - timestamps[i - 1] : 0;
+            smsSession.addEvent(startElapsedTimeMillis + interval, eventBuilder);
         }
         finishSmsSession(smsSession);
     }
diff --git a/src/java/com/android/internal/telephony/vendor/VendorPhoneSwitcher.java b/src/java/com/android/internal/telephony/vendor/VendorPhoneSwitcher.java
index 48103e2..33de2d1 100644
--- a/src/java/com/android/internal/telephony/vendor/VendorPhoneSwitcher.java
+++ b/src/java/com/android/internal/telephony/vendor/VendorPhoneSwitcher.java
@@ -19,7 +19,6 @@
 import static android.telephony.SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
 import static android.telephony.SubscriptionManager.INVALID_PHONE_INDEX;
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-import static android.telephony.TelephonyManager.RADIO_POWER_UNAVAILABLE;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -30,35 +29,24 @@
 import android.os.AsyncResult;
 import android.os.Looper;
 import android.os.Message;
-import android.os.Registrant;
 import android.os.SystemProperties;
-import android.telephony.data.ApnSetting;
-import android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
-
-import android.text.TextUtils;
+import android.telephony.data.ApnSetting;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.CallManager;
-import com.android.internal.telephony.Call;
-import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.dataconnection.DcRequest;
-import com.android.internal.telephony.dataconnection.DataEnabledSettings;
 import com.android.internal.telephony.GsmCdmaCall;
-import com.android.internal.telephony.imsphone.ImsPhone;
-import com.android.internal.telephony.imsphone.ImsPhoneCall;
-import com.android.internal.telephony.ITelephonyRegistry;
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.PhoneSwitcher;
-import com.android.internal.telephony.SubscriptionController;
 import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.dataconnection.DataEnabledSettings;
+import com.android.internal.telephony.dataconnection.DcRequest;
+import com.android.internal.telephony.imsphone.ImsPhone;
+import com.android.internal.telephony.imsphone.ImsPhoneCall;
 
-import java.lang.Integer;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -382,8 +370,7 @@
     /* Determine the phone id on which PS attach needs to be done
      */
     protected int phoneIdForRequest(NetworkRequest netRequest, int apnType) {
-        int subId = getSubIdFromNetworkSpecifier(netRequest.networkCapabilities
-                .getNetworkSpecifier());
+        int subId = getSubIdFromNetworkSpecifier(netRequest.getNetworkSpecifier());
 
         if (subId == DEFAULT_SUBSCRIPTION_ID) return mPreferredDataPhoneId;
         if (subId == INVALID_SUBSCRIPTION_ID) return INVALID_PHONE_INDEX;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java
index 3ff9995..17d9576 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java
@@ -32,8 +32,10 @@
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.NetworkService;
 import android.telephony.NetworkServiceCallback;
+import android.telephony.NrVopsSupportInfo;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
+import android.telephony.VopsSupportInfo;
 import android.test.suitebuilder.annotation.MediumTest;
 
 import com.android.internal.R;
@@ -156,7 +158,7 @@
             assertTrue(false);
         }
 
-        LteVopsSupportInfo lteVopsSupportInfo =
+        VopsSupportInfo lteVopsSupportInfo =
                 new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE,
                         LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE);
 
@@ -173,4 +175,276 @@
             assertTrue(false);
         }
     }
+
+    @Test
+    @MediumTest
+    public void testGetNetworkRegistrationInfoV1_5() {
+        // common parameters
+        int regState = NetworkRegistrationInfo.REGISTRATION_STATE_HOME;
+        int radioTech = ServiceState.RIL_RADIO_TECHNOLOGY_LTE;
+        int reasonForDenial = 0;
+
+        // voice services
+        List<Integer> availableVoiceServices = new ArrayList<>(Arrays.asList(new Integer[] {
+                NetworkRegistrationInfo.SERVICE_TYPE_VOICE,
+                NetworkRegistrationInfo.SERVICE_TYPE_SMS,
+                NetworkRegistrationInfo.SERVICE_TYPE_VIDEO
+        }));
+
+        // Default value per 24.008
+        int maxDataCalls = 16;
+        // data service
+        List<Integer> availableDataServices = Arrays.asList(
+                NetworkRegistrationInfo.SERVICE_TYPE_DATA);
+
+        // ENDC parameters
+        boolean isEndcAvailable = true;
+        boolean isDcNrRestricted = false;
+        boolean isNrAvailable = true;
+
+        // LTE VoPS parameters
+        boolean isVopsSupported = true;
+        boolean isEmcBearerSupported = true;
+
+        android.hardware.radio.V1_5.RegStateResult regResult =
+                new android.hardware.radio.V1_5.RegStateResult();
+
+        regResult.regState = regState;
+        regResult.rat = radioTech;
+        regResult.reasonForDenial = reasonForDenial;
+
+        android.hardware.radio.V1_5.RegStateResult.AccessTechnologySpecificInfo
+                .EutranRegistrationInfo eutranInfo = new android.hardware.radio.V1_5
+                .RegStateResult.AccessTechnologySpecificInfo.EutranRegistrationInfo();
+        eutranInfo.lteVopsInfo.isVopsSupported = isVopsSupported;
+        eutranInfo.lteVopsInfo.isEmcBearerSupported = isEmcBearerSupported;
+        eutranInfo.nrIndicators.isEndcAvailable = isEndcAvailable;
+        eutranInfo.nrIndicators.isDcNrRestricted = isDcNrRestricted;
+        eutranInfo.nrIndicators.isNrAvailable = isNrAvailable;
+        regResult.accessTechnologySpecificInfo.eutranInfo(eutranInfo);
+
+        VopsSupportInfo vops = new LteVopsSupportInfo(
+                LteVopsSupportInfo.LTE_STATUS_SUPPORTED, LteVopsSupportInfo.LTE_STATUS_SUPPORTED);
+
+        mSimulatedCommands.setVoiceRegStateResult(regResult);
+        mSimulatedCommands.setDataRegStateResult(regResult);
+
+        // test voice registration state
+        try {
+            mBinder.requestNetworkRegistrationInfo(0, NetworkRegistrationInfo.DOMAIN_CS, mCallback);
+        } catch (RemoteException e) {
+            assertTrue(false);
+        }
+
+        NetworkRegistrationInfo expectedState = new NetworkRegistrationInfo(
+                NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+                regState, ServiceState.rilRadioTechnologyToNetworkType(radioTech), reasonForDenial,
+                false, availableVoiceServices, null, "", false, 0, 0, 0);
+
+        try {
+            verify(mCallback, timeout(1000).times(1)).onRequestNetworkRegistrationInfoComplete(
+                    eq(NetworkServiceCallback.RESULT_SUCCESS), eq(expectedState));
+        } catch (RemoteException e) {
+            assertTrue(false);
+        }
+
+        // test data registration state
+        try {
+            mBinder.requestNetworkRegistrationInfo(0, NetworkRegistrationInfo.DOMAIN_PS, mCallback);
+        } catch (RemoteException e) {
+            assertTrue(false);
+        }
+
+        expectedState = new NetworkRegistrationInfo(
+                NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+                regState, ServiceState.rilRadioTechnologyToNetworkType(radioTech), reasonForDenial,
+                false, availableDataServices, null, "", maxDataCalls, isDcNrRestricted,
+                isNrAvailable, isEndcAvailable, vops);
+
+        try {
+            verify(mCallback, timeout(1000).times(1)).onRequestNetworkRegistrationInfoComplete(
+                    eq(NetworkServiceCallback.RESULT_SUCCESS), eq(expectedState));
+        } catch (RemoteException e) {
+            assertTrue(false);
+        }
+    }
+
+    @Test
+    @MediumTest
+    public void testGetNetworkRegistrationInfoV1_6WithLte() {
+        // common parameters
+        int regState = NetworkRegistrationInfo.REGISTRATION_STATE_HOME;
+        int radioTech = ServiceState.RIL_RADIO_TECHNOLOGY_LTE;
+        int reasonForDenial = 0;
+
+        // voice services
+        List<Integer> availableVoiceServices = new ArrayList<>(Arrays.asList(new Integer[] {
+                NetworkRegistrationInfo.SERVICE_TYPE_VOICE,
+                NetworkRegistrationInfo.SERVICE_TYPE_SMS,
+                NetworkRegistrationInfo.SERVICE_TYPE_VIDEO
+        }));
+
+        // Default value per 24.008
+        int maxDataCalls = 16;
+        // data service
+        List<Integer> availableDataServices = Arrays.asList(
+                NetworkRegistrationInfo.SERVICE_TYPE_DATA);
+
+        // ENDC parameters
+        boolean isEndcAvailable = true;
+        boolean isDcNrRestricted = false;
+        boolean isNrAvailable = true;
+
+        // LTE VoPS parameters
+        boolean isVopsSupported = true;
+        boolean isEmcBearerSupported = true;
+
+        android.hardware.radio.V1_6.RegStateResult regResult =
+                new android.hardware.radio.V1_6.RegStateResult();
+
+        regResult.regState = regState;
+        regResult.rat = radioTech;
+        regResult.reasonForDenial = reasonForDenial;
+
+        android.hardware.radio.V1_5.RegStateResult.AccessTechnologySpecificInfo
+                .EutranRegistrationInfo eutranInfo = new android.hardware.radio.V1_5
+                .RegStateResult.AccessTechnologySpecificInfo.EutranRegistrationInfo();
+        eutranInfo.lteVopsInfo.isVopsSupported = isVopsSupported;
+        eutranInfo.lteVopsInfo.isEmcBearerSupported = isEmcBearerSupported;
+        eutranInfo.nrIndicators.isEndcAvailable = isEndcAvailable;
+        eutranInfo.nrIndicators.isDcNrRestricted = isDcNrRestricted;
+        eutranInfo.nrIndicators.isNrAvailable = isNrAvailable;
+        regResult.accessTechnologySpecificInfo.eutranInfo(eutranInfo);
+
+        VopsSupportInfo vops = new LteVopsSupportInfo(
+                LteVopsSupportInfo.LTE_STATUS_SUPPORTED, LteVopsSupportInfo.LTE_STATUS_SUPPORTED);
+
+        mSimulatedCommands.setVoiceRegStateResult(regResult);
+        mSimulatedCommands.setDataRegStateResult(regResult);
+
+        // test voice registration state
+        try {
+            mBinder.requestNetworkRegistrationInfo(0, NetworkRegistrationInfo.DOMAIN_CS, mCallback);
+        } catch (RemoteException e) {
+            assertTrue(false);
+        }
+
+        NetworkRegistrationInfo expectedState = new NetworkRegistrationInfo(
+                NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+                regState, ServiceState.rilRadioTechnologyToNetworkType(radioTech), reasonForDenial,
+                false, availableVoiceServices, null, "", false, 0, 0, 0);
+
+        try {
+            verify(mCallback, timeout(1000).times(1)).onRequestNetworkRegistrationInfoComplete(
+                    eq(NetworkServiceCallback.RESULT_SUCCESS), eq(expectedState));
+        } catch (RemoteException e) {
+            assertTrue(false);
+        }
+
+        // test data registration state
+        try {
+            mBinder.requestNetworkRegistrationInfo(0, NetworkRegistrationInfo.DOMAIN_PS, mCallback);
+        } catch (RemoteException e) {
+            assertTrue(false);
+        }
+
+        expectedState = new NetworkRegistrationInfo(
+                NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+                regState, ServiceState.rilRadioTechnologyToNetworkType(radioTech), reasonForDenial,
+                false, availableDataServices, null, "", maxDataCalls, isDcNrRestricted,
+                isNrAvailable, isEndcAvailable, vops);
+
+        try {
+            verify(mCallback, timeout(1000).times(1)).onRequestNetworkRegistrationInfoComplete(
+                    eq(NetworkServiceCallback.RESULT_SUCCESS), eq(expectedState));
+        } catch (RemoteException e) {
+            assertTrue(false);
+        }
+    }
+
+
+    @Test
+    @MediumTest
+    public void testGetNetworkRegistrationInfoV1_6WithNr() {
+        // common parameters
+        int regState = NetworkRegistrationInfo.REGISTRATION_STATE_HOME;
+        int radioTech = ServiceState.RIL_RADIO_TECHNOLOGY_NR;
+        int reasonForDenial = 0;
+
+        // voice services
+        List<Integer> availableVoiceServices = new ArrayList<>(Arrays.asList(new Integer[] {
+                NetworkRegistrationInfo.SERVICE_TYPE_VOICE,
+                NetworkRegistrationInfo.SERVICE_TYPE_SMS,
+                NetworkRegistrationInfo.SERVICE_TYPE_VIDEO
+        }));
+
+        // Default value per 24.008
+        int maxDataCalls = 16;
+        // data service
+        List<Integer> availableDataServices = Arrays.asList(
+                NetworkRegistrationInfo.SERVICE_TYPE_DATA);
+
+        // NR VoPS parameters
+        byte vopsSupported = android.hardware.radio.V1_6.VopsIndicator.VOPS_OVER_3GPP;
+        byte emcSupported = android.hardware.radio.V1_6.EmcIndicator.EMC_NR_CONNECTED_TO_5GCN;
+        byte emfSupported = android.hardware.radio.V1_6.EmfIndicator.EMF_NR_CONNECTED_TO_5GCN;
+
+        android.hardware.radio.V1_6.RegStateResult regResult =
+                new android.hardware.radio.V1_6.RegStateResult();
+
+        regResult.regState = regState;
+        regResult.rat = radioTech;
+        regResult.reasonForDenial = reasonForDenial;
+
+
+        android.hardware.radio.V1_6.RegStateResult.AccessTechnologySpecificInfo
+                .NgranRegistrationInfo ngranInfo = new android.hardware.radio.V1_6
+                .RegStateResult.AccessTechnologySpecificInfo.NgranRegistrationInfo();
+        ngranInfo.nrVopsInfo.vopsSupported = vopsSupported;
+        ngranInfo.nrVopsInfo.emcSupported = emcSupported;
+        ngranInfo.nrVopsInfo.emfSupported = emfSupported;
+        regResult.accessTechnologySpecificInfo.ngranInfo(ngranInfo);
+
+        VopsSupportInfo vops = new NrVopsSupportInfo(vopsSupported, emcSupported, emfSupported);
+        mSimulatedCommands.setVoiceRegStateResult(regResult);
+        mSimulatedCommands.setDataRegStateResult(regResult);
+
+        // test voice registration state
+        try {
+            mBinder.requestNetworkRegistrationInfo(0, NetworkRegistrationInfo.DOMAIN_CS, mCallback);
+        } catch (RemoteException e) {
+            assertTrue(false);
+        }
+
+        NetworkRegistrationInfo expectedState = new NetworkRegistrationInfo(
+                NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+                regState, ServiceState.rilRadioTechnologyToNetworkType(radioTech), reasonForDenial,
+                false, availableVoiceServices, null, "", false, 0, 0, 0);
+
+        try {
+            verify(mCallback, timeout(1000).times(1)).onRequestNetworkRegistrationInfoComplete(
+                    eq(NetworkServiceCallback.RESULT_SUCCESS), eq(expectedState));
+        } catch (RemoteException e) {
+            assertTrue(false);
+        }
+
+        // test data registration state
+        try {
+            mBinder.requestNetworkRegistrationInfo(0, NetworkRegistrationInfo.DOMAIN_PS, mCallback);
+        } catch (RemoteException e) {
+            assertTrue(false);
+        }
+
+        expectedState = new NetworkRegistrationInfo(
+                NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+                regState, ServiceState.rilRadioTechnologyToNetworkType(radioTech), reasonForDenial,
+                false, availableDataServices, null, "", maxDataCalls, false, false, false, vops);
+
+        try {
+            verify(mCallback, timeout(1000).times(1)).onRequestNetworkRegistrationInfoComplete(
+                    eq(NetworkServiceCallback.RESULT_SUCCESS), eq(expectedState));
+        } catch (RemoteException e) {
+            assertTrue(false);
+        }
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkValidatorTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkValidatorTest.java
index 74ced90..2c1e18b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkValidatorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkValidatorTest.java
@@ -57,9 +57,9 @@
 public class CellularNetworkValidatorTest extends TelephonyTest {
     private CellularNetworkValidator mValidatorUT;
     private static final PhoneCapability CAPABILITY_WITH_VALIDATION_SUPPORTED =
-            new PhoneCapability(1, 1, null, true, PhoneCapability.DEVICE_NR_CAPABILITY_NONE);
+            new PhoneCapability(1, 1, null, true, new int[0]);
     private static final PhoneCapability CAPABILITY_WITHOUT_VALIDATION_SUPPORTED =
-            new PhoneCapability(1, 1, null, false, PhoneCapability.DEVICE_NR_CAPABILITY_NONE);
+            new PhoneCapability(1, 1, null, false, new int[0]);
     private final CellIdentityLte mCellIdentityLte1 = new CellIdentityLte(123, 456, 0, 0, 111);
     private final CellIdentityLte mCellIdentityLte2 = new CellIdentityLte(321, 654, 0, 0, 222);
     @Mock
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
index f2cb869..b96056a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
@@ -279,6 +279,8 @@
                     return TestApplication.getAppContext().getSystemService(name);
                 case Context.POWER_WHITELIST_MANAGER:
                     return mPowerWhitelistManager;
+                case Context.LOCATION_SERVICE:
+                    return mLocationManager;
                 default:
                     return null;
             }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
index 826594d..f2624af 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
@@ -116,7 +116,8 @@
                     + Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED + " INTEGER DEFAULT 0, "
                     + Telephony.SimInfo.COLUMN_RCS_CONFIG + " BLOB,"
                     + Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS + " TEXT,"
-                    + Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING + " INTEGER DEFAULT 0"
+                    + Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING + " INTEGER DEFAULT 0,"
+                    + Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS + "TEXT"
                     + ");";
         }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneCapabilityTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneCapabilityTest.java
index da986e4..2410625 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneCapabilityTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneCapabilityTest.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.telephony;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 
@@ -38,21 +39,22 @@
         ModemInfo modemInfo = new ModemInfo(1, 2, true, false);
         List<ModemInfo> logicalModemList = new ArrayList<>();
         logicalModemList.add(modemInfo);
-        int deviceNrCapability = PhoneCapability.DEVICE_NR_CAPABILITY_NONE;
+        int[] deviceNrCapabilities = new int[]{PhoneCapability.DEVICE_NR_CAPABILITY_SA};
 
         PhoneCapability capability = new PhoneCapability(maxActiveVoiceCalls, maxActiveData,
-                logicalModemList, false, deviceNrCapability);
+                logicalModemList, false, deviceNrCapabilities);
 
-        assertEquals(maxActiveVoiceCalls, capability.getMaxActivePacketSwitchedVoiceCalls());
-        assertEquals(maxActiveData, capability.getMaxActiveInternetData());
+        assertEquals(maxActiveVoiceCalls, capability.getMaxActiveVoiceSubscriptions());
+        assertEquals(maxActiveData, capability.getMaxActiveDataSubscriptions());
         assertEquals(1, capability.getLogicalModemList().size());
         assertEquals(modemInfo, capability.getLogicalModemList().get(0));
-        assertEquals(deviceNrCapability, capability.getDeviceNrCapabilityBitmask());
+        assertArrayEquals(deviceNrCapabilities, capability.getDeviceNrCapabilities());
+
         PhoneCapability toCompare = new PhoneCapability(maxActiveVoiceCalls + 1, maxActiveData - 1,
-                logicalModemList, false, PhoneCapability.DEVICE_NR_CAPABILITY_NSA);
+                logicalModemList, false, deviceNrCapabilities);
         assertEquals(capability,
                 new PhoneCapability(maxActiveVoiceCalls, maxActiveData, logicalModemList,
-                        false, deviceNrCapability));
+                        false, deviceNrCapabilities));
         assertNotEquals(capability, toCompare);
     }
 
@@ -64,21 +66,21 @@
         ModemInfo modemInfo = new ModemInfo(1, 2, true, false);
         List<ModemInfo> logicalModemList = new ArrayList<>();
         logicalModemList.add(modemInfo);
-        int deviceNrCapability = PhoneCapability.DEVICE_NR_CAPABILITY_NONE;
+        int[] deviceNrCapabilities = new int[]{};
 
         PhoneCapability capability = new PhoneCapability(maxActiveVoiceCalls, maxActiveData,
-                logicalModemList, false, PhoneCapability.DEVICE_NR_CAPABILITY_NONE);
+                logicalModemList, false, deviceNrCapabilities);
 
         Parcel parcel = Parcel.obtain();
         capability.writeToParcel(parcel, 0);
         parcel.setDataPosition(0);
         PhoneCapability toCompare = PhoneCapability.CREATOR.createFromParcel(parcel);
 
-        assertEquals(maxActiveVoiceCalls, toCompare.getMaxActivePacketSwitchedVoiceCalls());
-        assertEquals(maxActiveData, toCompare.getMaxActiveInternetData());
+        assertEquals(maxActiveVoiceCalls, toCompare.getMaxActiveVoiceSubscriptions());
+        assertEquals(maxActiveData, toCompare.getMaxActiveDataSubscriptions());
         assertEquals(1, toCompare.getLogicalModemList().size());
         assertEquals(modemInfo, toCompare.getLogicalModemList().get(0));
-        assertEquals(deviceNrCapability, toCompare.getDeviceNrCapabilityBitmask());
+        assertArrayEquals(deviceNrCapabilities, toCompare.getDeviceNrCapabilities());
         assertEquals(capability, toCompare);
     }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
index 2ca5a27..3485f49 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
@@ -123,8 +123,7 @@
     public void setUp() throws Exception {
         super.setUp(getClass().getSimpleName());
 
-        PhoneCapability phoneCapability = new PhoneCapability(1, 1, null, false,
-                PhoneCapability.DEVICE_NR_CAPABILITY_NONE);
+        PhoneCapability phoneCapability = new PhoneCapability(1, 1, null, false, new int[0]);
         doReturn(phoneCapability).when(mPhoneConfigurationManager).getCurrentPhoneCapability();
 
         doReturn(Call.State.ACTIVE).when(mActiveCall).getState();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
index c495e72..7c81bda 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
@@ -43,6 +43,7 @@
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_IMSI;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_RADIO_CAPABILITY;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SIM_STATUS;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SLICING_CONFIG;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SMSC_ADDRESS;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_UICC_APPLICATIONS_ENABLEMENT;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP;
@@ -2821,4 +2822,18 @@
         mRILUnderTest.setCompatVersion(testRequest, RIL.RADIO_HAL_VERSION_1_5);
         assertEquals(RIL.RADIO_HAL_VERSION_1_3, mRILUnderTest.getCompatVersion(testRequest));
     }
+
+    @FlakyTest
+    @Test
+    public void testGetSlicingConfig() throws Exception {
+        // Use Radio HAL v1.6
+        try {
+            replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV16);
+        } catch (Exception e) {
+        }
+        mRILUnderTest.getSlicingConfig(obtainMessage());
+        verify(mRadioProxy).getSlicingConfig(mSerialNumberCaptor.capture());
+        verifyRILResponse_1_6(
+                mRILUnderTest, mSerialNumberCaptor.getValue(), RIL_REQUEST_GET_SLICING_CONFIG);
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RadioConfigResponseTest.java b/tests/telephonytests/src/com/android/internal/telephony/RadioConfigResponseTest.java
index 0e2e983..a346ece 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/RadioConfigResponseTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/RadioConfigResponseTest.java
@@ -52,6 +52,10 @@
         assertFalse(
                 caps.contains(
                         TelephonyManager.CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE));
+        assertFalse(
+                caps.contains(TelephonyManager.CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING));
+        assertFalse(
+                caps.contains(TelephonyManager.CAPABILITY_SLICING_CONFIG_SUPPORTED));
     }
 
     @Test
@@ -64,6 +68,10 @@
         assertFalse(
                 caps.contains(
                         TelephonyManager.CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE));
+        assertFalse(
+                caps.contains(TelephonyManager.CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING));
+        assertFalse(
+                caps.contains(TelephonyManager.CAPABILITY_SLICING_CONFIG_SUPPORTED));
     }
 
     @Test
@@ -76,5 +84,9 @@
         assertTrue(
                 caps.contains(
                         TelephonyManager.CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE));
+        assertTrue(
+                caps.contains(TelephonyManager.CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING));
+        assertTrue(
+                caps.contains(TelephonyManager.CAPABILITY_SLICING_CONFIG_SUPPORTED));
     }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RadioInterfaceCapabilityControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/RadioInterfaceCapabilityControllerTest.java
index efd9280..e8e1124 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/RadioInterfaceCapabilityControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/RadioInterfaceCapabilityControllerTest.java
@@ -29,6 +29,7 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -52,6 +53,11 @@
         super.setUp(getClass().getSimpleName());
     }
 
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
     @Test
     public void testRadioInterfaceCapabilities() {
         final RadioInterfaceCapabilityController capabilities =
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
index b7a4ba0..0bef358 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
@@ -82,6 +82,7 @@
 import android.telephony.LteVopsSupportInfo;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.NetworkService;
+import android.telephony.NrVopsSupportInfo;
 import android.telephony.PhysicalChannelConfig;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
@@ -2372,7 +2373,7 @@
 
     @Test
     @SmallTest
-    public void testOnVopsInfoChanged() {
+    public void testOnLteVopsInfoChanged() {
         ServiceState ss = new ServiceState();
         ss.setVoiceRegState(ServiceState.STATE_IN_SERVICE);
         ss.setDataRegState(ServiceState.STATE_IN_SERVICE);
@@ -2433,6 +2434,70 @@
 
     @Test
     @SmallTest
+    public void testOnNrVopsInfoChanged() {
+        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, new int[] {1, 2}, 5000, "001", "01", "test",
+                        "tst", Collections.emptyList(), null);
+        NrVopsSupportInfo nrVopsSupportInfo = new NrVopsSupportInfo(
+                NrVopsSupportInfo.NR_STATUS_VOPS_NOT_SUPPORTED,
+                NrVopsSupportInfo.NR_STATUS_EMC_NOT_SUPPORTED,
+                NrVopsSupportInfo.NR_STATUS_EMF_NOT_SUPPORTED);
+
+        NetworkRegistrationInfo dataResult = new NetworkRegistrationInfo(
+                NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, TelephonyManager.NETWORK_TYPE_NR,
+                0, false, null, cellId, "00101", 1, false, false, false, nrVopsSupportInfo);
+        sst.mPollingContext[0] = 2;
+
+        sst.sendMessage(sst.obtainMessage(
+                ServiceStateTracker.EVENT_POLL_STATE_PS_CELLULAR_REGISTRATION,
+                new AsyncResult(sst.mPollingContext, dataResult, null)));
+        NetworkRegistrationInfo voiceResult = new NetworkRegistrationInfo(
+                NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME,
+                TelephonyManager.NETWORK_TYPE_NR, 0,
+                false, null, cellId, "00101", false, 0, 0, 0);
+        sst.sendMessage(sst.obtainMessage(
+                ServiceStateTracker.EVENT_POLL_STATE_CS_CELLULAR_REGISTRATION,
+                new AsyncResult(sst.mPollingContext, voiceResult, null)));
+
+        waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
+        assertEquals(ServiceState.STATE_IN_SERVICE, sst.getCurrentDataConnectionState());
+        NetworkRegistrationInfo sSnetworkRegistrationInfo =
+                sst.mSS.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
+                        AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+        assertEquals(nrVopsSupportInfo,
+                sSnetworkRegistrationInfo.getDataSpecificInfo().getVopsSupportInfo());
+
+        nrVopsSupportInfo = new NrVopsSupportInfo(
+                NrVopsSupportInfo.NR_STATUS_VOPS_3GPP_SUPPORTED,
+                NrVopsSupportInfo.NR_STATUS_EMC_5GCN_ONLY,
+                NrVopsSupportInfo.NR_STATUS_EMF_5GCN_ONLY);
+        dataResult = new NetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
+                AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME,
+                TelephonyManager.NETWORK_TYPE_NR, 0, false, null, cellId, "00101",
+                1, false, false, false, nrVopsSupportInfo);
+        sst.mPollingContext[0] = 1;
+        sst.sendMessage(sst.obtainMessage(
+                ServiceStateTracker.EVENT_POLL_STATE_PS_CELLULAR_REGISTRATION,
+                new AsyncResult(sst.mPollingContext, dataResult, null)));
+        waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
+
+        sSnetworkRegistrationInfo =
+                sst.mSS.getNetworkRegistrationInfo(2, 1);
+        assertEquals(nrVopsSupportInfo,
+                sSnetworkRegistrationInfo.getDataSpecificInfo().getVopsSupportInfo());
+    }
+
+
+    @Test
+    @SmallTest
     public void testEriLoading() {
         sst.obtainMessage(GsmCdmaPhone.EVENT_CARRIER_CONFIG_CHANGED, null).sendToTarget();
         waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java
index 84cedbd..40fa229 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java
@@ -47,7 +47,6 @@
 import android.telephony.SignalStrength;
 import android.telephony.SignalThresholdInfo;
 import android.telephony.TelephonyManager;
-import android.telephony.data.ApnSetting;
 import android.telephony.data.DataCallResponse;
 import android.telephony.data.DataProfile;
 import android.telephony.data.NetworkSliceInfo;
@@ -164,6 +163,9 @@
     private IccIoResult mIccIoResultForApduLogicalChannel;
     private int mChannelId = IccOpenLogicalChannelResponse.INVALID_CHANNEL;
 
+    private Object mDataRegStateResult;
+    private Object mVoiceRegStateResult;
+
     int mPausedResponseCount;
     ArrayList<Message> mPausedResponses = new ArrayList<Message>();
 
@@ -1002,14 +1004,17 @@
     public void getVoiceRegistrationState(Message result) {
         mGetVoiceRegistrationStateCallCount.incrementAndGet();
 
-        VoiceRegStateResult ret = new VoiceRegStateResult();
-        ret.regState = mVoiceRegState;
-        ret.rat = mVoiceRadioTech;
-        ret.cssSupported = mCssSupported;
-        ret.roamingIndicator = mRoamingIndicator;
-        ret.systemIsInPrl = mSystemIsInPrl;
-        ret.defaultRoamingIndicator = mDefaultRoamingIndicator;
-        ret.reasonForDenial = mReasonForDenial;
+        Object ret = mVoiceRegStateResult;
+        if (ret == null) {
+            ret = new VoiceRegStateResult();
+            ((VoiceRegStateResult) ret).regState = mVoiceRegState;
+            ((VoiceRegStateResult) ret).rat = mVoiceRadioTech;
+            ((VoiceRegStateResult) ret).cssSupported = mCssSupported;
+            ((VoiceRegStateResult) ret).roamingIndicator = mRoamingIndicator;
+            ((VoiceRegStateResult) ret).systemIsInPrl = mSystemIsInPrl;
+            ((VoiceRegStateResult) ret).defaultRoamingIndicator = mDefaultRoamingIndicator;
+            ((VoiceRegStateResult) ret).reasonForDenial = mReasonForDenial;
+        }
 
         resultSuccess(result, ret);
     }
@@ -1030,14 +1035,17 @@
     }
 
     @Override
-    public void getDataRegistrationState (Message result) {
+    public void getDataRegistrationState(Message result) {
         mGetDataRegistrationStateCallCount.incrementAndGet();
 
-        DataRegStateResult ret = new DataRegStateResult();
-        ret.regState = mDataRegState;
-        ret.rat = mDataRadioTech;
-        ret.maxDataCalls = mMaxDataCalls;
-        ret.reasonDataDenied = mReasonForDenial;
+        Object ret = mDataRegStateResult;
+        if (ret == null) {
+            ret = new DataRegStateResult();
+            ((DataRegStateResult) ret).regState = mDataRegState;
+            ((DataRegStateResult) ret).rat = mDataRadioTech;
+            ((DataRegStateResult) ret).maxDataCalls = mMaxDataCalls;
+            ((DataRegStateResult) ret).reasonDataDenied = mReasonForDenial;
+        }
 
         resultSuccess(result, ret);
     }
@@ -1207,14 +1215,6 @@
             }
         }
 
-        // Store different cids to simulate concurrent IMS and default data calls
-        if ((dataProfile.getSupportedApnTypesBitmask() & ApnSetting.TYPE_IMS)
-            == ApnSetting.TYPE_IMS) {
-            mSetupDataCallResult.cid = 0;
-        } else {
-            mSetupDataCallResult.cid = 1;
-        }
-
         DataCallResponse response = RIL.convertDataCallResult(mSetupDataCallResult);
         if (mDcSuccess) {
             resultSuccess(result, response);
@@ -2435,4 +2435,21 @@
         SimulatedCommandsVerifier.getInstance().releasePduSessionId(message, pduSessionId);
         resultSuccess(message, null);
     }
+
+    @Override
+    public void getSlicingConfig(Message result) {
+        SimulatedCommandsVerifier.getInstance().getSlicingConfig(result);
+        resultSuccess(result, null);
+    }
+
+    @VisibleForTesting
+    public void setDataRegStateResult(Object regStateResult) {
+        mDataRegStateResult = regStateResult;
+    }
+
+    @VisibleForTesting
+    public void setVoiceRegStateResult(Object regStateResult) {
+        mVoiceRegStateResult = regStateResult;
+    }
+
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
index 5cfd036..c4d54ff 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
@@ -1492,4 +1492,8 @@
     @Override
     public void releasePduSessionId(Message result, int pduSessionId) {
     }
+
+    @Override
+    public void getSlicingConfig(Message result) {
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SlidingWindowEventCounterTest.java b/tests/telephonytests/src/com/android/internal/telephony/SlidingWindowEventCounterTest.java
index 55a9c86..da8b4c2 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SlidingWindowEventCounterTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SlidingWindowEventCounterTest.java
@@ -21,15 +21,18 @@
 
 import android.os.SystemClock;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class SlidingWindowEventCounterTest extends TelephonyTest {
+@RunWith(AndroidJUnit4.class)
+public class SlidingWindowEventCounterTest {
     long mInitialTime;
 
     @Before
     public void setUp() throws Exception {
-        super.setUp(getClass().getSimpleName());
         mInitialTime = SystemClock.elapsedRealtime();
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
index f9199f7..5b8be32 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
@@ -88,6 +88,7 @@
     private static final String FAKE_ICCID_1 = "89012604200000000000";
     private static final String FAKE_MCC_MNC_1 = "123456";
     private static final String FAKE_MCC_MNC_2 = "456789";
+    private static final int FAKE_PHONE_ID_1 = 0;
 
     private SubscriptionInfoUpdater mUpdater;
     private IccRecords mIccRecord;
@@ -239,17 +240,17 @@
     @SmallTest
     public void testSimNotReady() throws Exception {
         mUpdater.updateInternalIccState(
-                IccCardConstants.INTENT_VALUE_ICC_NOT_READY, null, FAKE_SUB_ID_1);
+                IccCardConstants.INTENT_VALUE_ICC_NOT_READY, null, FAKE_PHONE_ID_1);
 
         processAllMessages();
         assertFalse(mUpdater.isSubInfoInitialized());
         verify(mSubscriptionContent, never()).put(anyString(), any());
         CarrierConfigManager mConfigManager = (CarrierConfigManager)
                 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
-        verify(mConfigManager, never()).updateConfigForPhoneId(eq(FAKE_SUB_ID_1),
+        verify(mConfigManager, never()).updateConfigForPhoneId(eq(FAKE_PHONE_ID_1),
                 eq(IccCardConstants.INTENT_VALUE_ICC_NOT_READY));
-        verify(mSubscriptionController, never()).clearSubInfo();
-        verify(mSubscriptionController, never()).notifySubscriptionInfoChanged();
+        verify(mSubscriptionController).clearSubInfoRecord(FAKE_PHONE_ID_1);
+        verify(mSubscriptionController).notifySubscriptionInfoChanged();
     }
 
     @Test
@@ -259,19 +260,19 @@
         doReturn(true).when(mIccCard).isEmptyProfile();
 
         mUpdater.updateInternalIccState(
-                IccCardConstants.INTENT_VALUE_ICC_NOT_READY, null, FAKE_SUB_ID_1);
+                IccCardConstants.INTENT_VALUE_ICC_NOT_READY, null, FAKE_PHONE_ID_1);
 
         processAllMessages();
         assertTrue(mUpdater.isSubInfoInitialized());
         // Sub info should be cleared and change should be notified.
-        verify(mSubscriptionController).clearSubInfoRecord(eq(FAKE_SUB_ID_1));
+        verify(mSubscriptionController).clearSubInfoRecord(eq(FAKE_PHONE_ID_1));
         verify(mSubscriptionController).notifySubscriptionInfoChanged();
         // No new sub should be added.
         verify(mSubscriptionManager, never()).addSubscriptionInfoRecord(any(), anyInt());
         verify(mSubscriptionContent, never()).put(anyString(), any());
         CarrierConfigManager mConfigManager = (CarrierConfigManager)
                 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
-        verify(mConfigManager).updateConfigForPhoneId(eq(FAKE_SUB_ID_1),
+        verify(mConfigManager).updateConfigForPhoneId(eq(FAKE_PHONE_ID_1),
                 eq(IccCardConstants.INTENT_VALUE_ICC_NOT_READY));
     }
 
@@ -286,24 +287,24 @@
         doReturn(false).when(mSubInfo).areUiccApplicationsEnabled();
 
         mUpdater.updateInternalIccState(
-                IccCardConstants.INTENT_VALUE_ICC_NOT_READY, null, FAKE_SUB_ID_1);
+                IccCardConstants.INTENT_VALUE_ICC_NOT_READY, null, FAKE_PHONE_ID_1);
 
         processAllMessages();
         assertTrue(mUpdater.isSubInfoInitialized());
         // Sub info should be cleared and change should be notified.
-        verify(mSubscriptionController).clearSubInfoRecord(eq(FAKE_SUB_ID_1));
+        verify(mSubscriptionController).clearSubInfoRecord(eq(FAKE_PHONE_ID_1));
         verify(mSubscriptionController).notifySubscriptionInfoChanged();
         // No new sub should be added.
         verify(mSubscriptionManager, never()).addSubscriptionInfoRecord(any(), anyInt());
         verify(mSubscriptionContent, never()).put(anyString(), any());
         CarrierConfigManager mConfigManager = (CarrierConfigManager)
                 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
-        verify(mConfigManager).updateConfigForPhoneId(eq(FAKE_SUB_ID_1),
+        verify(mConfigManager).updateConfigForPhoneId(eq(FAKE_PHONE_ID_1),
                 eq(IccCardConstants.INTENT_VALUE_ICC_NOT_READY));
 
         // When becomes ABSENT, UICC_APPLICATIONS_ENABLED should be reset to true.
         mUpdater.updateInternalIccState(
-                IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, FAKE_SUB_ID_1);
+                IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, FAKE_PHONE_ID_1);
         processAllMessages();
         ArgumentCaptor<ContentValues> valueCapture = ArgumentCaptor.forClass(ContentValues.class);
         verify(mContentProvider).update(eq(SubscriptionManager.CONTENT_URI), valueCapture.capture(),
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java
index 16e61dc..1362b33 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java
@@ -15,6 +15,8 @@
  */
 package com.android.internal.telephony;
 
+import static android.telephony.PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN;
+import static android.telephony.ServiceState.FREQUENCY_RANGE_LOW;
 import static android.telephony.SubscriptionManager.ACTION_DEFAULT_SUBSCRIPTION_CHANGED;
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED;
@@ -23,19 +25,29 @@
 import static android.telephony.TelephonyManager.RADIO_POWER_UNAVAILABLE;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import android.content.Intent;
+import android.content.pm.UserInfo;
 import android.net.LinkProperties;
+import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.Annotation;
+import android.telephony.CellIdentity;
+import android.telephony.CellIdentityGsm;
+import android.telephony.CellLocation;
 import android.telephony.LinkCapacityEstimate;
 import android.telephony.PhoneCapability;
+import android.telephony.PhysicalChannelConfig;
 import android.telephony.PreciseDataConnectionState;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -47,6 +59,8 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.annotation.NonNull;
+
 import com.android.server.TelephonyRegistry;
 
 import org.junit.After;
@@ -56,6 +70,7 @@
 import org.mockito.Mock;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -75,6 +90,9 @@
     private TelephonyDisplayInfo mTelephonyDisplayInfo;
     private int mSrvccState = -1;
     private int mRadioPowerState = RADIO_POWER_UNAVAILABLE;
+    private List<PhysicalChannelConfig> mPhysicalChannelConfigs;
+    private TelephonyRegistry.ConfigurationProvider mMockConfigurationProvider;
+    private CellLocation mCellLocation;
 
     // All events contribute to TelephonyRegistry#isPhoneStatePermissionRequired
     private static final Set<Integer> READ_PHONE_STATE_EVENTS;
@@ -140,7 +158,9 @@
             TelephonyCallback.RadioPowerStateListener,
             TelephonyCallback.PreciseDataConnectionStateListener,
             TelephonyCallback.DisplayInfoListener,
-            TelephonyCallback.LinkCapacityEstimateChangedListener {
+            TelephonyCallback.LinkCapacityEstimateChangedListener,
+            TelephonyCallback.PhysicalChannelConfigListener,
+            TelephonyCallback.CellLocationListener {
         // This class isn't mockable to get invocation counts because the IBinder is null and
         // crashes the TelephonyRegistry. Make a cheesy verify(times()) alternative.
         public AtomicInteger invocationCount = new AtomicInteger(0);
@@ -178,7 +198,17 @@
         @Override
         public void onLinkCapacityEstimateChanged(
                 List<LinkCapacityEstimate> linkCapacityEstimateList) {
-            mLinkCapacityEstimateList =  linkCapacityEstimateList;
+            mLinkCapacityEstimateList = linkCapacityEstimateList;
+        }
+
+        @Override
+        public void onCellLocationChanged(CellLocation location) {
+            mCellLocation = location;
+        }
+
+        @Override
+        public void onPhysicalChannelConfigChanged(@NonNull List<PhysicalChannelConfig> configs) {
+            mPhysicalChannelConfigs = configs;
         }
     }
 
@@ -197,12 +227,13 @@
     @Before
     public void setUp() throws Exception {
         super.setUp("TelephonyRegistryTest");
-        TelephonyRegistry.ConfigurationProvider mockConfigurationProvider =
-                mock(TelephonyRegistry.ConfigurationProvider.class);
-        when(mockConfigurationProvider.getRegistrationLimit()).thenReturn(-1);
-        when(mockConfigurationProvider.isRegistrationLimitEnabledInPlatformCompat(anyInt()))
+        mMockConfigurationProvider = mock(TelephonyRegistry.ConfigurationProvider.class);
+        when(mMockConfigurationProvider.getRegistrationLimit()).thenReturn(-1);
+        when(mMockConfigurationProvider.isRegistrationLimitEnabledInPlatformCompat(anyInt()))
                 .thenReturn(false);
-        mTelephonyRegistry = new TelephonyRegistry(mContext, mockConfigurationProvider);
+        when(mMockConfigurationProvider.isCallStateReadPhoneStateEnforcedInPlatformCompat(
+                anyString(), any())).thenReturn(false);
+        mTelephonyRegistry = new TelephonyRegistry(mContext, mMockConfigurationProvider);
         addTelephonyRegistryService();
         mTelephonyCallback = new TelephonyCallbackWrapper();
         mTelephonyCallback.init(mSimpleExecutor);
@@ -222,8 +253,7 @@
         doReturn(mMockSubInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt());
         doReturn(0/*slotIndex*/).when(mMockSubInfo).getSimSlotIndex();
         // mTelephonyRegistry.listen with notifyNow = true should trigger callback immediately.
-        PhoneCapability phoneCapability = new PhoneCapability(1, 2, null, false,
-                PhoneCapability.DEVICE_NR_CAPABILITY_NONE);
+        PhoneCapability phoneCapability = new PhoneCapability(1, 2, null, false, new int[0]);
         int[] events = {TelephonyCallback.EVENT_PHONE_CAPABILITY_CHANGED};
         mTelephonyRegistry.notifyPhoneCapabilityChanged(phoneCapability);
         mTelephonyRegistry.listenWithEventList(0, mContext.getOpPackageName(),
@@ -232,8 +262,7 @@
         assertEquals(phoneCapability, mPhoneCapability);
 
         // notifyPhoneCapabilityChanged with a new capability. Callback should be triggered.
-        phoneCapability = new PhoneCapability(3, 2, null, false,
-                PhoneCapability.DEVICE_NR_CAPABILITY_NONE);
+        phoneCapability = new PhoneCapability(3, 2, null, false, new int[0]);
         mTelephonyRegistry.notifyPhoneCapabilityChanged(phoneCapability);
         processAllMessages();
         assertEquals(phoneCapability, mPhoneCapability);
@@ -422,6 +451,33 @@
         assertEquals(4, mTelephonyCallback.invocationCount.get());
     }
 
+    @Test
+    public void testPhysicalChannelConfigChanged() {
+        // Return a slotIndex / phoneId of 0 for all sub ids given.
+        doReturn(mMockSubInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt());
+        doReturn(0/*slotIndex*/).when(mMockSubInfo).getSimSlotIndex();
+
+        final int subId = 1;
+        int[] events = {TelephonyCallback.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED};
+        // Construct PhysicalChannelConfig with minimum fields set (The default value for
+        // frequencyRange and band fields throw IAE)
+        PhysicalChannelConfig config = new PhysicalChannelConfig.Builder()
+                .setFrequencyRange(FREQUENCY_RANGE_LOW)
+                .setBand(1)
+                .setPhysicalCellId(2)
+                .build();
+        List<PhysicalChannelConfig> configs = new ArrayList<>(1);
+        configs.add(config);
+
+        mTelephonyRegistry.notifyPhysicalChannelConfigForSubscriber(subId, configs);
+        mTelephonyRegistry.listenWithEventList(subId, mContext.getOpPackageName(),
+                mContext.getAttributionTag(), mTelephonyCallback.callback, events, true);
+        processAllMessages();
+
+        assertNotNull(mPhysicalChannelConfigs);
+        assertEquals(PHYSICAL_CELL_ID_UNKNOWN, mPhysicalChannelConfigs.get(0).getPhysicalCellId());
+    }
+
     /**
      * Test listen to events that require READ_PHONE_STATE permission.
      */
@@ -439,6 +495,32 @@
     }
 
     /**
+     * Test enforcement of READ_PHONE_STATE for call state related events.
+     */
+    @Test
+    public void testCallStateChangedPermission() {
+        int[] events = new int[] {TelephonyCallback.EVENT_CALL_STATE_CHANGED,
+                TelephonyCallback.EVENT_LEGACY_CALL_STATE_CHANGED};
+        // Disable change ID for READ_PHONE_STATE enforcement
+        when(mMockConfigurationProvider.isCallStateReadPhoneStateEnforcedInPlatformCompat(
+                anyString(), any())).thenReturn(false);
+        // Start without READ_PHONE_STATE permission
+        mContextFixture.addCallingOrSelfPermission("");
+        assertSecurityExceptionNotThrown(events);
+        // Grant permission
+        mContextFixture.addCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE);
+        assertSecurityExceptionNotThrown(events);
+        //Enable READ_PHONE_STATE enforcement
+        when(mMockConfigurationProvider.isCallStateReadPhoneStateEnforcedInPlatformCompat(
+                anyString(), any())).thenReturn(true);
+        assertSecurityExceptionNotThrown(events);
+        // revoke READ_PHONE_STATE permission
+        mContextFixture.removeCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE);
+        assertSecurityExceptionThrown(events);
+
+    }
+
+    /**
      * Test listen to events that require READ_PRECISE_PHONE_STATE permission.
      */
     @Test
@@ -542,6 +624,51 @@
         assertEquals(displayInfo, mTelephonyDisplayInfo);
     }
 
+    @Test
+    public void testNotifyCellLocationForSubscriberByUserSwitched() throws RemoteException {
+        final int phoneId = 0;
+        final int subId = 1;
+
+        // Return a slotIndex / phoneId of 0 for subId 1.
+        doReturn(new int[] {subId}).when(mSubscriptionController).getSubId(phoneId);
+        doReturn(mMockSubInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(subId);
+        doReturn(phoneId).when(mMockSubInfo).getSimSlotIndex();
+        mServiceManagerMockedServices.put("isub", mSubscriptionController);
+        doReturn(mSubscriptionController).when(mSubscriptionController)
+                .queryLocalInterface(anyString());
+
+        UserInfo userInfo = new UserInfo(UserHandle.myUserId(), "" /* name */, 0 /* flags */);
+        doReturn(userInfo).when(mIActivityManager).getCurrentUser();
+
+        doReturn(true).when(mLocationManager).isLocationEnabledForUser(any(UserHandle.class));
+
+        CellIdentity cellIdentity = new CellIdentityGsm(-1, -1, -1, -1, null, null, null, null,
+                Collections.emptyList());
+        mTelephonyRegistry.notifyCellLocationForSubscriber(subId, cellIdentity);
+        processAllMessages();
+
+        // Listen to EVENT_CELL_LOCATION_CHANGED for the current user Id.
+        int[] events = {TelephonyCallback.EVENT_CELL_LOCATION_CHANGED};
+        mTelephonyRegistry.listenWithEventList(subId, mContext.getOpPackageName(),
+                mContext.getAttributionTag(), mTelephonyCallback.callback, events, false);
+
+        // Broadcast ACTION_USER_SWITCHED for USER_SYSTEM. Callback should be triggered.
+        mCellLocation = null;
+        mContext.sendBroadcast(new Intent(Intent.ACTION_USER_SWITCHED));
+
+        processAllMessages();
+        assertEquals(cellIdentity.asCellLocation(), mCellLocation);
+
+        // Broadcast ACTION_USER_SWITCHED for the current user Id + 1. Callback shouldn't be
+        // triggered.
+        userInfo.id++;
+        mCellLocation = null;
+        mContext.sendBroadcast(new Intent(Intent.ACTION_USER_SWITCHED));
+
+        processAllMessages();
+        assertEquals(null, mCellLocation);
+    }
+
     private void assertSecurityExceptionThrown(int[] event) {
         try {
             mTelephonyRegistry.listenWithEventList(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 035bcdf..b1f0e2e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -41,6 +41,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.location.LocationManager;
 import android.net.ConnectivityManager;
 import android.net.NetworkCapabilities;
 import android.net.vcn.VcnManager;
@@ -326,6 +327,8 @@
     protected LinkBandwidthEstimator mLinkBandwidthEstimator;
     @Mock
     protected PinStorage mPinStorage;
+    @Mock
+    protected LocationManager mLocationManager;
 
     protected ActivityManager mActivityManager;
     protected ImsCallProfile mImsCallProfile;
@@ -484,6 +487,7 @@
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
         mVcnManager = mContext.getSystemService(VcnManager.class);
+        mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
 
         //mTelephonyComponentFactory
         doReturn(mTelephonyComponentFactory).when(mTelephonyComponentFactory).inject(anyString());
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 f26c373..a6cdcae 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
@@ -42,6 +42,7 @@
 
 import android.content.IntentFilter;
 import android.content.pm.ServiceInfo;
+import android.hardware.radio.V1_0.SetupDataCallResult;
 import android.net.InetAddresses;
 import android.net.KeepalivePacketData;
 import android.net.LinkAddress;
@@ -83,8 +84,10 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.util.Arrays;
+import java.util.Collections;
 
 public class DataConnectionTest extends TelephonyTest {
+    private static final int DEFAULT_DC_CID = 10;
 
     @Mock
     DcTesterFailBringUpAll mDcTesterFailBringUpAll;
@@ -95,9 +98,13 @@
     @Mock
     ApnContext mApnContext;
     @Mock
+    ApnContext mEnterpriseApnContext;
+    @Mock
     DcFailBringUp mDcFailBringUp;
     @Mock
     DataCallSessionStats mDataCallSessionStats;
+    @Mock
+    DataConnection mDefaultDc;
 
     private DataConnection mDc;
     private DataConnectionTestHandler mDataConnectionTestHandler;
@@ -289,6 +296,7 @@
                 ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
         doReturn(mApn1).when(mApnContext).getApnSetting();
         doReturn(ApnSetting.TYPE_DEFAULT_STRING).when(mApnContext).getApnType();
+        doReturn(ApnSetting.TYPE_DEFAULT).when(mApnContext).getApnTypeBitmask();
 
         mDcFailBringUp.saveParameters(0, 0, -2);
         doReturn(mDcFailBringUp).when(mDcTesterFailBringUpAll).getDcFailBringUp();
@@ -352,8 +360,13 @@
         return (boolean) method.invoke(mDc);
     }
 
-    private SetupResult setLinkProperties(DataCallResponse response,
-                                                         LinkProperties linkProperties)
+    private boolean isEnterpriseUse() throws Exception {
+        Method method = DataConnection.class.getDeclaredMethod("isEnterpriseUse");
+        method.setAccessible(true);
+        return (boolean) method.invoke(mDc);
+    }
+
+    private SetupResult setLinkProperties(DataCallResponse response, LinkProperties linkProperties)
             throws Exception {
         Class[] cArgs = new Class[2];
         cArgs[0] = DataCallResponse.class;
@@ -373,9 +386,7 @@
     @SmallTest
     public void testConnectEvent() throws Exception {
         testSanity();
-
-        mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp);
-        waitForMs(200);
+        connectEvent(true);
 
         verify(mCT, times(1)).registerForVoiceCallStarted(any(Handler.class),
                 eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED), eq(null));
@@ -408,15 +419,15 @@
         assertEquals("spmode.ne.jp", dpCaptor.getValue().getApn());
         if (tdCaptor.getValue() != null) {
             if (mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) {
-                assertEquals(null, tdCaptor.getValue().getDnn());
+                assertEquals(null, tdCaptor.getValue().getDataNetworkName());
                 assertTrue(tdCaptor.getValue().getOsAppId()
                         .contains(ApnSetting.TYPE_ENTERPRISE_STRING));
             } else {
-                assertEquals("spmode.ne.jp", tdCaptor.getValue().getDnn());
+                assertEquals("spmode.ne.jp", tdCaptor.getValue().getDataNetworkName());
                 assertEquals(null, tdCaptor.getValue().getOsAppId());
             }
         }
-        assertEquals("DcActiveState", getCurrentState().getName());
+        assertTrue(mDc.isActive());
 
         assertEquals(mDc.getPduSessionId(), 1);
         assertEquals(3, mDc.getPcscfAddresses().length);
@@ -426,13 +437,85 @@
     }
 
     @Test
+    public void testConnectEventDuplicateContextIds() throws Exception {
+        setUpDefaultData();
+
+        // Create successful result with the same CID as default
+        SetupDataCallResult result = new SetupDataCallResult();
+        result.status = 0;
+        result.suggestedRetryTime = -1;
+        result.cid = DEFAULT_DC_CID;
+        result.active = 2;
+        result.type = "IP";
+        result.ifname = FAKE_IFNAME;
+        result.addresses = FAKE_ADDRESS;
+        result.dnses = FAKE_DNS;
+        result.gateways = FAKE_GATEWAY;
+        result.pcscf = FAKE_PCSCF_ADDRESS;
+        result.mtu = 1440;
+        mSimulatedCommands.setDataCallResult(true, result);
+
+        // Try to connect ENTERPRISE with the same CID as default
+        replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext);
+        doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting();
+        doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType();
+        doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask();
+
+        // Verify that ENTERPRISE wasn't set up
+        connectEvent(false);
+        assertEquals("DcInactiveState", getCurrentState().getName());
+
+        // Change the CID
+        result.cid = DEFAULT_DC_CID + 1;
+        mSimulatedCommands.setDataCallResult(true, result);
+
+        // Verify that ENTERPRISE was set up
+        connectEvent(true);
+        assertTrue(mDc.getNetworkCapabilities().hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_ENTERPRISE));
+    }
+
+    @Test
+    public void testConnectEventNoDefaultData() throws Exception {
+        assertFalse(mDefaultDc.isActive());
+
+        // Try to connect ENTERPRISE when default data doesn't exist
+        replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext);
+        doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting();
+        doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType();
+        doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask();
+
+        // Verify that ENTERPRISE wasn't set up
+        connectEvent(false);
+        assertEquals("DcInactiveState", getCurrentState().getName());
+
+        // Set up default data
+        replaceInstance(ConnectionParams.class, "mApnContext", mCp, mApnContext);
+        setUpDefaultData();
+
+        // Verify that ENTERPRISE was set up
+        replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext);
+        connectEvent(true);
+        assertTrue(mDc.getNetworkCapabilities().hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_ENTERPRISE));
+    }
+
+    private void setUpDefaultData() throws Exception {
+        replaceInstance(DataConnection.class, "mCid", mDefaultDc, DEFAULT_DC_CID);
+        doReturn(true).when(mDefaultDc).isActive();
+        doReturn(Arrays.asList(mApnContext)).when(mDefaultDc).getApnContexts();
+        mDcc.addActiveDcByCid(mDefaultDc);
+        assertTrue(mDefaultDc.getApnContexts().stream()
+                .anyMatch(apn -> apn.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT));
+    }
+
+    @Test
     @SmallTest
     public void testDisconnectEvent() throws Exception {
         testConnectEvent();
 
         mDc.setPduSessionId(5);
-        mDc.sendMessage(DataConnection.EVENT_DISCONNECT, mDcp);
-        waitForMs(100);
+        disconnectEvent();
 
         verify(mSimulatedCommandsVerifier, times(1)).unregisterForLceInfo(any(Handler.class));
         verify(mSimulatedCommandsVerifier, times(1))
@@ -617,12 +700,9 @@
                 CarrierConfigManager.KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY,
                 new String[] {"supl"});
 
-        mDc.sendMessage(DataConnection.EVENT_DISCONNECT, mDcp);
-        waitForMs(100);
+        disconnectEvent();
         doReturn(mApn1).when(mApnContext).getApnSetting();
-        doReturn(ApnSetting.TYPE_ENTERPRISE).when(mApnContext).getApnTypeBitmask();
-        mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp);
-        waitForMs(200);
+        connectEvent(true);
 
         assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
                 .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN));
@@ -630,6 +710,42 @@
                 .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET));
         assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
                 .hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL));
+        assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE));
+    }
+
+    @Test
+    @SmallTest
+    public void testEnterpriseNetworkCapability() throws Exception {
+        mContextFixture.getCarrierConfigBundle().putStringArray(
+                CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+                new String[] { "default" });
+        doReturn(mApn2).when(mApnContext).getApnSetting();
+        testConnectEvent();
+
+        assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN));
+        assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET));
+        assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS));
+        assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE));
+
+        disconnectEvent();
+        setUpDefaultData();
+        replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext);
+        doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting();
+        doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType();
+        doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask();
+        connectEvent(true);
+
+        assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN));
+        assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET));
+        assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL));
         assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
                 .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE));
     }
@@ -673,12 +789,14 @@
         assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
 
         mDc.onMeterednessChanged(true);
+        waitForMs(100);
 
         assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
         assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
         assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
 
         mDc.onMeterednessChanged(false);
+        waitForMs(100);
 
         assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
         assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
@@ -697,12 +815,14 @@
         assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
 
         mDc.onCongestednessChanged(true);
+        waitForMs(100);
 
         assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
         assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
         assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
 
         mDc.onCongestednessChanged(false);
+        waitForMs(100);
 
         assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
         assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
@@ -710,6 +830,16 @@
     }
 
     @Test
+    public void testSubIds() throws Exception {
+        mContextFixture.getCarrierConfigBundle().putStringArray(
+                CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+                new String[] { "default" });
+        testConnectEvent();
+
+        assertEquals(Collections.singleton(0), getNetworkCapabilities().getSubIds());
+    }
+
+    @Test
     public void testShouldSkip464Xlat() throws Exception {
         assertFalse(testShouldSkip464XlatEvent(mApn1));
         disconnectEvent();
@@ -729,16 +859,19 @@
         method.setAccessible(true);
 
         doReturn(apn).when(mApnContext).getApnSetting();
-        connectEvent();
+        doReturn(apn.getApnTypeBitmask()).when(mApnContext).getApnTypeBitmask();
+        connectEvent(true);
         logd(getNetworkCapabilities().toString());
 
         return (Boolean) method.invoke(mDc);
     }
 
-    private void connectEvent() throws Exception {
+    private void connectEvent(boolean validate) {
         mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp);
         waitForMs(200);
-        assertEquals("DcActiveState", getCurrentState().getName());
+        if (validate) {
+            assertTrue(mDc.isActive());
+        }
     }
 
     private void disconnectEvent() throws Exception {
@@ -749,7 +882,7 @@
 
     @Test
     @SmallTest
-    public void testIsIpAddress() throws Exception {
+    public void testIsIpAddress() {
         // IPv4
         assertTrue(DataConnection.isIpAddress("1.2.3.4"));
         assertTrue(DataConnection.isIpAddress("127.0.0.1"));
@@ -1056,6 +1189,24 @@
     }
 
     @Test
+    public void testIsEnterpriseUse() throws Exception {
+        assertFalse(isEnterpriseUse());
+        assertFalse(mDc.getNetworkCapabilities().hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_ENTERPRISE));
+
+        setUpDefaultData();
+        replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext);
+        doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting();
+        doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType();
+        doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask();
+        connectEvent(true);
+
+        assertTrue(isEnterpriseUse());
+        assertTrue(mDc.getNetworkCapabilities().hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_ENTERPRISE));
+    }
+
+    @Test
     @SmallTest
     public void testGetDisallowedApnTypes() throws Exception {
         mContextFixture.getCarrierConfigBundle().putStringArray(
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 0c7cc1b..a1b91e5 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
@@ -127,6 +127,7 @@
     public static final String FAKE_APN6 = "FAKE APN 6";
     public static final String FAKE_APN7 = "FAKE APN 7";
     public static final String FAKE_APN8 = "FAKE APN 8";
+    public static final String FAKE_APN9 = "FAKE APN 9";
     public static final String FAKE_IFNAME = "FAKE IFNAME";
     public static final String FAKE_PCSCF_ADDRESS = "22.33.44.55";
     public static final String FAKE_GATEWAY = "11.22.33.44";
@@ -208,18 +209,12 @@
 
         private String mFakeApn1Types = "default,supl";
 
-        private int mNetworkTypeBitmask = NETWORK_TYPE_LTE_BITMASK;
-
         private int mRowIdOffset = 0;
 
         public void setFakeApn1Types(String apnTypes) {
             mFakeApn1Types = apnTypes;
         }
 
-        public void setFakeApn1NetworkTypeBitmask(int networkTypeBitmask) {
-            mNetworkTypeBitmask = networkTypeBitmask;
-        }
-
         public void setRowIdOffset(int rowIdOffset) {
             mRowIdOffset = rowIdOffset;
         }
@@ -294,7 +289,7 @@
                             0,                      // mtu
                             "",                     // mvno_type
                             "",                     // mnvo_match_data
-                            mNetworkTypeBitmask,    // network_type_bitmask
+                            NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask
                             0,                      // apn_set_id
                             -1,                     // carrier_id
                             -1                      // skip_464xlat
@@ -466,7 +461,7 @@
                     });
 
                     mc.addRow(new Object[]{
-                            2169,                   // id
+                            2169 + mRowIdOffset,    // id
                             FAKE_PLMN,              // numeric
                             "sp-mode",              // name
                             FAKE_APN7,              // apn
@@ -499,7 +494,7 @@
                     });
 
                     mc.addRow(new Object[]{
-                            2170,                   // id
+                            2170 + mRowIdOffset,    // id
                             FAKE_PLMN,              // numeric
                             "IMS",                  // name
                             FAKE_APN8,              // apn
@@ -531,6 +526,39 @@
                             -1                      // skip_464xlat
                     });
 
+                    mc.addRow(new Object[]{
+                            2171 + mRowIdOffset,    // id
+                            FAKE_PLMN,              // numeric
+                            "sp-mode nr",           // name
+                            FAKE_APN9,              // apn
+                            "",                     // proxy
+                            "",                     // port
+                            "",                     // mmsc
+                            "",                     // mmsproxy
+                            "",                     // mmsport
+                            "",                     // user
+                            "",                     // password
+                            -1,                     // authtype
+                            "default,enterprise",   // types
+                            "IP",                   // protocol
+                            "IP",                   // roaming_protocol
+                            1,                      // carrier_enabled
+                            ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer
+                            0,                      // bearer_bitmask
+                            0,                      // profile_id
+                            1,                      // modem_cognitive
+                            0,                      // max_conns
+                            0,                      // wait_time
+                            0,                      // max_conns_time
+                            0,                      // mtu
+                            "",                     // mvno_type
+                            "",                     // mnvo_match_data
+                            NETWORK_TYPE_NR_BITMASK, // network_type_bitmask
+                            0,                      // apn_set_id
+                            -1,                     // carrier_id
+                            -1                      // skip_464xlat
+                    });
+
                     return mc;
                 }
             } else if (isPathPrefixMatch(uri,
@@ -776,8 +804,6 @@
     @Test
     @MediumTest
     public void testDataSetup() throws Exception {
-        mSimulatedCommands.setDataCallResult(true, createSetupDataCallResult());
-
         DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
         boolean allowed = isDataAllowed(dataConnectionReasons);
         assertFalse(dataConnectionReasons.toString(), allowed);
@@ -950,8 +976,7 @@
         waitForMs(200);
         // expected tear down all metered DataConnections
         verify(mSimulatedCommandsVerifier, times(2)).deactivateDataCall(
-                eq(DataService.REQUEST_REASON_NORMAL), anyInt(),
-                any(Message.class));
+                anyInt(), eq(DataService.REQUEST_REASON_NORMAL), any(Message.class));
         assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING));
         assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_MMS_STRING));
 
@@ -1164,30 +1189,37 @@
 
     // Test the ENTERPRISE APN setup.
     @Test
-    @SmallTest
     public void testTrySetupDataEnterpriseApn() {
-        mApnSettingContentProvider.setFakeApn1Types("default,enterprise");
-        mApnSettingContentProvider.setFakeApn1NetworkTypeBitmask(NETWORK_TYPE_NR_BITMASK);
+        mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
+        sendInitializationEvents();
+
+        ArgumentCaptor<TrafficDescriptor> tdCaptor =
+                ArgumentCaptor.forClass(TrafficDescriptor.class);
+        verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
+                eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false),
+                eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(),
+                anyBoolean(), any(Message.class));
+        assertEquals("FAKE APN 1", tdCaptor.getValue().getDataNetworkName());
+        assertEquals(null, tdCaptor.getValue().getOsAppId());
+
         mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
                 .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR)
                 .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
                 .build();
         doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo(
                 anyInt(), anyInt());
-        initApns(ApnSetting.TYPE_ENTERPRISE_STRING,
-                new String[]{ApnSetting.TYPE_ENTERPRISE_STRING, ApnSetting.TYPE_DEFAULT_STRING});
+        SetupDataCallResult result = createSetupDataCallResult();
+        result.cid = 10;
+        mSimulatedCommands.setDataCallResult(true, result);
         mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null);
+        waitForMs(200);
 
-        sendInitializationEvents();
-
-        ArgumentCaptor<TrafficDescriptor> tdCaptor =
-                ArgumentCaptor.forClass(TrafficDescriptor.class);
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
                 eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false),
                 eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(),
                 anyBoolean(), any(Message.class));
-        assertEquals(null, tdCaptor.getValue().getDnn());
-        assertTrue(tdCaptor.getValue().getOsAppId().contains(ApnSetting.TYPE_ENTERPRISE_STRING));
+        assertEquals(null, tdCaptor.getValue().getDataNetworkName());
+        assertTrue(tdCaptor.getValue().getOsAppId().equals("ENTERPRISE"));
     }
 
     @Test
@@ -1556,7 +1588,6 @@
         mApnSettingContentProvider.setFakeApn1Types("default,supl,dun");
 
         // Enable the default apn
-        mSimulatedCommands.setDataCallResult(true, createSetupDataCallResult());
         mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
         waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
 
@@ -2339,8 +2370,6 @@
 
     @Test
     public void testRatChanged() throws Exception {
-        mSimulatedCommands.setDataCallResult(true, createSetupDataCallResult());
-
         DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
         boolean allowed = isDataAllowed(dataConnectionReasons);
         assertFalse(dataConnectionReasons.toString(), allowed);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/LinkBandwidthEstimatorTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/LinkBandwidthEstimatorTest.java
index 52b1013..e48f183 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/LinkBandwidthEstimatorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/LinkBandwidthEstimatorTest.java
@@ -19,13 +19,16 @@
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 
 import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.BW_STATS_COUNT_THRESHOLD;
-import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.MSG_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED;
+import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.LINK_RX;
+import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.LINK_TX;
 import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.MSG_DEFAULT_NETWORK_CHANGED;
 import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.MSG_MODEM_ACTIVITY_RETURNED;
 import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.MSG_NR_FREQUENCY_CHANGED;
 import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.MSG_SCREEN_STATE_CHANGED;
 import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.MSG_SIGNAL_STRENGTH_CHANGED;
+import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.UNKNOWN_TAC;
 
+import static org.junit.Assert.*;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -70,7 +73,6 @@
             new ModemActivityInfo(100L, 0, 0, TX_TIME_1_MS, RX_TIME_2_MS);
     private NetworkCapabilities mNetworkCapabilities;
     private CellIdentityLte mCellIdentity;
-    private Pair<Integer, Integer> mDefaultBwKbps;
     private long mElapsedTimeMs = 0;
     private long mTxBytes = 0;
     private long mRxBytes = 0;
@@ -78,7 +80,7 @@
     TelephonyFacade mTelephonyFacade;
     @Mock
     DataConnection mDataConnection;
-    NetworkRegistrationInfo mNri;
+    private NetworkRegistrationInfo mNri;
 
     @Before
     public void setUp() throws Exception {
@@ -88,7 +90,6 @@
                 .build();
 
         mCellIdentity = new CellIdentityLte(310, 260, 1234, 123456, 366);
-        mDefaultBwKbps = new Pair<>(30_000, 15_000);
         mNri = new NetworkRegistrationInfo.Builder()
                 .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
                 .build();
@@ -98,8 +99,8 @@
         when(mTelephonyFacade.getMobileTxBytes()).thenReturn(0L);
         when(mPhone.getCurrentCellIdentity()).thenReturn(mCellIdentity);
         when(mDcTracker.getDataConnectionByApnType(anyString())).thenReturn(mDataConnection);
-        when(mDcTracker.getLinkBandwidthsFromCarrierConfig(anyString())).thenReturn(mDefaultBwKbps);
         when(mSignalStrength.getDbm()).thenReturn(-100);
+        when(mSignalStrength.getLevel()).thenReturn(1);
         mLBE = new LinkBandwidthEstimator(mPhone, mTelephonyFacade);
         mLBE.obtainMessage(MSG_DEFAULT_NETWORK_CHANGED, mNetworkCapabilities).sendToTarget();
         processAllMessages();
@@ -166,7 +167,7 @@
         processAllMessages();
 
         verify(mTelephonyManager, times(2)).requestModemActivityInfo(any(), any());
-        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(15_000), eq(30_000));
+        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
     }
 
     @Test
@@ -196,7 +197,7 @@
         processAllMessages();
 
         verify(mTelephonyManager, times(2)).requestModemActivityInfo(any(), any());
-        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(15_000), eq(30_000));
+        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
     }
 
     @Test
@@ -224,7 +225,7 @@
             moveTimeForward(1_100);
             processAllMessages();
         }
-        verify(mTelephonyManager, times(4)).requestModemActivityInfo(any(), any());
+        verify(mTelephonyManager, times(2)).requestModemActivityInfo(any(), any());
     }
 
     @Test
@@ -260,14 +261,12 @@
                 .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR)
                 .build();
         when(mServiceState.getNetworkRegistrationInfo(anyInt(), anyInt())).thenReturn(mNri);
-        mDefaultBwKbps = new Pair<>(300_000, 150_000);
-        when(mDcTracker.getLinkBandwidthsFromCarrierConfig(anyString())).thenReturn(mDefaultBwKbps);
         addElapsedTime(6000);
         moveTimeForward(6000);
         processAllMessages();
 
         verify(mTelephonyManager, times(0)).requestModemActivityInfo(any(), any());
-        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(150_000), eq(300_000));
+        verify(mDataConnection, times(2)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
     }
 
     @Test
@@ -277,7 +276,7 @@
 
         for (int i = 0; i < BW_STATS_COUNT_THRESHOLD + 2; i++) {
             addTxBytes(10_000L);
-            addRxBytes(300_000L);
+            addRxBytes(500_000L);
             addElapsedTime(5_100);
             moveTimeForward(5_100);
             processAllMessages();
@@ -286,8 +285,8 @@
             processAllMessages();
         }
 
-        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(15_000), eq(30_000));
-        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(15_000), eq(17_274));
+        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
+        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(19_597));
 
         addTxBytes(20_000L);
         addRxBytes(50_000L);
@@ -297,29 +296,50 @@
         moveTimeForward(6000);
         processAllMessages();
 
-        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(15_000), eq(25_327));
+        verify(mDataConnection, times(2)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
     }
 
     @Test
-    public void testCarrierConfigChangeTriggerBandwidthUpdate() throws Exception {
-        mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
-        addTxBytes(10_000L);
-        addRxBytes(19_000L);
-        addElapsedTime(2000);
-        moveTimeForward(2000);
-        processAllMessages();
-
-        addTxBytes(10_000L);
-        addRxBytes(19_000L);
-        when(mSignalStrength.getLevel()).thenReturn(2);
-        mDefaultBwKbps = new Pair<>(50_000, 20_000);
-        when(mDcTracker.getLinkBandwidthsFromCarrierConfig(anyString())).thenReturn(mDefaultBwKbps);
-        mLBE.obtainMessage(MSG_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED).sendToTarget();
-        addElapsedTime(6000);
-        moveTimeForward(6000);
-        processAllMessages();
-
-        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(20_000), eq(50_000));
+    public void testAvgBwForAllPossibleRat() throws Exception {
+        Pair<Integer, Integer> values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_GPRS);
+        assertEquals(24, (int) values.second);
+        values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_EDGE);
+        assertEquals(18, (int) values.second);
+        values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_UMTS);
+        assertEquals(115, (int) values.second);
+        values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_CDMA);
+        assertEquals(14, (int) values.second);
+        values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_1xRTT);
+        assertEquals(30, (int) values.second);
+        values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_EVDO_0);
+        assertEquals(48, (int) values.second);
+        values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_EVDO_A);
+        assertEquals(550, (int) values.second);
+        values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_HSDPA);
+        assertEquals(620, (int) values.second);
+        values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_HSUPA);
+        assertEquals(1800, (int) values.second);
+        values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_HSPA);
+        assertEquals(1800, (int) values.second);
+        values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_EVDO_B);
+        assertEquals(550, (int) values.second);
+        values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_EHRPD);
+        assertEquals(750, (int) values.first);
+        values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_HSPAP);
+        assertEquals(3400, (int) values.second);
+        values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_TD_SCDMA);
+        assertEquals(115, (int) values.first);
+        values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_LTE);
+        assertEquals(15000, (int) values.second);
+        when(mServiceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED);
+        when(mServiceState.getNrFrequencyRange()).thenReturn(ServiceState.FREQUENCY_RANGE_MMWAVE);
+        values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_LTE);
+        assertEquals(145000, (int) values.first);
+        when(mServiceState.getNrFrequencyRange()).thenReturn(ServiceState.FREQUENCY_RANGE_UNKNOWN);
+        values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_LTE);
+        assertEquals(47000, (int) values.first);
+        values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_NR);
+        assertEquals(145_000, (int) values.first);
     }
 
     @Test
@@ -336,14 +356,12 @@
         when(mServiceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED);
         when(mServiceState.getNrFrequencyRange()).thenReturn(ServiceState.FREQUENCY_RANGE_MMWAVE);
         when(mSignalStrength.getLevel()).thenReturn(2);
-        mDefaultBwKbps = new Pair<>(500_000, 200_000);
-        when(mDcTracker.getLinkBandwidthsFromCarrierConfig(anyString())).thenReturn(mDefaultBwKbps);
         mLBE.obtainMessage(MSG_NR_FREQUENCY_CHANGED).sendToTarget();
         addElapsedTime(6000);
         moveTimeForward(6000);
         processAllMessages();
 
-        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(200_000), eq(500_000));
+        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
     }
 
     @Test
@@ -353,7 +371,7 @@
 
         for (int i = 0; i < BW_STATS_COUNT_THRESHOLD + 2; i++) {
             addTxBytes(10_000L);
-            addRxBytes(300_000L);
+            addRxBytes(500_000L);
             addElapsedTime(5_100);
             moveTimeForward(5_100);
             processAllMessages();
@@ -364,8 +382,8 @@
 
         verify(mTelephonyManager, times(BW_STATS_COUNT_THRESHOLD + 2))
                 .requestModemActivityInfo(any(), any());
-        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(15_000), eq(30_000));
-        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(15_000), eq(17_274));
+        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
+        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(19_597));
     }
 
     @Test
@@ -375,7 +393,7 @@
 
         for (int i = 0; i < BW_STATS_COUNT_THRESHOLD; i++) {
             addTxBytes(10_000L);
-            addRxBytes(300_000L);
+            addRxBytes(500_000L);
             addElapsedTime(5_100);
             moveTimeForward(5_100);
             processAllMessages();
@@ -388,7 +406,7 @@
         when(mPhone.getCurrentCellIdentity()).thenReturn(mCellIdentity);
         for (int i = BW_STATS_COUNT_THRESHOLD; i < 3 * BW_STATS_COUNT_THRESHOLD; i++) {
             addTxBytes(10_000L);
-            addRxBytes(400_000L);
+            addRxBytes(500_000L);
             addElapsedTime(5_100);
             moveTimeForward(5_100);
             processAllMessages();
@@ -397,18 +415,20 @@
             processAllMessages();
         }
 
-        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(15_000), eq(30_000));
-        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(15_000), eq(17_300));
+        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
+        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(19_597));
     }
 
     @Test
     public void testUseAllTacStatsIfNoEnoughDataWithCurrentTac() throws Exception {
         mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
         processAllMessages();
+        mLBE.obtainMessage(MSG_SIGNAL_STRENGTH_CHANGED, mSignalStrength).sendToTarget();
+        processAllMessages();
 
         for (int i = 0; i < BW_STATS_COUNT_THRESHOLD; i++) {
             addTxBytes(10_000L);
-            addRxBytes(300_000L);
+            addRxBytes(900_000L);
             addElapsedTime(5_100);
             moveTimeForward(5_100);
             processAllMessages();
@@ -421,7 +441,7 @@
         when(mPhone.getCurrentCellIdentity()).thenReturn(mCellIdentity);
         for (int i = BW_STATS_COUNT_THRESHOLD; i < BW_STATS_COUNT_THRESHOLD * 3 / 2; i++) {
             addTxBytes(10_000L);
-            addRxBytes(400_000L);
+            addRxBytes(1_000_000L);
             addElapsedTime(5_100);
             moveTimeForward(5_100);
             processAllMessages();
@@ -430,8 +450,18 @@
             processAllMessages();
         }
 
-        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(15_000), eq(30_000));
-        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(15_000), eq(17_300));
+        LinkBandwidthEstimator.NetworkBandwidth network = mLBE.lookupNetwork("310260", 366, "LTE");
+        assertEquals(BW_STATS_COUNT_THRESHOLD - 1, network.getCount(LINK_RX, 1));
+        assertEquals(900_000L * 8 * 1000 / 200 / 1024 * (BW_STATS_COUNT_THRESHOLD - 1),
+                network.getValue(LINK_RX, 1));
+        network = mLBE.lookupNetwork("310260", 367, "LTE");
+        assertEquals(2, network.getCount(LINK_RX, 1));
+        assertEquals(1_000_000L * 8 * 1000 / 200 / 1024 * 2,
+                network.getValue(LINK_RX, 1));
+        network = mLBE.lookupNetwork("310260", UNKNOWN_TAC, "LTE");
+        assertEquals(BW_STATS_COUNT_THRESHOLD * 3 / 2 - 1, network.getCount(LINK_RX, 1));
+        assertEquals(218_748, network.getValue(LINK_RX, 1));
+        verify(mDataConnection, times(2)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
     }
 
     @Test
@@ -441,7 +471,7 @@
 
         for (int i = 0; i < BW_STATS_COUNT_THRESHOLD + 5; i++) {
             addTxBytes(10_000L);
-            addRxBytes(300_000L);
+            addRxBytes(500_000L);
             addElapsedTime(5_100);
             moveTimeForward(5_100);
             processAllMessages();
@@ -450,8 +480,8 @@
             processAllMessages();
         }
 
-        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(15_000), eq(30_000));
-        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(15_000), eq(17_274));
+        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
+        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(19_597));
 
         mCellIdentity = new CellIdentityLte(320, 265, 1234, 123456, 366);
         when(mPhone.getCurrentCellIdentity()).thenReturn(mCellIdentity);
@@ -462,6 +492,56 @@
         moveTimeForward(5_100);
         processAllMessages();
 
-        verify(mDataConnection, times(2)).updateLinkBandwidthEstimation(eq(15_000), eq(30_000));
+        verify(mDataConnection, times(2)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
+    }
+
+    @Test
+    public void testIgnoreLowTxRxTime() throws Exception {
+        mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
+        processAllMessages();
+
+        for (int i = 0; i < BW_STATS_COUNT_THRESHOLD + 5; i++) {
+            addTxBytes(10_000L);
+            addRxBytes(500_000L);
+            addElapsedTime(5_100);
+            moveTimeForward(5_100);
+            processAllMessages();
+            mLBE.obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, new ModemActivityInfo(
+                    i * 5_100L, 0, 0, TX_TIME_2_MS, i * 80)).sendToTarget();
+            processAllMessages();
+        }
+
+        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
+        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(anyInt(), anyInt());
+    }
+
+    @Test
+    public void testUseHighTxRxByteEdge() throws Exception {
+        mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
+        processAllMessages();
+        mNri = new NetworkRegistrationInfo.Builder()
+                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_EDGE)
+                .build();
+        when(mServiceState.getNetworkRegistrationInfo(anyInt(), anyInt())).thenReturn(mNri);
+        mLBE.obtainMessage(MSG_SIGNAL_STRENGTH_CHANGED, mSignalStrength).sendToTarget();
+        processAllMessages();
+        for (int i = 0; i < BW_STATS_COUNT_THRESHOLD + 5; i++) {
+            addTxBytes(12_000L);
+            addRxBytes(12_000L);
+            addElapsedTime(5_100);
+            moveTimeForward(5_100);
+            processAllMessages();
+            mLBE.obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, new ModemActivityInfo(
+                    i * 5_100L, 0, 0, TX_TIME_2_MS, i * RX_TIME_2_MS * 5)).sendToTarget();
+            processAllMessages();
+        }
+
+        LinkBandwidthEstimator.NetworkBandwidth network = mLBE.lookupNetwork("310260", 366, "EDGE");
+
+        assertEquals(0, network.getCount(LINK_TX, 1));
+        assertEquals(BW_STATS_COUNT_THRESHOLD + 4, network.getCount(LINK_RX, 1));
+        assertEquals(12_000L * 8 / 1024 * (BW_STATS_COUNT_THRESHOLD + 4),
+                network.getValue(LINK_RX, 1));
+        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(92));
     }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/QosCallbackTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/QosCallbackTrackerTest.java
index d886b3d..7434662 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/QosCallbackTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/QosCallbackTrackerTest.java
@@ -258,7 +258,7 @@
         qosSessions.remove(1);
         mQosCallbackTracker.updateSessions(qosSessions);
 
-        verify(mDcNetworkAgent, times(1)).notifyQosSessionLost(eq(1), eq(1235));
+        verify(mDcNetworkAgent, times(1)).notifyQosSessionLost(eq(1), eq(1235), eq(1));
     }
 
     @Test
@@ -380,8 +380,8 @@
         // Update empty QOS sessions list
         mQosCallbackTracker.updateSessions(new ArrayList<>());
 
-        verify(mDcNetworkAgent, times(1)).notifyQosSessionLost(eq(1), eq(1234));
-        verify(mDcNetworkAgent, times(1)).notifyQosSessionLost(eq(2), eq(1235));
+        verify(mDcNetworkAgent, times(1)).notifyQosSessionLost(eq(1), eq(1234), eq(1));
+        verify(mDcNetworkAgent, times(1)).notifyQosSessionLost(eq(2), eq(1235), eq(1));
     }
 
     @Test
@@ -423,8 +423,8 @@
         // Update empty QOS sessions list
         mQosCallbackTracker.updateSessions(new ArrayList<>());
 
-        verify(mDcNetworkAgent, times(1)).notifyQosSessionLost(eq(1), eq(1234));
-        verify(mDcNetworkAgent, times(1)).notifyQosSessionLost(eq(2), eq(1235));
+        verify(mDcNetworkAgent, times(1)).notifyQosSessionLost(eq(1), eq(1234), eq(1));
+        verify(mDcNetworkAgent, times(1)).notifyQosSessionLost(eq(2), eq(1235), eq(1));
     }
 }
 
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 ceb5acc..aacfd4a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
@@ -1376,7 +1376,7 @@
 
         if (rxBytes != 0 || txBytes != 0) {
             expectedStats = expectedStats.addEntry(
-                    new Entry(NetworkStats.IFACE_VT, UID_ALL, SET_FOREGROUND,
+                    new Entry(mCTUT.getVtInterface(), UID_ALL, SET_FOREGROUND,
                             TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, rxBytes, 0L,
                             txBytes, 0L, 0L));
         }