Merge changes from topic "active_dataconnections"

* changes:
  Notify ALL active data connections
  Use actual data connection state
diff --git a/src/java/com/android/internal/telephony/CellularNetworkService.java b/src/java/com/android/internal/telephony/CellularNetworkService.java
index 3bb3814..57b9088 100644
--- a/src/java/com/android/internal/telephony/CellularNetworkService.java
+++ b/src/java/com/android/internal/telephony/CellularNetworkService.java
@@ -228,9 +228,6 @@
                         (android.hardware.radio.V1_0.VoiceRegStateResult) result;
                 int regState = getRegStateFromHalRegState(voiceRegState.regState);
                 int networkType = ServiceState.rilRadioTechnologyToNetworkType(voiceRegState.rat);
-                if (networkType == TelephonyManager.NETWORK_TYPE_LTE_CA) {
-                    networkType = TelephonyManager.NETWORK_TYPE_LTE;
-                }
                 int reasonForDenial = voiceRegState.reasonForDenial;
                 boolean emergencyOnly = isEmergencyOnly(voiceRegState.regState);
                 boolean cssSupported = voiceRegState.cssSupported;
@@ -251,9 +248,6 @@
                         (android.hardware.radio.V1_2.VoiceRegStateResult) result;
                 int regState = getRegStateFromHalRegState(voiceRegState.regState);
                 int networkType = ServiceState.rilRadioTechnologyToNetworkType(voiceRegState.rat);
-                if (networkType == TelephonyManager.NETWORK_TYPE_LTE_CA) {
-                    networkType = TelephonyManager.NETWORK_TYPE_LTE;
-                }
                 int reasonForDenial = voiceRegState.reasonForDenial;
                 boolean emergencyOnly = isEmergencyOnly(voiceRegState.regState);
                 boolean cssSupported = voiceRegState.cssSupported;
@@ -281,7 +275,6 @@
             int regState = NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN;
             int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
             int reasonForDenial = 0;
-            boolean isUsingCarrierAggregation = false;
             boolean emergencyOnly = false;
             int maxDataCalls = 0;
             CellIdentity cellIdentity;
@@ -355,15 +348,10 @@
             List<Integer> availableServices = getAvailableServices(
                     regState, domain, emergencyOnly);
 
-            if (networkType == TelephonyManager.NETWORK_TYPE_LTE_CA) {
-                isUsingCarrierAggregation = true;
-                networkType = TelephonyManager.NETWORK_TYPE_LTE;
-            }
-
             return new NetworkRegistrationInfo(domain, transportType, regState, networkType,
                     reasonForDenial, emergencyOnly, availableServices, cellIdentity, rplmn,
                     maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable,
-                    lteVopsSupportInfo, isUsingCarrierAggregation);
+                    lteVopsSupportInfo);
         }
 
         private @NonNull NetworkRegistrationInfo getNetworkRegistrationInfo(
@@ -380,16 +368,10 @@
             final String rplmn = regResult.registeredPlmn;
             final int reasonForDenial = regResult.reasonForDenial;
 
-            // Network Type fixup for carrier aggregation
             int networkType = ServiceState.rilRadioTechnologyToNetworkType(regResult.rat);
-            // In earlier versions of the HAL, LTE_CA was allowed to indicate that the device
-            // is on CA; however, that has been superseded by the PHYSICAL_CHANNEL_CONFIG signal.
-            // Because some vendors provide both NETWORK_TYPE_LTE_CA *and* PHYSICAL_CHANNEL_CONFIG,
-            // this tweak is left for compatibility; however, the network type is no longer allowed
-            // to be used to declare that carrier aggregation is in effect, because the other
-            // signal provides a much richer information set, and we want to mitigate confusion in
-            // how CA information is being provided.
             if (networkType == TelephonyManager.NETWORK_TYPE_LTE_CA) {
+                // In Radio HAL v1.5, NETWORK_TYPE_LTE_CA is ignored. Callers should use
+                // PhysicalChannelConfig.
                 networkType = TelephonyManager.NETWORK_TYPE_LTE;
             }
 
@@ -448,7 +430,7 @@
                     return new NetworkRegistrationInfo(domain, transportType, regState, networkType,
                             reasonForDenial, isEmergencyOnly, availableServices, cellIdentity,
                             rplmn, MAX_DATA_CALLS, isDcNrRestricted, isNrAvailable, isEndcAvailable,
-                            vopsInfo, false /* isUsingCarrierAggregation */);
+                            vopsInfo);
             }
         }
 
diff --git a/src/java/com/android/internal/telephony/DeviceStateMonitor.java b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
index e009aad..9e95939 100644
--- a/src/java/com/android/internal/telephony/DeviceStateMonitor.java
+++ b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
@@ -891,10 +891,10 @@
          * List of dB thresholds for NGRAN {@link AccessNetworkType} RSRSRP
          */
         public static final int[] NGRAN_RSRSRQ = new int[] {
-            -16, /* SIGNAL_STRENGTH_POOR */
-            -12, /* SIGNAL_STRENGTH_MODERATE */
-            -9, /* SIGNAL_STRENGTH_GOOD */
-            -6  /* SIGNAL_STRENGTH_GREAT */
+            -31, /* SIGNAL_STRENGTH_POOR */
+            -19, /* SIGNAL_STRENGTH_MODERATE */
+            -7, /* SIGNAL_STRENGTH_GOOD */
+            6  /* SIGNAL_STRENGTH_GREAT */
         };
 
         /**
diff --git a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
index ee1b0aa..5499920 100644
--- a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
+++ b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
@@ -31,7 +31,6 @@
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.telephony.ims.stub.ImsSmsImplBase;
 import android.telephony.ims.stub.ImsSmsImplBase.SendStatusResult;
-import android.util.Pair;
 
 import com.android.ims.FeatureConnector;
 import com.android.ims.ImsException;
@@ -130,11 +129,12 @@
             tracker.mMessageRef = messageRef;
             switch(status) {
                 case ImsSmsImplBase.SEND_STATUS_OK:
-                    if (tracker.mDeliveryIntent == null) {
-                        // Remove the tracker here if a status report is not requested.
-                        mTrackers.remove(token);
+                    if (tracker.mDeliveryIntent != null) {
+                        // Expecting a status report. Put this tracker to the map.
+                        mSmsDispatchersController.putDeliveryPendingTracker(tracker);
                     }
                     tracker.onSent(mContext);
+                    mTrackers.remove(token);
                     mPhone.notifySmsSent(tracker.mDestAddress);
                     break;
                 case ImsSmsImplBase.SEND_STATUS_ERROR:
@@ -147,7 +147,8 @@
                     break;
                 case ImsSmsImplBase.SEND_STATUS_ERROR_FALLBACK:
                     tracker.mRetryCount += 1;
-                    fallbackToPstn(token, tracker);
+                    mTrackers.remove(token);
+                    fallbackToPstn(tracker);
                     break;
                 default:
             }
@@ -164,35 +165,18 @@
                         "Status report received with a PDU that could not be parsed.");
             }
             int messageRef = message.mWrappedSmsMessage.mMessageRef;
-            SmsTracker tracker = null;
-            int key = 0;
-            for (Map.Entry<Integer, SmsTracker> entry : mTrackers.entrySet()) {
-                if (messageRef == ((SmsTracker) entry.getValue()).mMessageRef) {
-                    tracker = entry.getValue();
-                    key = entry.getKey();
-                    break;
-                }
+            boolean handled = mSmsDispatchersController.handleSmsStatusReport(format, pdu);
+            if (!handled) {
+                loge("Can not handle the status report for messageRef " + messageRef);
             }
-
-            if (tracker == null) {
-                throw new RemoteException("No tracker for messageRef " + messageRef);
-            }
-            Pair<Boolean, Boolean> result = mSmsDispatchersController.handleSmsStatusReport(
-                    tracker, format, pdu);
-            logd("Status report handle result, success: " + result.first
-                    + " complete: " + result.second);
             try {
                 getImsManager().acknowledgeSmsReport(
                         token,
                         messageRef,
-                        result.first ? ImsSmsImplBase.STATUS_REPORT_STATUS_OK
+                        handled ? ImsSmsImplBase.STATUS_REPORT_STATUS_OK
                                 : ImsSmsImplBase.STATUS_REPORT_STATUS_ERROR);
             } catch (ImsException e) {
-                loge("Failed to acknowledgeSmsReport(). Error: "
-                        + e.getMessage());
-            }
-            if (result.second) {
-                mTrackers.remove(key);
+                loge("Failed to acknowledgeSmsReport(). Error: " + e.getMessage());
             }
         }
 
@@ -407,7 +391,8 @@
                     ImsSmsImplBase.SEND_STATUS_OK);
         } catch (ImsException e) {
             loge("sendSms failed. Falling back to PSTN. Error: " + e.getMessage());
-            fallbackToPstn(token, tracker);
+            mTrackers.remove(token);
+            fallbackToPstn(tracker);
             mMetrics.writeImsServiceSendSms(mPhone.getPhoneId(), format,
                     ImsSmsImplBase.SEND_STATUS_ERROR_FALLBACK);
         }
@@ -418,9 +403,8 @@
     }
 
     @VisibleForTesting
-    public void fallbackToPstn(int token, SmsTracker tracker) {
+    public void fallbackToPstn(SmsTracker tracker) {
         mSmsDispatchersController.sendRetrySms(tracker);
-        mTrackers.remove(token);
     }
 
     @Override
diff --git a/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java b/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java
index 94ea9d0..fcd2f35 100644
--- a/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java
+++ b/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java
@@ -68,6 +68,7 @@
     private static final int CMD_INTERRUPT_NETWORK_SCAN = 6;
     private static final int EVENT_INTERRUPT_NETWORK_SCAN_DONE = 7;
     private static final int EVENT_MODEM_RESET = 8;
+    private static final int EVENT_RADIO_UNAVAILABLE = 9;
 
     private final Handler mHandler = new Handler() {
         @Override
@@ -102,6 +103,8 @@
                     mScheduler.interruptScanDone((AsyncResult) msg.obj);
                     break;
 
+                case EVENT_RADIO_UNAVAILABLE:
+                    // Fallthrough
                 case EVENT_MODEM_RESET:
                     AsyncResult ar = (AsyncResult) msg.obj;
                     mScheduler.deleteScanAndMayNotify(
@@ -564,6 +567,7 @@
                 nsri.mPhone.startNetworkScan(nsri.getRequest(),
                         mHandler.obtainMessage(EVENT_START_NETWORK_SCAN_DONE, nsri));
                 nsri.mPhone.mCi.registerForModemReset(mHandler, EVENT_MODEM_RESET, nsri);
+                nsri.mPhone.mCi.registerForNotAvailable(mHandler, EVENT_RADIO_UNAVAILABLE, nsri);
                 return true;
             }
             return false;
@@ -584,6 +588,7 @@
                     }
                 }
                 mLiveRequestInfo.mPhone.mCi.unregisterForModemReset(mHandler);
+                mLiveRequestInfo.mPhone.mCi.unregisterForNotAvailable(mHandler);
                 mLiveRequestInfo = null;
                 if (mPendingRequestInfo != null) {
                     startNewScan(mPendingRequestInfo);
diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java
index 4e4d7a9..14b38da 100644
--- a/src/java/com/android/internal/telephony/NetworkTypeController.java
+++ b/src/java/com/android/internal/telephony/NetworkTypeController.java
@@ -23,12 +23,10 @@
 import android.os.AsyncResult;
 import android.os.Message;
 import android.os.PersistableBundle;
-import android.provider.Settings;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.Annotation;
 import android.telephony.CarrierConfigManager;
 import android.telephony.NetworkRegistrationInfo;
-import android.telephony.PhoneStateListener;
 import android.telephony.RadioAccessFamily;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
@@ -36,6 +34,8 @@
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 
+import com.android.internal.telephony.dataconnection.DcController;
+import com.android.internal.telephony.dataconnection.DcController.PhysicalLinkState;
 import com.android.internal.util.IState;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.State;
@@ -81,42 +81,40 @@
     private static final int EVENT_DATA_RAT_CHANGED = 2;
     private static final int EVENT_NR_STATE_CHANGED = 3;
     private static final int EVENT_NR_FREQUENCY_CHANGED = 4;
-    private static final int EVENT_DATA_ACTIVITY_CHANGED = 5;
+    private static final int EVENT_PHYSICAL_LINK_STATE_CHANGED = 5;
     private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED = 6;
     private static final int EVENT_CARRIER_CONFIG_CHANGED = 7;
     private static final int EVENT_PRIMARY_TIMER_EXPIRED = 8;
     private static final int EVENT_SECONDARY_TIMER_EXPIRED = 9;
     private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 10;
-    private static final int EVENT_DATA_CONNECTION_STATE_CHANGED = 11;
-    private static final int EVENT_PREFERRED_NETWORK_MODE_CHANGED = 12;
+    private static final int EVENT_PREFERRED_NETWORK_MODE_CHANGED = 11;
+    private static final int EVENT_INITIALIZE = 12;
     // events that don't reset the timer
     private static final int[] ALL_EVENTS = { EVENT_DATA_RAT_CHANGED, EVENT_NR_STATE_CHANGED,
-            EVENT_NR_FREQUENCY_CHANGED, EVENT_DATA_ACTIVITY_CHANGED,
+            EVENT_NR_FREQUENCY_CHANGED, EVENT_PHYSICAL_LINK_STATE_CHANGED,
             EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED, EVENT_PRIMARY_TIMER_EXPIRED,
-            EVENT_SECONDARY_TIMER_EXPIRED, EVENT_DATA_CONNECTION_STATE_CHANGED };
+            EVENT_SECONDARY_TIMER_EXPIRED};
 
-    private static final String[] sEvents = new String[EVENT_PREFERRED_NETWORK_MODE_CHANGED + 1];
+    private static final String[] sEvents = new String[EVENT_INITIALIZE + 1];
     static {
         sEvents[EVENT_UPDATE] = "EVENT_UPDATE";
         sEvents[EVENT_QUIT] = "EVENT_QUIT";
         sEvents[EVENT_DATA_RAT_CHANGED] = "EVENT_DATA_RAT_CHANGED";
         sEvents[EVENT_NR_STATE_CHANGED] = "EVENT_NR_STATE_CHANGED";
         sEvents[EVENT_NR_FREQUENCY_CHANGED] = "EVENT_NR_FREQUENCY_CHANGED";
-        sEvents[EVENT_DATA_ACTIVITY_CHANGED] = "EVENT_DATA_ACTIVITY_CHANGED";
+        sEvents[EVENT_PHYSICAL_LINK_STATE_CHANGED] = "EVENT_PHYSICAL_LINK_STATE_CHANGED";
         sEvents[EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED] =
                 "EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED";
         sEvents[EVENT_CARRIER_CONFIG_CHANGED] = "EVENT_CARRIER_CONFIG_CHANGED";
         sEvents[EVENT_PRIMARY_TIMER_EXPIRED] = "EVENT_PRIMARY_TIMER_EXPIRED";
         sEvents[EVENT_SECONDARY_TIMER_EXPIRED] = "EVENT_SECONDARY_TIMER_EXPIRED";
         sEvents[EVENT_RADIO_OFF_OR_UNAVAILABLE] = "EVENT_RADIO_OFF_OR_UNAVAILABLE";
-        sEvents[EVENT_DATA_CONNECTION_STATE_CHANGED] = "EVENT_DATA_CONNECTION_STATE_CHANGED";
         sEvents[EVENT_PREFERRED_NETWORK_MODE_CHANGED] = "EVENT_PREFERRED_NETWORK_MODE_CHANGED";
+        sEvents[EVENT_INITIALIZE] = "EVENT_INITIALIZE";
     }
 
     private final Phone mPhone;
     private final DisplayInfoController mDisplayInfoController;
-    private final TelephonyManager mTelephonyManager;
-    private final SettingsObserver mSettingsObserver;
     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -129,16 +127,6 @@
             }
         }
     };
-    private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
-        @Override
-        public void onDataActivity(int direction) {
-            sendMessage(EVENT_DATA_ACTIVITY_CHANGED);
-        }
-        @Override
-        public void onDataConnectionStateChanged(int state, int networkType) {
-            sendMessage(EVENT_DATA_CONNECTION_STATE_CHANGED);
-        }
-    };
 
     private Map<String, OverrideTimerRule> mOverrideTimerRules = new HashMap<>();
     private String mLteEnhancedPattern = "";
@@ -146,9 +134,11 @@
     private boolean mIsPhysicalChannelConfigOn;
     private boolean mIsPrimaryTimerActive;
     private boolean mIsSecondaryTimerActive;
+    private boolean mIsTimerResetEnabledForLegacyStateRRCIdle;
     private String mPrimaryTimerState;
     private String mSecondaryTimerState;
     private String mPreviousState;
+    private @PhysicalLinkState int mPhysicalLinkState;
 
     /**
      * NetworkTypeController constructor.
@@ -160,9 +150,6 @@
         super(TAG, displayInfoController);
         mPhone = phone;
         mDisplayInfoController = displayInfoController;
-        mTelephonyManager = TelephonyManager.from(phone.getContext())
-                .createForSubscriptionId(phone.getSubId());
-        mSettingsObserver = new SettingsObserver(mPhone.getContext(), getHandler());
         mOverrideNetworkType = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE;
         mIsPhysicalChannelConfigOn = true;
         addState(mDefaultState);
@@ -171,9 +158,8 @@
         addState(mLteConnectedState, mDefaultState);
         addState(mNrConnectedState, mDefaultState);
         setInitialState(mDefaultState);
-        registerForAllEvents();
-        parseCarrierConfigs();
         start();
+        sendMessage(EVENT_INITIALIZE);
     }
 
     /**
@@ -187,9 +173,14 @@
     private void registerForAllEvents() {
         mPhone.registerForRadioOffOrNotAvailable(getHandler(),
                 EVENT_RADIO_OFF_OR_UNAVAILABLE, null);
+        mPhone.registerForPreferredNetworkTypeChanged(getHandler(),
+                EVENT_PREFERRED_NETWORK_MODE_CHANGED, null);
         mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, getHandler(),
                 EVENT_DATA_RAT_CHANGED, null);
+        mPhone.getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+                .registerForPhysicalLinkStateChanged(getHandler(),
+                        EVENT_PHYSICAL_LINK_STATE_CHANGED);
         mPhone.getServiceStateTracker().registerForNrStateChanged(getHandler(),
                 EVENT_NR_STATE_CHANGED, null);
         mPhone.getServiceStateTracker().registerForNrFrequencyChanged(getHandler(),
@@ -199,26 +190,17 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
         mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
-        if (mTelephonyManager != null) {
-            mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_DATA_ACTIVITY
-                    | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
-        }
-        mSettingsObserver.observe(Settings.Global.getUriFor(Settings.Global.PREFERRED_NETWORK_MODE),
-                EVENT_PREFERRED_NETWORK_MODE_CHANGED);
     }
 
     private void unRegisterForAllEvents() {
         mPhone.unregisterForRadioOffOrNotAvailable(getHandler());
+        mPhone.unregisterForPreferredNetworkTypeChanged(getHandler());
         mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, getHandler());
         mPhone.getServiceStateTracker().unregisterForNrStateChanged(getHandler());
         mPhone.getServiceStateTracker().unregisterForNrFrequencyChanged(getHandler());
         mPhone.getDeviceStateMonitor().unregisterForPhysicalChannelConfigNotifChanged(getHandler());
         mPhone.getContext().unregisterReceiver(mIntentReceiver);
-        if (mTelephonyManager != null) {
-            mTelephonyManager.listen(mPhoneStateListener, 0);
-        }
-        mSettingsObserver.unobserve();
     }
 
     private void parseCarrierConfigs() {
@@ -230,6 +212,9 @@
                 CarrierConfigManager.KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING);
         mLteEnhancedPattern = CarrierConfigManager.getDefaultConfig().getString(
                 CarrierConfigManager.KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING);
+        mIsTimerResetEnabledForLegacyStateRRCIdle =
+                CarrierConfigManager.getDefaultConfig().getBoolean(
+                        CarrierConfigManager.KEY_NR_TIMERS_RESET_IF_NON_ENDC_AND_RRC_IDLE_BOOL);
 
         CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
                 .getSystemService(Context.CARRIER_CONFIG_SERVICE);
@@ -255,6 +240,8 @@
                     mLteEnhancedPattern = b.getString(
                             CarrierConfigManager.KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING);
                 }
+                mIsTimerResetEnabledForLegacyStateRRCIdle = b.getBoolean(
+                        CarrierConfigManager.KEY_NR_TIMERS_RESET_IF_NON_ENDC_AND_RRC_IDLE_BOOL);
             }
         }
         createTimerRules(nrIconConfiguration, overrideTimerRule, overrideSecondaryTimerRule);
@@ -393,7 +380,7 @@
                 keys.add(STATE_CONNECTED);
                 break;
             case NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED:
-                keys.add(isDataActive() ? STATE_NOT_RESTRICTED_RRC_CON
+                keys.add(isPhysicalLinkActive() ? STATE_NOT_RESTRICTED_RRC_CON
                         : STATE_NOT_RESTRICTED_RRC_IDLE);
                 break;
             case NetworkRegistrationInfo.NR_STATE_RESTRICTED:
@@ -457,12 +444,22 @@
                     unRegisterForAllEvents();
                     quit();
                     break;
+                case EVENT_INITIALIZE:
+                    // The reason that we do it here is because some of the works below requires
+                    // other modules (e.g. DcTracker, ServiceStateTracker), which is not created
+                    // yet when NetworkTypeController is created.
+                    registerForAllEvents();
+                    parseCarrierConfigs();
+                    break;
                 case EVENT_DATA_RAT_CHANGED:
                 case EVENT_NR_STATE_CHANGED:
                 case EVENT_NR_FREQUENCY_CHANGED:
-                case EVENT_DATA_ACTIVITY_CHANGED:
                     // ignored
                     break;
+                case EVENT_PHYSICAL_LINK_STATE_CHANGED:
+                    AsyncResult ar = (AsyncResult) msg.obj;
+                    mPhysicalLinkState = (int) ar.result;
+                    break;
                 case EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED:
                     AsyncResult result = (AsyncResult) msg.obj;
                     mIsPhysicalChannelConfigOn = (boolean) result.result;
@@ -498,13 +495,6 @@
                     resetAllTimers();
                     transitionTo(mLegacyState);
                     break;
-                case EVENT_DATA_CONNECTION_STATE_CHANGED:
-                    if (mPhone.getServiceState().getDataNetworkType()
-                            != mDisplayInfoController.getTelephonyDisplayInfo().getNetworkType()) {
-                        resetAllTimers();
-                        transitionToCurrentState();
-                    }
-                    break;
                 case EVENT_PREFERRED_NETWORK_MODE_CHANGED:
                     resetAllTimers();
                     transitionToCurrentState();
@@ -551,8 +541,13 @@
                     if (rat == TelephonyManager.NETWORK_TYPE_NR || isLte(rat) && isNrConnected()) {
                         transitionTo(mNrConnectedState);
                     } else if (isLte(rat) && isNrNotRestricted()) {
-                        transitionWithTimerTo(isDataActive() ? mLteConnectedState : mIdleState);
+                        transitionWithTimerTo(isPhysicalLinkActive()
+                                ? mLteConnectedState : mIdleState);
                     } else {
+                        if (!isLte(rat)) {
+                            // Rat is 3G or 2G, and it doesn't need NR timer.
+                            resetAllTimers();
+                        }
                         updateOverrideNetworkType();
                     }
                     mIsNrRestricted = isNrRestricted();
@@ -561,16 +556,24 @@
                     if (isNrConnected()) {
                         transitionTo(mNrConnectedState);
                     } else if (isLte(rat) && isNrNotRestricted()) {
-                        transitionWithTimerTo(isDataActive() ? mLteConnectedState : mIdleState);
+                        transitionWithTimerTo(isPhysicalLinkActive()
+                                ? mLteConnectedState : mIdleState);
                     } else if (isLte(rat) && isNrRestricted()) {
                         updateOverrideNetworkType();
                     }
                     mIsNrRestricted = isNrRestricted();
                     break;
                 case EVENT_NR_FREQUENCY_CHANGED:
-                case EVENT_DATA_ACTIVITY_CHANGED:
                     // ignored
                     break;
+                case EVENT_PHYSICAL_LINK_STATE_CHANGED:
+                    AsyncResult ar = (AsyncResult) msg.obj;
+                    mPhysicalLinkState = (int) ar.result;
+                    if (mIsTimerResetEnabledForLegacyStateRRCIdle && !isPhysicalLinkActive()) {
+                        resetAllTimers();
+                        updateOverrideNetworkType();
+                    }
+                    break;
                 default:
                     return NOT_HANDLED;
             }
@@ -625,10 +628,12 @@
                 case EVENT_NR_FREQUENCY_CHANGED:
                     // ignore
                     break;
-                case EVENT_DATA_ACTIVITY_CHANGED:
+                case EVENT_PHYSICAL_LINK_STATE_CHANGED:
+                    AsyncResult ar = (AsyncResult) msg.obj;
+                    mPhysicalLinkState = (int) ar.result;
                     if (isNrNotRestricted()) {
                         // NOT_RESTRICTED_RRC_IDLE -> NOT_RESTRICTED_RRC_CON
-                        if (isDataActive()) {
+                        if (isPhysicalLinkActive()) {
                             transitionWithTimerTo(mLteConnectedState);
                         }
                     } else {
@@ -690,10 +695,12 @@
                 case EVENT_NR_FREQUENCY_CHANGED:
                     // ignore
                     break;
-                case EVENT_DATA_ACTIVITY_CHANGED:
+                case EVENT_PHYSICAL_LINK_STATE_CHANGED:
+                    AsyncResult ar = (AsyncResult) msg.obj;
+                    mPhysicalLinkState = (int) ar.result;
                     if (isNrNotRestricted()) {
                         // NOT_RESTRICTED_RRC_CON -> NOT_RESTRICTED_RRC_IDLE
-                        if (!isDataActive()) {
+                        if (!isPhysicalLinkActive()) {
                             transitionWithTimerTo(mIdleState);
                         }
                     } else {
@@ -745,14 +752,16 @@
                     if (rat == TelephonyManager.NETWORK_TYPE_NR || isLte(rat) && isNrConnected()) {
                         updateOverrideNetworkType();
                     } else if (isLte(rat) && isNrNotRestricted()) {
-                        transitionWithTimerTo(isDataActive() ? mLteConnectedState : mIdleState);
+                        transitionWithTimerTo(isPhysicalLinkActive()
+                                ? mLteConnectedState : mIdleState);
                     } else {
                         transitionWithTimerTo(mLegacyState);
                     }
                     break;
                 case EVENT_NR_STATE_CHANGED:
                     if (isLte(rat) && isNrNotRestricted()) {
-                        transitionWithTimerTo(isDataActive() ? mLteConnectedState : mIdleState);
+                        transitionWithTimerTo(isPhysicalLinkActive()
+                                ? mLteConnectedState : mIdleState);
                     } else if (rat != TelephonyManager.NETWORK_TYPE_NR && !isNrConnected()) {
                         transitionWithTimerTo(mLegacyState);
                     }
@@ -772,7 +781,9 @@
                     }
                     mIsNrMmwave = isNrMmwave();
                     break;
-                case EVENT_DATA_ACTIVITY_CHANGED:
+                case EVENT_PHYSICAL_LINK_STATE_CHANGED:
+                    AsyncResult ar = (AsyncResult) msg.obj;
+                    mPhysicalLinkState = (int) ar.result;
                     if (!isNrConnected()) {
                         log("NR state changed. Sending EVENT_NR_STATE_CHANGED");
                         sendMessage(EVENT_NR_STATE_CHANGED);
@@ -831,7 +842,7 @@
             transitionState = mNrConnectedState;
             mPreviousState = isNrMmwave() ? STATE_CONNECTED_MMWAVE : STATE_CONNECTED;
         } else if (isLte(dataRat) && isNrNotRestricted()) {
-            if (isDataActive()) {
+            if (isPhysicalLinkActive()) {
                 transitionState = mLteConnectedState;
                 mPreviousState = STATE_NOT_RESTRICTED_RRC_CON;
             } else {
@@ -877,9 +888,18 @@
         if (currentState.equals(STATE_CONNECTED_MMWAVE)) {
             resetAllTimers();
         }
+
+        int rat = mPhone.getServiceState().getDataNetworkType();
+        if (!isLte(rat) && rat != TelephonyManager.NETWORK_TYPE_NR) {
+            // Rat is 3G or 2G, and it doesn't need NR timer.
+            resetAllTimers();
+        }
     }
 
     private void resetAllTimers() {
+        if (DBG) {
+            log("Remove all timers");
+        }
         removeMessages(EVENT_PRIMARY_TIMER_EXPIRED);
         removeMessages(EVENT_SECONDARY_TIMER_EXPIRED);
         mIsPrimaryTimerActive = false;
@@ -994,10 +1014,8 @@
                 || rat == TelephonyManager.NETWORK_TYPE_LTE_CA;
     }
 
-    private boolean isDataActive() {
-        PhoneInternalInterface.DataActivityState activity = mPhone.getDataActivityState();
-        return activity != PhoneInternalInterface.DataActivityState.DORMANT
-                && activity != PhoneInternalInterface.DataActivityState.NONE;
+    private boolean isPhysicalLinkActive() {
+        return mPhysicalLinkState == DcController.PHYSICAL_LINK_ACTIVE;
     }
 
     private String getEventName(int event) {
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index b9e2630..76811db 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -405,6 +405,8 @@
 
     private final RegistrantList mOtaspRegistrants = new RegistrantList();
 
+    private final RegistrantList mPreferredNetworkTypeRegistrants = new RegistrantList();
+
     protected Registrant mPostDialHandler;
 
     protected final LocalLog mLocalLog;
@@ -2249,6 +2251,7 @@
                 + " filteredType = " + filteredType);
 
         mCi.setPreferredNetworkType(filteredType, response);
+        mPreferredNetworkTypeRegistrants.notifyRegistrants();
     }
 
     /**
@@ -2261,6 +2264,27 @@
     }
 
     /**
+     * Register for preferred network type changes
+     *
+     * @param h Handler that receives the notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    public void registerForPreferredNetworkTypeChanged(Handler h, int what, Object obj) {
+        checkCorrectThread(h);
+        mPreferredNetworkTypeRegistrants.addUnique(h, what, obj);
+    }
+
+    /**
+     * Unregister for preferred network type changes.
+     *
+     * @param h Handler that should be unregistered.
+     */
+    public void unregisterForPreferredNetworkTypeChanged(Handler h) {
+        mPreferredNetworkTypeRegistrants.remove(h);
+    }
+
+    /**
      * Get the cached value of the preferred network type setting
      */
     public int getCachedPreferredNetworkType() {
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 2aa304d..4a2e7da 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -44,6 +44,7 @@
 import android.hardware.radio.V1_0.RadioIndicationType;
 import android.hardware.radio.V1_0.RadioResponseInfo;
 import android.hardware.radio.V1_0.RadioResponseType;
+import android.hardware.radio.V1_0.RadioTechnologyFamily;
 import android.hardware.radio.V1_0.ResetNvType;
 import android.hardware.radio.V1_0.SelectUiccSub;
 import android.hardware.radio.V1_0.SimApdu;
@@ -4069,7 +4070,7 @@
             if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
 
             ImsSmsMessage msg = new ImsSmsMessage();
-            msg.tech = RILConstants.GSM_PHONE;
+            msg.tech = RadioTechnologyFamily.THREE_GPP;
             msg.retry = (byte) retry >= 1 ? true : false;
             msg.messageRef = messageRef;
 
@@ -4096,7 +4097,7 @@
             if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
 
             ImsSmsMessage msg = new ImsSmsMessage();
-            msg.tech = RILConstants.CDMA_PHONE;
+            msg.tech = RadioTechnologyFamily.THREE_GPP2;
             msg.retry = (byte) retry >= 1 ? true : false;
             msg.messageRef = messageRef;
 
diff --git a/src/java/com/android/internal/telephony/RatRatcheter.java b/src/java/com/android/internal/telephony/RatRatcheter.java
index 7406cef..24a8ac5 100644
--- a/src/java/com/android/internal/telephony/RatRatcheter.java
+++ b/src/java/com/android/internal/telephony/RatRatcheter.java
@@ -54,8 +54,6 @@
     private final SparseArray<SparseIntArray> mRatFamilyMap = new SparseArray<>();
 
     private final Phone mPhone;
-    private boolean mVoiceRatchetEnabled = true;
-    private boolean mDataRatchetEnabled = true;
 
     /**
      * Updates the ServiceState with a new set of cell bandwidths IFF the new bandwidth list has a
@@ -119,55 +117,35 @@
         }
     }
 
-    /** Ratchets RATs and cell bandwidths if oldSS and newSS have the same RAT family. */
-    public void ratchet(@NonNull ServiceState oldSS, @NonNull ServiceState newSS,
-                        boolean locationChange) {
-        // temporarily disable rat ratchet on location change.
-        if (locationChange) {
-            mVoiceRatchetEnabled = false;
-            mDataRatchetEnabled = false;
+    /**
+     * Ratchets RATs and cell bandwidths if oldSS and newSS have the same RAT family.
+     *
+     * Ensure that a device on the same cell reports the best-seen capability to the user.
+     */
+    public void ratchet(@NonNull ServiceState oldSS, @NonNull ServiceState newSS) {
+        // Different rat family, don't need rat ratchet and update cell bandwidths.
+        if (!isSameRatFamily(oldSS, newSS)) {
+            Rlog.e(LOG_TAG, "Same cell cannot have different RAT Families. Likely bug.");
             return;
         }
 
-        // Different rat family, don't need rat ratchet and update cell bandwidths.
-        if (!isSameRatFamily(oldSS, newSS)) {
-           return;
+        final int[] domains = {
+                NetworkRegistrationInfo.DOMAIN_CS, NetworkRegistrationInfo.DOMAIN_PS};
+        for (int domain : domains) {
+            NetworkRegistrationInfo oldNri = oldSS.getNetworkRegistrationInfo(
+                    domain, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+            NetworkRegistrationInfo newNri = newSS.getNetworkRegistrationInfo(
+                    domain, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+            int newNetworkType = ratchetRat(oldNri.getAccessNetworkTechnology(),
+                    newNri.getAccessNetworkTechnology());
+            newNri.setAccessNetworkTechnology(newNetworkType);
+            if (oldNri.isUsingCarrierAggregation()) newNri.setIsUsingCarrierAggregation(true);
+            newSS.addNetworkRegistrationInfo(newNri);
         }
 
+        // Ratchet Cell Bandwidths
         updateBandwidths(oldSS.getCellBandwidths(), newSS);
-
-        boolean newUsingCA = oldSS.isUsingCarrierAggregation()
-                || newSS.isUsingCarrierAggregation()
-                || newSS.getCellBandwidths().length > 1;
-        NetworkRegistrationInfo oldCsNri = oldSS.getNetworkRegistrationInfo(
-                NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
-        NetworkRegistrationInfo newCsNri = newSS.getNetworkRegistrationInfo(
-                NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
-        if (mVoiceRatchetEnabled) {
-            int newPsNetworkType = ratchetRat(oldCsNri.getAccessNetworkTechnology(),
-                    newCsNri.getAccessNetworkTechnology());
-            newCsNri.setAccessNetworkTechnology(newPsNetworkType);
-            newSS.addNetworkRegistrationInfo(newCsNri);
-        } else if (oldCsNri.getAccessNetworkTechnology() != oldCsNri.getAccessNetworkTechnology()) {
-            // resume rat ratchet on following rat change within the same location
-            mVoiceRatchetEnabled = true;
-        }
-
-        NetworkRegistrationInfo oldPsNri = oldSS.getNetworkRegistrationInfo(
-                NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
-        NetworkRegistrationInfo newPsNri = newSS.getNetworkRegistrationInfo(
-                NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
-        if (mDataRatchetEnabled) {
-            int newPsNetworkType = ratchetRat(oldPsNri.getAccessNetworkTechnology(),
-                    newPsNri.getAccessNetworkTechnology());
-            newPsNri.setAccessNetworkTechnology(newPsNetworkType);
-            newSS.addNetworkRegistrationInfo(newPsNri);
-        } else if (oldPsNri.getAccessNetworkTechnology() != newPsNri.getAccessNetworkTechnology()) {
-            // resume rat ratchet on following rat change within the same location
-            mDataRatchetEnabled = true;
-        }
-
-        newSS.setIsUsingCarrierAggregation(newUsingCA);
     }
 
     private boolean isSameRatFamily(ServiceState ss1, ServiceState ss2) {
diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java
index ea14908..18c829c 100644
--- a/src/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/SMSDispatcher.java
@@ -259,15 +259,6 @@
         Rlog.d(TAG, "handleStatusReport() called with no subclass.");
     }
 
-    /* TODO: Need to figure out how to keep track of status report routing in a
-     *       persistent manner. If the phone process restarts (reboot or crash),
-     *       we will lose this list and any status reports that come in after
-     *       will be dropped.
-     */
-    /** Sent messages awaiting a delivery status report. */
-    @UnsupportedAppUsage
-    protected final ArrayList<SmsTracker> deliveryPendingList = new ArrayList<SmsTracker>();
-
     /**
      * Handles events coming from the phone stack. Overridden from handler.
      *
@@ -758,8 +749,8 @@
             if (DBG) Rlog.d(TAG, "SMS send complete. Broadcasting intent: " + sentIntent);
 
             if (tracker.mDeliveryIntent != null) {
-                // Expecting a status report.  Add it to the list.
-                deliveryPendingList.add(tracker);
+                // Expecting a status report. Put this tracker to the map.
+                mSmsDispatchersController.putDeliveryPendingTracker(tracker);
             }
             tracker.onSent(mContext);
             mPhone.notifySmsSent(tracker.mDestAddress);
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index 0e0d3e4..915422a 100755
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -3251,10 +3251,8 @@
             int newRAT = newNrs != null ? newNrs.getAccessNetworkTechnology()
                     : TelephonyManager.NETWORK_TYPE_UNKNOWN;
 
-            boolean isOldCA = oldNrs != null ? (oldNrs.getDataSpecificInfo() != null
-                    ? oldNrs.getDataSpecificInfo().isUsingCarrierAggregation() : false) : false;
-            boolean isNewCA = newNrs!= null ? (newNrs. getDataSpecificInfo() != null
-                    ? newNrs. getDataSpecificInfo().isUsingCarrierAggregation() : false) : false;
+            boolean isOldCA = oldNrs != null ? oldNrs.isUsingCarrierAggregation() : false;
+            boolean isNewCA = newNrs != null ? newNrs.isUsingCarrierAggregation() : false;
 
             // If the carrier enable KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING and the operator name
             // match this pattern, the data rat display LteAdvanced indicator.
@@ -3295,12 +3293,15 @@
         boolean hasLocationChanged = mCellIdentity == null
                 ? primaryCellIdentity != null : !mCellIdentity.isSameCell(primaryCellIdentity);
 
-        // ratchet the new tech up through its rat family but don't drop back down
-        // until cell change or device is OOS
-        boolean isDataInService = mNewSS.getDataRegistrationState()
-                == ServiceState.STATE_IN_SERVICE;
-        if (isDataInService) {
-            mRatRatcheter.ratchet(mSS, mNewSS, hasLocationChanged);
+        boolean isRegisteredOnWwan = false;
+        for (NetworkRegistrationInfo nri : mNewSS.getNetworkRegistrationInfoListForTransportType(
+                AccessNetworkConstants.TRANSPORT_TYPE_WWAN)) {
+            isRegisteredOnWwan |= nri.isRegistered();
+        }
+
+        // Ratchet if the device is in service on the same cell
+        if (isRegisteredOnWwan && !hasLocationChanged) {
+            mRatRatcheter.ratchet(mSS, mNewSS);
         }
 
         boolean hasRilVoiceRadioTechnologyChanged =
diff --git a/src/java/com/android/internal/telephony/SmsDispatchersController.java b/src/java/com/android/internal/telephony/SmsDispatchersController.java
index 564197a..7f3de53 100644
--- a/src/java/com/android/internal/telephony/SmsDispatchersController.java
+++ b/src/java/com/android/internal/telephony/SmsDispatchersController.java
@@ -39,7 +39,6 @@
 import android.telephony.ServiceState;
 import android.telephony.SmsManager;
 import android.telephony.SmsMessage;
-import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.cdma.CdmaInboundSmsHandler;
@@ -52,7 +51,6 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Map.Entry;
 
 /**
  *
@@ -110,6 +108,26 @@
     private boolean mIms = false;
     private String mImsSmsFormat = SmsConstants.FORMAT_UNKNOWN;
 
+    /** 3GPP format sent messages awaiting a delivery status report. */
+    private HashMap<Integer, SMSDispatcher.SmsTracker> mDeliveryPendingMapFor3GPP = new HashMap<>();
+
+    /** 3GPP2 format sent messages awaiting a delivery status report. */
+    private HashMap<Integer, SMSDispatcher.SmsTracker> mDeliveryPendingMapFor3GPP2 =
+            new HashMap<>();
+
+    /**
+     * Puts a delivery pending tracker to the map based on the format.
+     *
+     * @param tracker the tracker awaiting a delivery status report.
+     */
+    public void putDeliveryPendingTracker(SMSDispatcher.SmsTracker tracker) {
+        if (isCdmaFormat(tracker.mFormat)) {
+            mDeliveryPendingMapFor3GPP2.put(tracker.mMessageRef, tracker);
+        } else {
+            mDeliveryPendingMapFor3GPP.put(tracker.mMessageRef, tracker);
+        }
+    }
+
     public SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor,
             SmsUsageMonitor usageMonitor) {
         Rlog.d(TAG, "SmsDispatchersController created");
@@ -760,86 +778,58 @@
     }
 
     /**
-     * Handles the sms status report for the sent sms through ImsSmsDispatcher. Carriers can send
-     * the report over CS even if the previously submitted SMS-SUBMIT was sent over IMS. For this
-     * case, finds a corresponding tracker from the tracker map in ImsSmsDispatcher and handles it.
+     * Handles the sms status report based on the format.
      *
-     * @param messageRef the TP-MR of the previously submitted SMS-SUBMIT in the report.
      * @param format the format.
      * @param pdu the pdu of the report.
+     * @return true if the report is handled successfully, false Otherwise.
      */
-    public void handleSentOverImsStatusReport(int messageRef, String format, byte[] pdu) {
-        for (Entry<Integer, SMSDispatcher.SmsTracker> entry :
-                mImsSmsDispatcher.mTrackers.entrySet()) {
-            int token = entry.getKey();
-            SMSDispatcher.SmsTracker tracker = entry.getValue();
-            if (tracker.mMessageRef == messageRef) {
-                Pair<Boolean, Boolean> result = handleSmsStatusReport(tracker, format, pdu);
-                if (result.second) {
-                    mImsSmsDispatcher.mTrackers.remove(token);
-                }
-                return;
-            }
-        }
-    }
-
-    /**
-     * Triggers the correct method for handling the sms status report based on the format.
-     *
-     * @param tracker the sms tracker.
-     * @param format the format.
-     * @param pdu the pdu of the report.
-     * @return a Pair in which the first boolean is whether the report was handled successfully
-     *          or not and the second boolean is whether processing the sms is complete and the
-     *          tracker no longer need to be kept track of, false if we should expect more callbacks
-     *          and the tracker should be kept.
-     */
-    public Pair<Boolean, Boolean> handleSmsStatusReport(SMSDispatcher.SmsTracker tracker,
-            String format, byte[] pdu) {
+    public boolean handleSmsStatusReport(String format, byte[] pdu) {
+        int messageRef;
+        SMSDispatcher.SmsTracker tracker;
+        boolean handled = false;
         if (isCdmaFormat(format)) {
-            return handleCdmaStatusReport(tracker, format, pdu);
+            com.android.internal.telephony.cdma.SmsMessage sms =
+                    com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu);
+            if (sms != null) {
+                messageRef = sms.mMessageRef;
+                tracker = mDeliveryPendingMapFor3GPP2.get(messageRef);
+                if (tracker != null) {
+                    // The status is composed of an error class (bits 25-24) and a status code
+                    // (bits 23-16).
+                    int errorClass = (sms.getStatus() >> 24) & 0x03;
+                    if (errorClass != ERROR_TEMPORARY) {
+                        // Update the message status (COMPLETE or FAILED)
+                        tracker.updateSentMessageStatus(
+                                mContext,
+                                (errorClass == ERROR_NONE)
+                                        ? Sms.STATUS_COMPLETE
+                                        : Sms.STATUS_FAILED);
+                        // No longer need to be kept.
+                        mDeliveryPendingMapFor3GPP2.remove(messageRef);
+                    }
+                    handled = triggerDeliveryIntent(tracker, format, pdu);
+                }
+            }
         } else {
-            return handleGsmStatusReport(tracker, format, pdu);
-        }
-    }
-
-    private Pair<Boolean, Boolean> handleCdmaStatusReport(SMSDispatcher.SmsTracker tracker,
-            String format, byte[] pdu) {
-        com.android.internal.telephony.cdma.SmsMessage sms =
-                com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu);
-        boolean complete = false;
-        boolean success = false;
-        if (sms != null) {
-            // The status is composed of an error class (bits 25-24) and a status code (bits 23-16).
-            int errorClass = (sms.getStatus() >> 24) & 0x03;
-            if (errorClass != ERROR_TEMPORARY) {
-                // Update the message status (COMPLETE or FAILED)
-                tracker.updateSentMessageStatus(
-                        mContext,
-                        (errorClass == ERROR_NONE) ? Sms.STATUS_COMPLETE : Sms.STATUS_FAILED);
-                complete = true;
+            com.android.internal.telephony.gsm.SmsMessage sms =
+                    com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu);
+            if (sms != null) {
+                messageRef = sms.mMessageRef;
+                tracker = mDeliveryPendingMapFor3GPP.get(messageRef);
+                if (tracker != null) {
+                    int tpStatus = sms.getStatus();
+                    if (tpStatus >= Sms.STATUS_FAILED || tpStatus < Sms.STATUS_PENDING) {
+                        // Update the message status (COMPLETE or FAILED)
+                        tracker.updateSentMessageStatus(mContext, tpStatus);
+                        // No longer need to be kept.
+                        mDeliveryPendingMapFor3GPP.remove(messageRef);
+                    }
+                    handled = triggerDeliveryIntent(tracker, format, pdu);
+                }
             }
-            success = triggerDeliveryIntent(tracker, format, pdu);
         }
-        return new Pair(success, complete);
-    }
-
-    private Pair<Boolean, Boolean> handleGsmStatusReport(SMSDispatcher.SmsTracker tracker,
-            String format, byte[] pdu) {
-        com.android.internal.telephony.gsm.SmsMessage sms =
-                com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu);
-        boolean complete = false;
-        boolean success = false;
-        if (sms != null) {
-            int tpStatus = sms.getStatus();
-            if(tpStatus >= Sms.STATUS_FAILED || tpStatus < Sms.STATUS_PENDING ) {
-                // Update the message status (COMPLETE or FAILED)
-                tracker.updateSentMessageStatus(mContext, tpStatus);
-                complete = true;
-            }
-            success = triggerDeliveryIntent(tracker, format, pdu);
-        }
-        return new Pair(success, complete);
+        return handled;
     }
 
     private boolean triggerDeliveryIntent(SMSDispatcher.SmsTracker tracker, String format,
diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java
index 2b23911..64d828b 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -36,6 +36,7 @@
 import android.graphics.BitmapFactory;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.ParcelUuid;
 import android.os.RegistrantList;
@@ -576,16 +577,18 @@
      * @hide
      */
     public SubscriptionInfo getSubscriptionInfo(int subId) {
-        // check cache for active subscriptions first, before querying db
-        for (SubscriptionInfo subInfo : mCacheActiveSubInfoList) {
-            if (subInfo.getSubscriptionId() == subId) {
-                return subInfo;
+        synchronized (mSubInfoListLock) {
+            // check cache for active subscriptions first, before querying db
+            for (SubscriptionInfo subInfo : mCacheActiveSubInfoList) {
+                if (subInfo.getSubscriptionId() == subId) {
+                    return subInfo;
+                }
             }
-        }
-        // check cache for opportunistic subscriptions too, before querying db
-        for (SubscriptionInfo subInfo : mCacheOpportunisticSubInfoList) {
-            if (subInfo.getSubscriptionId() == subId) {
-                return subInfo;
+            // check cache for opportunistic subscriptions too, before querying db
+            for (SubscriptionInfo subInfo : mCacheOpportunisticSubInfoList) {
+                if (subInfo.getSubscriptionId() == subId) {
+                    return subInfo;
+                }
             }
         }
 
@@ -1363,12 +1366,14 @@
         // validate the given info - does it exist in the active subscription list
         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
         int slotIndex = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
-        for (SubscriptionInfo info : mCacheActiveSubInfoList) {
-            if ((info.getSubscriptionType() == subscriptionType)
-                    && info.getIccId().equalsIgnoreCase(uniqueId)) {
-                subId = info.getSubscriptionId();
-                slotIndex = info.getSimSlotIndex();
-                break;
+        synchronized (mSubInfoListLock) {
+            for (SubscriptionInfo info : mCacheActiveSubInfoList) {
+                if ((info.getSubscriptionType() == subscriptionType)
+                        && info.getIccId().equalsIgnoreCase(uniqueId)) {
+                    subId = info.getSubscriptionId();
+                    slotIndex = info.getSimSlotIndex();
+                    break;
+                }
             }
         }
         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
@@ -1960,12 +1965,25 @@
     }
 
     /**
+     * Scrub given IMSI on production builds.
+     */
+    private String scrubImsi(String imsi) {
+        if (Build.IS_ENG) {
+            return imsi;
+        } else if (imsi != null) {
+            return imsi.substring(0, Math.min(6, imsi.length())) + "...";
+        } else {
+            return "null";
+        }
+    }
+
+    /**
      * Set IMSI by subscription ID
      * @param imsi IMSI (International Mobile Subscriber Identity)
      * @return the number of records updated
      */
     public int setImsi(String imsi, int subId) {
-        if (DBG) logd("[setImsi]+ imsi:" + imsi + " subId:" + subId);
+        if (DBG) logd("[setImsi]+ imsi:" + scrubImsi(imsi) + " subId:" + subId);
         ContentValues value = new ContentValues(1);
         value.put(SubscriptionManager.IMSI, imsi);
 
@@ -2594,11 +2612,13 @@
     }
 
     private boolean isSubscriptionVisible(int subId) {
-        for (SubscriptionInfo info : mCacheOpportunisticSubInfoList) {
-            if (info.getSubscriptionId() == subId) {
-                // If group UUID is null, it's stand alone opportunistic profile. So it's visible.
-                // otherwise, it's bundled opportunistic profile, and is not visible.
-                return info.getGroupUuid() == null;
+        synchronized (mSubInfoListLock) {
+            for (SubscriptionInfo info : mCacheOpportunisticSubInfoList) {
+                if (info.getSubscriptionId() == subId) {
+                    // If group UUID is null, it's stand alone opportunistic profile. So it's
+                    // visible. Otherwise, it's bundled opportunistic profile, and is not visible.
+                    return info.getGroupUuid() == null;
+                }
             }
         }
 
@@ -3884,9 +3904,11 @@
     private boolean shouldDisableSubGroup(ParcelUuid groupUuid) {
         if (groupUuid == null) return false;
 
-        for (SubscriptionInfo activeInfo : mCacheActiveSubInfoList) {
-            if (!activeInfo.isOpportunistic() && groupUuid.equals(activeInfo.getGroupUuid())) {
-                return false;
+        synchronized (mSubInfoListLock) {
+            for (SubscriptionInfo activeInfo : mCacheActiveSubInfoList) {
+                if (!activeInfo.isOpportunistic() && groupUuid.equals(activeInfo.getGroupUuid())) {
+                    return false;
+                }
             }
         }
 
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index 4877baf..a97224e 100644
--- a/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -22,7 +22,6 @@
 import android.os.Message;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
-import android.util.Pair;
 
 import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
 import com.android.internal.telephony.GsmCdmaPhone;
@@ -63,8 +62,9 @@
     @Override
     protected void handleStatusReport(Object o) {
         if (o instanceof SmsMessage) {
-            if (VDBG) Rlog.d(TAG, "calling handleCdmaStatusReport()");
-            handleCdmaStatusReport((SmsMessage) o);
+            if (VDBG) Rlog.d(TAG, "calling handleSmsStatusReport()");
+            byte[] pdu = ((SmsMessage) o).getPdu();
+            mSmsDispatchersController.handleSmsStatusReport(SmsConstants.FORMAT_3GPP2, pdu);
         } else {
             Rlog.e(TAG, "handleStatusReport() called for object type " + o.getClass().getName());
         }
@@ -95,32 +95,6 @@
     protected TextEncodingDetails calculateLength(CharSequence messageBody, boolean use7bitOnly) {
         return SMSDispatcherUtil.calculateLengthCdma(messageBody, use7bitOnly);
     }
-    /**
-     * Called from parent class to handle status report from {@code CdmaInboundSmsHandler}.
-     * @param sms the CDMA SMS message to process
-     */
-    @UnsupportedAppUsage
-    private void handleCdmaStatusReport(SmsMessage sms) {
-        byte[] pdu = sms.getPdu();
-        int messageRef = sms.mMessageRef;
-        boolean handled = false;
-        for (int i = 0, count = deliveryPendingList.size(); i < count; i++) {
-            SmsTracker tracker = deliveryPendingList.get(i);
-            if (tracker.mMessageRef == messageRef) {
-                Pair<Boolean, Boolean> result =
-                        mSmsDispatchersController.handleSmsStatusReport(tracker, getFormat(), pdu);
-                if (result.second) {
-                    deliveryPendingList.remove(i);
-                }
-                handled = true;
-                break; // Only expect to see one tracker matching this message.
-            }
-        }
-        if (!handled) {
-            // Try to find the sent SMS from the map in ImsSmsDispatcher.
-            mSmsDispatchersController.handleSentOverImsStatusReport(messageRef, getFormat(), pdu);
-        }
-    }
 
     /** {@inheritDoc} */
     @Override
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index bea9a00..8663961 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -1575,7 +1575,7 @@
                 }
 
                 for (InetAddress gateway : response.getGatewayAddresses()) {
-                    int mtu = gateway instanceof java.net.Inet6Address ? response.getMtuV6() 
+                    int mtu = gateway instanceof java.net.Inet6Address ? response.getMtuV6()
                             : response.getMtuV4();
                     // Allow 0.0.0.0 or :: as a gateway;
                     // this indicates a point-to-point interface.
@@ -1877,10 +1877,8 @@
                             DataConnection.this, mTransportType);
                     NetworkInfo networkInfo = mHandoverSourceNetworkAgent.getNetworkInfo();
                     if (networkInfo != null) {
-                        networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
-                                "dangling clean up", networkInfo.getExtraInfo());
-                        mHandoverSourceNetworkAgent.sendNetworkInfo(networkInfo,
-                                DataConnection.this);
+                        log("Cleared dangling network agent. " + mHandoverSourceNetworkAgent);
+                        mHandoverSourceNetworkAgent.unregister(DataConnection.this);
                     } else {
                         String str = "Failed to get network info.";
                         loge(str);
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java b/src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java
index 6aaadf5..5cfc599 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java
@@ -113,7 +113,12 @@
         UNDESIRED_POWER_STATE(true),
         INTERNAL_DATA_DISABLED(true),
         RADIO_DISABLED_BY_CARRIER(true),
-        APN_NOT_CONNECTABLE(true),
+        APN_NOT_CONNECTABLE(true),  // Not in the right state for data call setup.
+        DATA_IS_CONNECTING(true),   // Data is in connecting state. No need to send another setup
+                                    // request.
+        DATA_IS_DISCONNECTING(true),    // Data is being disconnected. Telephony will retry after
+                                        // disconnected.
+        DATA_ALREADY_CONNECTED(true),   // Data is already connected. No need to setup data again.
         ON_IWLAN(true),
         IN_ECBM(true),
         ON_OTHER_TRANSPORT(true);   // When data retry occurs, the given APN type's preferred
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcController.java b/src/java/com/android/internal/telephony/dataconnection/DcController.java
index 3809af5..8819b0e 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcController.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcController.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.telephony.dataconnection;
 
+import android.annotation.IntDef;
 import android.content.Context;
 import android.hardware.radio.V1_4.DataConnActiveStatus;
 import android.net.LinkAddress;
@@ -25,6 +26,7 @@
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
+import android.os.RegistrantList;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.DataFailCause;
 import android.telephony.PhoneStateListener;
@@ -42,6 +44,8 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -55,6 +59,24 @@
     private static final boolean DBG = true;
     private static final boolean VDBG = false;
 
+    /** Physical link state unknown */
+    public static final int PHYSICAL_LINK_UNKNOWN = 0;
+
+    /** Physical link state inactive (i.e. RRC idle) */
+    public static final int PHYSICAL_LINK_NOT_ACTIVE = 1;
+
+    /** Physical link state active (i.e. RRC connected) */
+    public static final int PHYSICAL_LINK_ACTIVE = 2;
+
+    /** @hide */
+    @IntDef(prefix = { "PHYSICAL_LINK_" }, value = {
+            PHYSICAL_LINK_UNKNOWN,
+            PHYSICAL_LINK_NOT_ACTIVE,
+            PHYSICAL_LINK_ACTIVE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PhysicalLinkState{}
+
     private final Phone mPhone;
     private final DcTracker mDct;
     private final DataServiceManager mDataServiceManager;
@@ -77,6 +99,16 @@
     private volatile boolean mExecutingCarrierChange;
 
     /**
+     * Aggregated physical link state from all data connections. This reflects the device's RRC
+     * connection state.
+     * // TODO: Instead of tracking the RRC state here, we should make PhysicalChannelConfig work in
+     *          S.
+     */
+    private @PhysicalLinkState int mPhysicalLinkState = PHYSICAL_LINK_UNKNOWN;
+
+    private RegistrantList mPhysicalLinkStateChangedRegistrants = new RegistrantList();
+
+    /**
      * Constructor.
      *
      * @param name to be used for the Controller
@@ -392,24 +424,33 @@
                 }
             }
 
-            if (isAnyDataCallDormant && !isAnyDataCallActive) {
-                // There is no way to indicate link activity per APN right now. So
-                // Link Activity will be considered dormant only when all data calls
-                // are dormant.
-                // If a single data call is in dormant state and none of the data
-                // calls are active broadcast overall link state as dormant.
-                if (DBG) {
-                    log("onDataStateChanged: Data Activity updated to DORMANT. stopNetStatePoll");
+            if (mDataServiceManager.getTransportType()
+                    == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
+                int physicalLinkState = isAnyDataCallActive
+                        ? PHYSICAL_LINK_ACTIVE : PHYSICAL_LINK_NOT_ACTIVE;
+                if (mPhysicalLinkState != physicalLinkState) {
+                    mPhysicalLinkState = physicalLinkState;
+                    mPhysicalLinkStateChangedRegistrants.notifyResult(mPhysicalLinkState);
                 }
-                mDct.sendStopNetStatPoll(DctConstants.Activity.DORMANT);
-            } else {
-                if (DBG) {
-                    log("onDataStateChanged: Data Activity updated to NONE. " +
-                            "isAnyDataCallActive = " + isAnyDataCallActive +
-                            " isAnyDataCallDormant = " + isAnyDataCallDormant);
-                }
-                if (isAnyDataCallActive) {
-                    mDct.sendStartNetStatPoll(DctConstants.Activity.NONE);
+                if (isAnyDataCallDormant && !isAnyDataCallActive) {
+                    // There is no way to indicate link activity per APN right now. So
+                    // Link Activity will be considered dormant only when all data calls
+                    // are dormant.
+                    // If a single data call is in dormant state and none of the data
+                    // calls are active broadcast overall link state as dormant.
+                    if (DBG) {
+                        log("onDataStateChanged: Data activity DORMANT. stopNetStatePoll");
+                    }
+                    mDct.sendStopNetStatPoll(DctConstants.Activity.DORMANT);
+                } else {
+                    if (DBG) {
+                        log("onDataStateChanged: Data Activity updated to NONE. "
+                                + "isAnyDataCallActive = " + isAnyDataCallActive
+                                + " isAnyDataCallDormant = " + isAnyDataCallDormant);
+                    }
+                    if (isAnyDataCallActive) {
+                        mDct.sendStartNetStatPoll(DctConstants.Activity.NONE);
+                    }
                 }
             }
 
@@ -434,6 +475,25 @@
     }
 
     /**
+     * Register for physical link state (i.e. RRC state) changed event.
+     *
+     * @param h The handler
+     * @param what The event
+     */
+    public void registerForPhysicalLinkStateChanged(Handler h, int what) {
+        mPhysicalLinkStateChangedRegistrants.addUnique(h, what, null);
+    }
+
+    /**
+     * Unregister from physical link state (i.e. RRC state) changed event.
+     *
+     * @param h The previously registered handler
+     */
+    public void unregisterForPhysicalLinkStateChanged(Handler h) {
+        mPhysicalLinkStateChangedRegistrants.remove(h);
+    }
+
+    /**
      * lr is short name for logAndAddLogRec
      * @param s
      */
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java b/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java
index c911dfd..5a15fab 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java
@@ -17,6 +17,7 @@
 package com.android.internal.telephony.dataconnection;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.net.KeepalivePacketData;
 import android.net.LinkProperties;
 import android.net.NattKeepalivePacketData;
@@ -32,6 +33,7 @@
 import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.AnomalyReporter;
 import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
 import android.util.LocalLog;
 import android.util.SparseArray;
 
@@ -45,8 +47,8 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.time.Duration;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 import java.util.UUID;
 
 /**
@@ -62,6 +64,8 @@
 public class DcNetworkAgent extends NetworkAgent {
     private final String mTag;
 
+    private final int mId;
+
     private Phone mPhone;
 
     private int mTransportType;
@@ -76,10 +80,8 @@
 
     private NetworkInfo mNetworkInfo;
 
-    // For debugging IMS redundant network agent issue.
-    private static List<DcNetworkAgent> sNetworkAgents = new ArrayList<>();
-
-    private static int sRedundantTimes = 0;
+    // For interface duplicate detection. Key is the net id, value is the interface name in string.
+    private static Map<Integer, String> sInterfaceNames = new ArrayMap<>();
 
     DcNetworkAgent(DataConnection dc, Phone phone, NetworkInfo ni, int score,
             NetworkAgentConfig config, NetworkProvider networkProvider, int transportType) {
@@ -87,36 +89,38 @@
                 dc.getNetworkCapabilities(), dc.getLinkProperties(), score, config,
                 networkProvider);
         register();
-        mTag = "DcNetworkAgent" + "-" + getNetwork().netId;
+        mId = getNetwork().netId;
+        mTag = "DcNetworkAgent" + "-" + mId;
         mPhone = phone;
         mNetworkCapabilities = dc.getNetworkCapabilities();
         mTransportType = transportType;
         mDataConnection = dc;
         mNetworkInfo = new NetworkInfo(ni);
         setLegacyExtraInfo(ni.getExtraInfo());
-        // TODO: Remove after b/151487565 is fixed.
-        sNetworkAgents.add(this);
-        checkRedundantIms();
-        logd(mTag + " created for data connection " + dc.getName());
+        if (dc.getLinkProperties() != null) {
+            checkDuplicateInterface(mId, dc.getLinkProperties().getInterfaceName());
+            logd("created for data connection " + dc.getName() + ", "
+                    + dc.getLinkProperties().getInterfaceName());
+        } else {
+            loge("The connection does not have a valid link properties.");
+        }
     }
 
-    // This is a temp code to catch the multiple IMS network agents issue.
-    // TODO: Remove after b/151487565 is fixed.
-    private void checkRedundantIms() {
-        if (sNetworkAgents.stream()
-                .filter(n -> n.mNetworkCapabilities.hasCapability(
-                        NetworkCapabilities.NET_CAPABILITY_IMS))
-                .count() > 1) {
-            sRedundantTimes++;
-            if (sRedundantTimes == 5) { // When it occurs 5 times.
-                String message = "Multiple IMS network agents detected.";
-                log(message);
+    private void checkDuplicateInterface(int netId, @Nullable String interfaceName) {
+        for (Map.Entry<Integer, String> entry: sInterfaceNames.entrySet()) {
+            if (Objects.equals(interfaceName, entry.getValue())) {
+                String message = "Duplicate interface " + interfaceName
+                        + " is detected. DcNetworkAgent-" + entry.getKey()
+                        + " already used this interface name.";
+                loge(message);
                 // Using fixed UUID to avoid duplicate bugreport notification
                 AnomalyReporter.reportAnomaly(
-                        UUID.fromString("a5cf4881-75ae-4129-a25d-71bc4293f493"),
+                        UUID.fromString("02f3d3f6-4613-4415-b6cb-8d92c8a938a6"),
                         message);
+                return;
             }
         }
+        sInterfaceNames.put(netId, interfaceName);
     }
 
     /**
@@ -147,7 +151,7 @@
             loge("releaseOwnership called on no-owner DcNetworkAgent!");
             return;
         } else if (mDataConnection != dc) {
-            log("releaseOwnership: This agent belongs to "
+            loge("releaseOwnership: This agent belongs to "
                     + mDataConnection.getName() + ", ignored the request from " + dc.getName());
             return;
         }
@@ -256,9 +260,11 @@
      * @param linkProperties The link properties
      * @param dc The data connection that invokes this method.
      */
-    public synchronized void sendLinkProperties(LinkProperties linkProperties,
+    public synchronized void sendLinkProperties(@NonNull LinkProperties linkProperties,
                                                 DataConnection dc) {
         if (!isOwned(dc, "sendLinkProperties")) return;
+
+        sInterfaceNames.put(mId, dc.getLinkProperties().getInterfaceName());
         sendLinkProperties(linkProperties);
     }
 
@@ -274,6 +280,19 @@
     }
 
     /**
+     * Unregister the network agent from connectivity service.
+     *
+     * @param dc The data connection that invokes this method.
+     */
+    public synchronized void unregister(DataConnection dc) {
+        if (!isOwned(dc, "unregister")) return;
+
+        logd("Unregister from connectivity service. " + sInterfaceNames.get(mId) + " removed.");
+        sInterfaceNames.remove(mId);
+        super.unregister();
+    }
+
+    /**
      * Set the network info.
      *
      * @param networkInfo The network info.
@@ -292,9 +311,7 @@
         }
         if ((oldState == NetworkInfo.State.SUSPENDED || oldState == NetworkInfo.State.CONNECTED)
                 && state == NetworkInfo.State.DISCONNECTED) {
-            logd("Unregister from connectivity service");
-            sNetworkAgents.remove(this);
-            unregister();
+            unregister(dc);
         }
         mNetworkInfo = new NetworkInfo(networkInfo);
     }
@@ -337,11 +354,13 @@
 
     @Override
     public String toString() {
-        return "DcNetworkAgent:"
+        return "DcNetworkAgent-"
+                + mId
                 + " mDataConnection="
                 + ((mDataConnection != null) ? mDataConnection.getName() : null)
                 + " mTransportType="
                 + AccessNetworkConstants.transportTypeToString(mTransportType)
+                + " " + ((mDataConnection != null) ? mDataConnection.getLinkProperties() : null)
                 + " mNetworkCapabilities=" + mNetworkCapabilities;
     }
 
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index a86bba7..2f1f871 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -1329,7 +1329,16 @@
 
         // Step 3. Build disallowed reasons.
         if (apnContext != null && !apnContext.isConnectable()) {
-            reasons.add(DataDisallowedReasonType.APN_NOT_CONNECTABLE);
+            DctConstants.State state = apnContext.getState();
+            if (state == DctConstants.State.CONNECTED) {
+                reasons.add(DataDisallowedReasonType.DATA_ALREADY_CONNECTED);
+            } else if (state == DctConstants.State.DISCONNECTING) {
+                reasons.add(DataDisallowedReasonType.DATA_IS_DISCONNECTING);
+            } else if (state == DctConstants.State.CONNECTING) {
+                reasons.add(DataDisallowedReasonType.DATA_IS_CONNECTING);
+            } else {
+                reasons.add(DataDisallowedReasonType.APN_NOT_CONNECTABLE);
+            }
         }
 
         // In legacy mode, if RAT is IWLAN then don't allow default/IA PDP at all.
@@ -1782,6 +1791,19 @@
         ArrayList<ApnSetting> dunCandidates = new ArrayList<ApnSetting>();
         ArrayList<ApnSetting> retDunSettings = new ArrayList<ApnSetting>();
 
+        if (mPhone.getServiceState().getRoaming()) {
+            CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
+                    .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+            if (configManager != null) {
+                PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId());
+                if (b != null) {
+                    if (b.getBoolean(CarrierConfigManager.KEY_DISABLE_DUN_APN_WHILE_ROAMING)) {
+                        return new ArrayList<>();
+                    }
+                }
+            }
+        }
+
         // Places to look for tether APN in order: TETHER_DUN_APN setting (to be deprecated soon),
         // APN database
         String apnData = Settings.Global.getString(mResolver, Settings.Global.TETHER_DUN_APN);
@@ -5094,4 +5116,23 @@
         }
         updateLinkBandwidths(bandwidths, useLte);
     }
+
+    /**
+     * Register for physical link state (i.e. RRC state) changed event.
+     *
+     * @param h The handler
+     * @param what The event
+     */
+    public void registerForPhysicalLinkStateChanged(Handler h, int what) {
+        mDcc.registerForPhysicalLinkStateChanged(h, what);
+    }
+
+    /**
+     * Unregister from physical link state (i.e. RRC state) changed event.
+     *
+     * @param h The previously registered handler
+     */
+    public void unregisterForPhysicalLinkStateChanged(Handler h) {
+        mDcc.unregisterForPhysicalLinkStateChanged(h);
+    }
 }
diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java
index 8cfde1f..3b55008 100644
--- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java
+++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java
@@ -59,7 +59,6 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
@@ -80,7 +79,9 @@
     private static final String EMERGENCY_NUMBER_DB_OTA_FILE_NAME = "emergency_number_db";
     private static final String EMERGENCY_NUMBER_DB_OTA_FILE_PATH =
             "misc/emergencynumberdb/" + EMERGENCY_NUMBER_DB_OTA_FILE_NAME;
-    private FileInputStream mEmergencyNumberDbOtaFileInputStream = null;
+
+    /** Used for storing overrided (non-default) OTA database file path */
+    private ParcelFileDescriptor mOverridedOtaDbParcelFileDescriptor = null;
 
     /** @hide */
     public static boolean DBG = false;
@@ -170,13 +171,6 @@
         mPhone = phone;
         mCi = ci;
 
-        try {
-            mEmergencyNumberDbOtaFileInputStream = new FileInputStream(
-                    new File(Environment.getDataDirectory(), EMERGENCY_NUMBER_DB_OTA_FILE_PATH));
-        } catch (FileNotFoundException ex) {
-            loge("Initialize ota emergency database file input failure: " + ex);
-        }
-
         if (mPhone != null) {
             CarrierConfigManager configMgr = (CarrierConfigManager)
                     mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
@@ -488,6 +482,7 @@
     }
 
     private int cacheOtaEmergencyNumberDatabase() {
+        FileInputStream fileInputStream = null;
         BufferedInputStream inputStream = null;
         ProtobufEccData.AllInfo allEccMessages = null;
         int otaDatabaseVersion = INVALID_DATABASE_VERSION;
@@ -496,11 +491,16 @@
         List<EmergencyNumber> updatedOtaEmergencyNumberList = new ArrayList<>();
         try {
             // If OTA File partition is not available, try to reload the default one.
-            if (mEmergencyNumberDbOtaFileInputStream == null) {
-                mEmergencyNumberDbOtaFileInputStream = new FileInputStream(
-                      new File(Environment.getDataDirectory(), EMERGENCY_NUMBER_DB_OTA_FILE_PATH));
+            if (mOverridedOtaDbParcelFileDescriptor == null) {
+                fileInputStream = new FileInputStream(
+                        new File(Environment.getDataDirectory(),
+                                EMERGENCY_NUMBER_DB_OTA_FILE_PATH));
+            } else {
+                File file = ParcelFileDescriptor
+                        .getFile(mOverridedOtaDbParcelFileDescriptor.getFileDescriptor());
+                fileInputStream = new FileInputStream(new File(file.getAbsolutePath()));
             }
-            inputStream = new BufferedInputStream(mEmergencyNumberDbOtaFileInputStream);
+            inputStream = new BufferedInputStream(fileInputStream);
             allEccMessages = ProtobufEccData.AllInfo.parseFrom(readInputStreamToByteArray(
                     new GZIPInputStream(inputStream)));
             logd(mCountryIso + " ota emergency database is loaded. Ver: " + otaDatabaseVersion);
@@ -517,7 +517,7 @@
         } catch (IOException ex) {
             loge("Cache ota emergency database IOException: " + ex);
         } finally {
-            // close quietly by catching non-runtime exceptions.
+            // Close quietly by catching non-runtime exceptions.
             if (inputStream != null) {
                 try {
                     inputStream.close();
@@ -526,6 +526,14 @@
                 } catch (Exception ignored) {
                 }
             }
+            if (fileInputStream != null) {
+                try {
+                    fileInputStream.close();
+                } catch (RuntimeException rethrown) {
+                    throw rethrown;
+                } catch (Exception ignored) {
+                }
+            }
         }
 
         // Use a valid database that has higher version.
@@ -606,17 +614,7 @@
     private void overrideOtaEmergencyNumberDbFilePath(
             ParcelFileDescriptor otaParcelableFileDescriptor) {
         logd("overrideOtaEmergencyNumberDbFilePath:" + otaParcelableFileDescriptor);
-        try {
-            if (otaParcelableFileDescriptor == null) {
-                mEmergencyNumberDbOtaFileInputStream = new FileInputStream(
-                    new File(Environment.getDataDirectory(), EMERGENCY_NUMBER_DB_OTA_FILE_PATH));
-            } else {
-                mEmergencyNumberDbOtaFileInputStream = new FileInputStream(
-                    otaParcelableFileDescriptor.getFileDescriptor());
-            }
-        } catch (FileNotFoundException ex) {
-            loge("Override ota emergency database failure: " + ex);
-        }
+        mOverridedOtaDbParcelFileDescriptor = otaParcelableFileDescriptor;
     }
 
     private void updateOtaEmergencyNumberListDatabaseAndNotify() {
diff --git a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
index 9d030a4..b386259 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -22,7 +22,6 @@
 import android.os.AsyncResult;
 import android.os.Message;
 import android.telephony.ServiceState;
-import android.util.Pair;
 
 import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
 import com.android.internal.telephony.InboundSmsHandler;
@@ -139,31 +138,7 @@
      */
     private void handleStatusReport(AsyncResult ar) {
         byte[] pdu = (byte[]) ar.result;
-        SmsMessage sms = SmsMessage.createFromPdu(pdu);
-        boolean handled = false;
-
-        if (sms != null) {
-            int messageRef = sms.mMessageRef;
-            for (int i = 0, count = deliveryPendingList.size(); i < count; i++) {
-                SmsTracker tracker = deliveryPendingList.get(i);
-                if (tracker.mMessageRef == messageRef) {
-                    Pair<Boolean, Boolean> result = mSmsDispatchersController.handleSmsStatusReport(
-                            tracker,
-                            getFormat(),
-                            pdu);
-                    if (result.second) {
-                        deliveryPendingList.remove(i);
-                    }
-                    handled = true;
-                    break; // Only expect to see one tracker matching this messageref
-                }
-            }
-            if (!handled) {
-                // Try to find the sent SMS from the map in ImsSmsDispatcher.
-                mSmsDispatchersController.handleSentOverImsStatusReport(
-                        messageRef, getFormat(), pdu);
-            }
-        }
+        mSmsDispatchersController.handleSmsStatusReport(SmsConstants.FORMAT_3GPP, pdu);
         mCi.acknowledgeLastIncomingGsmSms(true, 0 /* cause */, null);
     }
 
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index 66f2571..0e54e86 100755
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -2775,6 +2775,7 @@
                     removeConnection(mPendingMO);
                     mPendingMO.finalize();
                     mPendingMO = null;
+                    updatePhoneState();
                     mPhone.initiateSilentRedial();
                     return;
                 } else {
@@ -2782,6 +2783,17 @@
                 }
                 mMetrics.writeOnImsCallStartFailed(mPhone.getPhoneId(), imsCall.getCallSession(),
                         reasonInfo);
+            } else if (reasonInfo.getCode() == ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED
+                    && mForegroundCall.getState() == ImsPhoneCall.State.ALERTING) {
+                if (DBG) log("onCallStartFailed: Initiated call by silent redial"
+                        + " under ALERTING state.");
+                ImsPhoneConnection conn = findConnection(imsCall);
+                if (conn != null) {
+                    mForegroundCall.detach(conn);
+                    removeConnection(conn);
+                }
+                updatePhoneState();
+                mPhone.initiateSilentRedial();
             }
         }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java
index e2bacc2..3ff9995 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java
@@ -164,7 +164,7 @@
                 domain, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, voiceRegState,
                 ServiceState.rilRadioTechnologyToNetworkType(voiceRadioTech), reasonForDenial,
                 false, availableServices, null, "", maxDataCalls, false, false, false,
-                lteVopsSupportInfo, false);
+                lteVopsSupportInfo);
 
         try {
             verify(mCallback, timeout(1000).times(1)).onRequestNetworkRegistrationInfoComplete(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java
index d13152e..0a460e4 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java
@@ -32,7 +32,6 @@
 import android.telephony.SmsMessage;
 import android.telephony.ims.stub.ImsSmsImplBase;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Pair;
 
 import com.android.internal.util.HexDump;
 
@@ -149,22 +148,17 @@
     @Test
     @SmallTest
     public void testReceiveGsmSmsStatusReport() throws Exception {
-        int sentSmsToken = mImsSmsDispatcher.mNextToken.get();
         int statusReportToken = 456; // Generated by IMS providers
         int messageRef = 123; // TP-MR for sent SMS
-        int trackersSize = mImsSmsDispatcher.mTrackers.size();
         // PDU for SMS-STATUS-REPORT
         byte[] pdu = HexDump.hexStringToByteArray("0006000681214365919061800000639190618000006300");
 
         // Set TP-MR
         pdu[2] = (byte) messageRef;
-        mSmsTracker.mMessageRef = messageRef;
 
-        mImsSmsDispatcher.mTrackers.put(sentSmsToken, mSmsTracker);
         when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM);
-        when(mSmsDispatchersController.handleSmsStatusReport(
-                    eq(mSmsTracker), eq(SmsMessage.FORMAT_3GPP), eq(pdu)))
-                .thenReturn(new Pair(true, true));
+        when(mSmsDispatchersController.handleSmsStatusReport(eq(SmsMessage.FORMAT_3GPP), eq(pdu)))
+                .thenReturn(true);
 
         // Receive the status report
         mImsSmsDispatcher
@@ -177,7 +171,6 @@
                         eq(statusReportToken),
                         eq(messageRef),
                         eq(ImsSmsImplBase.STATUS_REPORT_STATUS_OK));
-        assertEquals(trackersSize, mImsSmsDispatcher.mTrackers.size());
     }
 
     /**
diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java
index b34821e..001ba39 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java
@@ -32,6 +32,7 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import com.android.internal.telephony.dataconnection.DcController;
 import com.android.internal.util.IState;
 import com.android.internal.util.StateMachine;
 
@@ -49,14 +50,14 @@
     private static final int EVENT_DATA_RAT_CHANGED = 2;
     private static final int EVENT_NR_STATE_CHANGED = 3;
     private static final int EVENT_NR_FREQUENCY_CHANGED = 4;
-    private static final int EVENT_DATA_ACTIVITY_CHANGED = 5;
+    private static final int EVENT_PHYSICAL_LINK_STATE_CHANGED = 5;
     private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED = 6;
     private static final int EVENT_CARRIER_CONFIG_CHANGED = 7;
     private static final int EVENT_PRIMARY_TIMER_EXPIRED = 8;
     private static final int EVENT_SECONDARY_TIMER_EXPIRED = 9;
     private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 10;
-    private static final int EVENT_DATA_CONNECTION_STATE_CHANGED = 11;
-    private static final int EVENT_PREFERRED_NETWORK_MODE_CHANGED = 12;
+    private static final int EVENT_PREFERRED_NETWORK_MODE_CHANGED = 11;
+    private static final int EVENT_INITIALIZE = 12;
 
     private NetworkTypeController mNetworkTypeController;
     private PersistableBundle mBundle;
@@ -94,6 +95,7 @@
         doReturn(TelephonyManager.NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA).when(mPhone)
                 .getCachedPreferredNetworkType();
         mNetworkTypeController = new NetworkTypeController(mPhone, mDisplayInfoController);
+        processAllMessages();
     }
 
     @After
@@ -190,9 +192,8 @@
         assertEquals("DefaultState", getCurrentState().getName());
         doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType();
         doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState();
-        doReturn(PhoneInternalInterface.DataActivityState.DORMANT)
-                .when(mPhone).getDataActivityState();
-
+        mNetworkTypeController.sendMessage(EVENT_PHYSICAL_LINK_STATE_CHANGED,
+                new AsyncResult(null, DcController.PHYSICAL_LINK_NOT_ACTIVE, null));
         mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE);
         processAllMessages();
         assertEquals("not_restricted_rrc_idle", getCurrentState().getName());
@@ -203,9 +204,8 @@
         assertEquals("DefaultState", getCurrentState().getName());
         doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType();
         doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState();
-        doReturn(PhoneInternalInterface.DataActivityState.DATAINANDOUT)
-                .when(mPhone).getDataActivityState();
-
+        mNetworkTypeController.sendMessage(EVENT_PHYSICAL_LINK_STATE_CHANGED,
+                new AsyncResult(null, DcController.PHYSICAL_LINK_ACTIVE, null));
         mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE);
         processAllMessages();
         assertEquals("not_restricted_rrc_con", getCurrentState().getName());
@@ -284,9 +284,8 @@
         testTransitionToCurrentStateNrConnectedMmwave();
         doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType();
         doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState();
-        doReturn(PhoneInternalInterface.DataActivityState.DATAINANDOUT)
-                .when(mPhone).getDataActivityState();
-
+        mNetworkTypeController.sendMessage(EVENT_PHYSICAL_LINK_STATE_CHANGED,
+                new AsyncResult(null, DcController.PHYSICAL_LINK_ACTIVE, null));
         mNetworkTypeController.sendMessage(EVENT_NR_FREQUENCY_CHANGED);
         mNetworkTypeController.sendMessage(EVENT_NR_STATE_CHANGED);
         processAllMessages();
@@ -295,13 +294,11 @@
     }
 
     @Test
-    public void testEventDataActivityChanged() throws Exception {
+    public void testEventPhysicalLinkStateChanged() throws Exception {
         testTransitionToCurrentStateLteConnected();
         doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange();
-        doReturn(PhoneInternalInterface.DataActivityState.DORMANT)
-                .when(mPhone).getDataActivityState();
-
-        mNetworkTypeController.sendMessage(EVENT_DATA_ACTIVITY_CHANGED);
+        mNetworkTypeController.sendMessage(EVENT_PHYSICAL_LINK_STATE_CHANGED,
+                new AsyncResult(null, DcController.PHYSICAL_LINK_NOT_ACTIVE, null));
         processAllMessages();
         assertEquals("not_restricted_rrc_idle", getCurrentState().getName());
     }
@@ -335,27 +332,6 @@
     }
 
     @Test
-    public void testEventDataConnectionStateChanged() throws Exception {
-        testTransitionToCurrentStateNrConnected();
-        assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA,
-                mNetworkTypeController.getOverrideNetworkType());
-
-        // TelephonyDisplayInfo can't be mocked since it's final, so create a new one for testing
-        TelephonyDisplayInfo telephonyDisplayInfo = new TelephonyDisplayInfo(
-                TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE);
-
-        doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState();
-        doReturn(telephonyDisplayInfo).when(mDisplayInfoController).getTelephonyDisplayInfo();
-        doReturn(TelephonyManager.NETWORK_TYPE_HSPAP).when(mServiceState).getDataNetworkType();
-
-        mNetworkTypeController.sendMessage(EVENT_DATA_CONNECTION_STATE_CHANGED);
-        processAllMessages();
-        assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE,
-                mNetworkTypeController.getOverrideNetworkType());
-    }
-
-    @Test
     public void testEventPreferredNetworkModeChanged() throws Exception {
         testTransitionToCurrentStateNrConnected();
         assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA,
@@ -373,6 +349,7 @@
 
     @Test
     public void testPrimaryTimerExpire() throws Exception {
+        doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType();
         doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState();
         mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING,
                 "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10");
@@ -402,6 +379,7 @@
 
     @Test
     public void testPrimaryTimerReset() throws Exception {
+        doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType();
         doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState();
         mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING,
                 "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10");
@@ -436,6 +414,7 @@
 
     @Test
     public void testPrimaryTimerExpireMmwave() throws Exception {
+        doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType();
         doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState();
         doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange();
         mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING,
@@ -467,6 +446,7 @@
 
     @Test
     public void testPrimaryTimerResetMmwave() throws Exception {
+        doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType();
         doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState();
         doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange();
         mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING,
@@ -502,6 +482,7 @@
 
     @Test
     public void testSecondaryTimerExpire() throws Exception {
+        doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType();
         doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState();
         mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING,
                 "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10");
@@ -542,6 +523,7 @@
 
     @Test
     public void testSecondaryTimerReset() throws Exception {
+        doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType();
         doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState();
         mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING,
                 "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10");
@@ -587,6 +569,7 @@
 
     @Test
     public void testSecondaryTimerExpireMmwave() throws Exception {
+        doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType();
         doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState();
         doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange();
         mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING,
@@ -628,6 +611,7 @@
 
     @Test
     public void testSecondaryTimerResetMmwave() throws Exception {
+        doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType();
         doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState();
         doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange();
         mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING,
@@ -671,4 +655,39 @@
         assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE,
                 mNetworkTypeController.getOverrideNetworkType());
     }
+
+    @Test
+    public void testNrTimerResetIn3g() throws Exception {
+        doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType();
+        doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState();
+        doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange();
+        mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING,
+                "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10");
+        mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING,
+                "connected_mmwave,any,30");
+        broadcastCarrierConfigs();
+
+        assertEquals("connected_mmwave", getCurrentState().getName());
+        assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE,
+                mNetworkTypeController.getOverrideNetworkType());
+
+        // should trigger 10 second primary timer
+        doReturn(ServiceState.FREQUENCY_RANGE_LOW).when(mServiceState).getNrFrequencyRange();
+        mNetworkTypeController.sendMessage(EVENT_NR_FREQUENCY_CHANGED);
+        processAllMessages();
+
+        assertEquals("connected", getCurrentState().getName());
+        assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE,
+                mNetworkTypeController.getOverrideNetworkType());
+
+        // rat is UMTS, should stop timer
+        doReturn(TelephonyManager.NETWORK_TYPE_UMTS).when(mServiceState).getDataNetworkType();
+        doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState();
+        mNetworkTypeController.sendMessage(EVENT_DATA_RAT_CHANGED);
+        processAllMessages();
+
+        assertEquals("legacy", getCurrentState().getName());
+        assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE,
+                mNetworkTypeController.getOverrideNetworkType());
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
index 1fa781e..0ed994f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
@@ -110,6 +110,7 @@
 import android.hardware.radio.V1_0.RadioError;
 import android.hardware.radio.V1_0.RadioResponseInfo;
 import android.hardware.radio.V1_0.RadioResponseType;
+import android.hardware.radio.V1_0.RadioTechnologyFamily;
 import android.hardware.radio.V1_0.SmsWriteArgs;
 import android.hardware.radio.V1_5.IRadio;
 import android.hardware.radio.deprecated.V1_0.IOemHook;
@@ -927,13 +928,13 @@
         gsmMsg.pdu = pdu;
 
         ImsSmsMessage firstMsg = new ImsSmsMessage();
-        firstMsg.tech = RILConstants.GSM_PHONE;
+        firstMsg.tech = RadioTechnologyFamily.THREE_GPP;
         firstMsg.retry = false;
         firstMsg.messageRef = 0;
         firstMsg.gsmMessage.add(gsmMsg);
 
         ImsSmsMessage retryMsg = new ImsSmsMessage();
-        retryMsg.tech = RILConstants.GSM_PHONE;
+        retryMsg.tech = RadioTechnologyFamily.THREE_GPP;
         retryMsg.retry = true;
         retryMsg.messageRef = 0;
         retryMsg.gsmMessage.add(gsmMsg);
@@ -962,13 +963,13 @@
         CdmaSmsMessage cdmaMsg = new CdmaSmsMessage();
 
         ImsSmsMessage firstMsg = new ImsSmsMessage();
-        firstMsg.tech = RILConstants.CDMA_PHONE;
+        firstMsg.tech = RadioTechnologyFamily.THREE_GPP2;
         firstMsg.retry = false;
         firstMsg.messageRef = 0;
         firstMsg.cdmaMessage.add(cdmaMsg);
 
         ImsSmsMessage retryMsg = new ImsSmsMessage();
-        retryMsg.tech = RILConstants.CDMA_PHONE;
+        retryMsg.tech = RadioTechnologyFamily.THREE_GPP2;
         retryMsg.retry = true;
         retryMsg.messageRef = 0;
         retryMsg.cdmaMessage.add(cdmaMsg);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RatRatcheterTest.java b/tests/telephonytests/src/com/android/internal/telephony/RatRatcheterTest.java
index b0cc83e..c378995 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/RatRatcheterTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/RatRatcheterTest.java
@@ -104,8 +104,7 @@
                 false,  // isDcNrRestricted
                 false,  // isNrAvailable
                 false,  // isEndcAvailable
-                lteVopsSupportInfo,  // lteVopsSupportInfo
-                isUsingCarrierAggregation);  // isUsingCarrierAggregation
+                lteVopsSupportInfo);  // lteVopsSupportInfo
     }
 
     private void setNetworkRegistrationInfo(ServiceState ss, int accessNetworkTechnology) {
@@ -141,7 +140,7 @@
         setNetworkRegistrationInfo(newSS, TelephonyManager.NETWORK_TYPE_LTE);
 
         RatRatcheter ratRatcheter = new RatRatcheter(mPhone);
-        ratRatcheter.ratchet(oldSS, newSS, false);
+        ratRatcheter.ratchet(oldSS, newSS);
 
         assertTrue(newSS.isUsingCarrierAggregation());
     }
@@ -158,7 +157,7 @@
         setNetworkRegistrationInfo(newSS, TelephonyManager.NETWORK_TYPE_LTE);
 
         RatRatcheter ratRatcheter = new RatRatcheter(mPhone);
-        ratRatcheter.ratchet(oldSS, newSS, false);
+        ratRatcheter.ratchet(oldSS, newSS);
 
         assertFalse(newSS.isUsingCarrierAggregation());
     }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTest.java
index 7bb6476..9057935 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTest.java
@@ -335,7 +335,7 @@
 
         wwanDataRegState = new NetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
-                0, 0, 0, true, null, null, "", 0, false, false, false, lteVopsSupportInfo, false);
+                0, 0, 0, true, null, null, "", 0, false, false, false, lteVopsSupportInfo);
         ss.addNetworkRegistrationInfo(wwanDataRegState);
         assertEquals(ss.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN), wwanDataRegState);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
index 2d3d7a4..86201cd 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
@@ -314,10 +314,10 @@
                 });
         mBundle.putIntArray(CarrierConfigManager.KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY,
                 new int[] {
-                    -16, /* SIGNAL_STRENGTH_POOR */
-                    -12, /* SIGNAL_STRENGTH_MODERATE */
-                    -9, /* SIGNAL_STRENGTH_GOOD */
-                    -6  /* SIGNAL_STRENGTH_GREAT */
+                    -31, /* SIGNAL_STRENGTH_POOR */
+                    -19, /* SIGNAL_STRENGTH_MODERATE */
+                    -7, /* SIGNAL_STRENGTH_GOOD */
+                    6  /* SIGNAL_STRENGTH_GREAT */
                 });
         mBundle.putIntArray(CarrierConfigManager.KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY,
                 new int[] {
@@ -790,7 +790,7 @@
                     -20, /** csiRsrq NONE */
                     -23, /** CsiSinr NONE */
                     -44, /** SsRsrp SIGNAL_STRENGTH_GREAT */
-                    -20, /** SsRsrq NONE */
+                    -32, /** SsRsrq NONE */
                     -23) /** SsSinr NONE */
         );
 
@@ -1911,7 +1911,7 @@
         NetworkRegistrationInfo dataResult = new NetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 state, dataRat, 0, false, null, cid, getPlmnFromCellIdentity(cid),
-                1, false, false, false, lteVopsSupportInfo, false);
+                1, false, false, false, lteVopsSupportInfo);
         sst.mPollingContext[0] = 2;
         // update data reg state to be in service
         sst.sendMessage(sst.obtainMessage(
@@ -1939,7 +1939,7 @@
         NetworkRegistrationInfo dataResult = new NetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 state, dataRat, 0, false, null, cid, getPlmnFromCellIdentity(cid),
-                1, false, false, false, lteVopsSupportInfo, false);
+                1, false, false, false, lteVopsSupportInfo);
         sst.sendMessage(sst.obtainMessage(
                 ServiceStateTracker.EVENT_POLL_STATE_PS_CELLULAR_REGISTRATION,
                 new AsyncResult(sst.mPollingContext, dataResult, null)));
@@ -1958,7 +1958,7 @@
         NetworkRegistrationInfo dataIwlanResult = new NetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
                 iwlanState, iwlanDataRat, 0, false,
-                null, null, "", 1, false, false, false, lteVopsSupportInfo, false);
+                null, null, "", 1, false, false, false, lteVopsSupportInfo);
         sst.sendMessage(sst.obtainMessage(
                 ServiceStateTracker.EVENT_POLL_STATE_PS_IWLAN_REGISTRATION,
                 new AsyncResult(sst.mPollingContext, dataIwlanResult, null)));
@@ -2024,30 +2024,6 @@
 
     }
 
-    // TODO(nharold): This actually seems like broken behavior; rather than preserve it, we should
-    // probably remove it.
-    // GSM, Edge, GPRS are grouped under the same family where Edge > GPRS > GSM.
-    // Expect no rat update from E to G immediately following cell id change.
-    // Expect ratratchet (from G to E) for the following rat update within the cell location.
-    @Test
-    public void testRatRatchetWithCellChangeBeforeRatChange() throws Exception {
-        // cell ID update
-        CellIdentityGsm cellIdentity =
-                new CellIdentityGsm(0, 1, 900, 5, "001", "01", "test", "tst",
-                        Collections.emptyList());
-        changeRegState(1, cellIdentity, 16, 2);
-        assertEquals(ServiceState.STATE_IN_SERVICE, sst.getCurrentDataConnectionState());
-        assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_EDGE, sst.mSS.getRilDataRadioTechnology());
-
-        // RAT: EDGE -> GPRS, cell ID unchanged. Expect no rat ratchet following cell Id change.
-        changeRegState(1, cellIdentity, 16, 1);
-        assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_GPRS, sst.mSS.getRilDataRadioTechnology());
-
-        // RAT: GPRS -> EDGE should ratchet.
-        changeRegState(1, cellIdentity, 16, 2);
-        assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_EDGE, sst.mSS.getRilDataRadioTechnology());
-    }
-
     private void sendPhyChanConfigChange(int[] bandwidths) {
         ArrayList<PhysicalChannelConfig> pc = new ArrayList<>();
         int ssType = PhysicalChannelConfig.CONNECTION_PRIMARY_SERVING;
@@ -2073,7 +2049,7 @@
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME, TelephonyManager.NETWORK_TYPE_LTE,
                 0, false, null, cellId, getPlmnFromCellIdentity(cellId), 1, false, false, false,
-                lteVopsSupportInfo, false);
+                lteVopsSupportInfo);
         NetworkRegistrationInfo voiceResult = new NetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME, TelephonyManager.NETWORK_TYPE_LTE,
@@ -2149,7 +2125,7 @@
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING,
                 TelephonyManager.NETWORK_TYPE_UNKNOWN, 0, false, null, null, "", 1, false, false,
-                false, lteVopsSupportInfo, false);
+                false, lteVopsSupportInfo);
         NetworkRegistrationInfo voiceResult = new NetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING,
@@ -2343,7 +2319,7 @@
         NetworkRegistrationInfo dataResult = new NetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME, TelephonyManager.NETWORK_TYPE_LTE,
-                0, false, null, cellId, "00101", 1, false, false, false, lteVopsSupportInfo, false);
+                0, false, null, cellId, "00101", 1, false, false, false, lteVopsSupportInfo);
         sst.mPollingContext[0] = 2;
 
         sst.sendMessage(sst.obtainMessage(
@@ -2373,7 +2349,7 @@
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME,
                 TelephonyManager.NETWORK_TYPE_LTE, 0, false, null, cellId, "00101",
-                1, false, false, false, lteVopsSupportInfo, false);
+                1, false, false, false, lteVopsSupportInfo);
         sst.mPollingContext[0] = 1;
         sst.sendMessage(sst.obtainMessage(
                 ServiceStateTracker.EVENT_POLL_STATE_PS_CELLULAR_REGISTRATION,
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java
index 9c1d1a8..a0c9913 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java
@@ -36,6 +36,7 @@
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Looper;
+import android.telephony.AccessNetworkConstants;
 import android.telephony.data.ApnSetting;
 import android.telephony.data.DataCallResponse;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -99,6 +100,8 @@
         LinkProperties lp = new LinkProperties();
         mResult = new UpdateLinkPropertyResult(lp);
         doReturn(mResult).when(mDc).updateLinkProperty(any(DataCallResponse.class));
+        doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+                .when(mDataServiceManager).getTransportType();
 
         mDcc = DcController.makeDcc(mPhone, mDcTracker, mDataServiceManager,
                 new Handler(Looper.myLooper()), "");
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 8ae9e5b..6dd37fd 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
@@ -1380,6 +1380,26 @@
         assertTrue(dunApnExpected.equals(dunApns.get(0)));
     }
 
+    @Test
+    @SmallTest
+    public void testFetchDunApnWhileRoaming() {
+        doReturn(true).when(mServiceState).getRoaming();
+        mBundle.putBoolean(CarrierConfigManager.KEY_DISABLE_DUN_APN_WHILE_ROAMING, true);
+
+        sendInitializationEvents();
+
+        String dunApnString = "[ApnSettingV3]HOT mobile PC,pc.hotm,,,,,,,,,440,10,,DUN,,,true,"
+                + "0,,,,,,,,";
+
+        Settings.Global.putString(mContext.getContentResolver(),
+                Settings.Global.TETHER_DUN_APN, dunApnString);
+        // Expect empty DUN APN list
+        assertEquals(0, mDct.fetchDunApns().size());
+
+        Settings.Global.putString(mContext.getContentResolver(),
+                Settings.Global.TETHER_DUN_APN, null);
+    }
+
     // Test oos
     @Test
     @SmallTest