Merge "Unit Tests for CellInfo Timestamp"
diff --git a/Android.bp b/Android.bp
index 4925d51..7530b7a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -57,7 +57,6 @@
     static_libs: [
         "telephony-protos",
         "ecc-protos-lite",
-        "android-support-annotations",
     ],
 
     product_variables: {
diff --git a/proto/src/telephony.proto b/proto/src/telephony.proto
index 14e2e12..28e1355 100644
--- a/proto/src/telephony.proto
+++ b/proto/src/telephony.proto
@@ -50,6 +50,9 @@
 
   // Hardware revision (EVT, DVT, PVT etc.)
   optional string hardware_revision = 9;
+
+  // The last active subscription info for each slot.
+  repeated ActiveSubscriptionInfo last_active_subscription_info = 10;
 }
 
 // The time information
@@ -276,9 +279,6 @@
 
   // Current data radio technology
   optional RadioAccessTechnology data_rat = 6 [default = UNKNOWN];
-
-  // All the active subscription information.
-  repeated ActiveSubscriptionInfo active_subscription_info = 7;
 }
 
 // Radio access families
@@ -619,9 +619,6 @@
 
   // The network interface name e.g. wlan0, rmnet_data0.
   optional string iframe = 3;
-
-  // All the active subscription information.
-  repeated ActiveSubscriptionInfo active_subscription_info = 4;
 }
 
 message TelephonyEvent {
@@ -675,73 +672,99 @@
     // Carrier Key Change event.
     CARRIER_KEY_CHANGED = 14;
 
-    // Phone status change event.
-    PHONE_STATUS_CHANGED = 15;
-
     // Data switch event.
-    DATA_SWITCH = 16;
+    DATA_SWITCH = 15;
 
     // Network validate event.
-    NETWORK_VALIDATE = 17;
+    NETWORK_VALIDATE = 16;
 
     // On deman data switch event.
-    ON_DEMAND_DATA_SWITCH = 18;
+    ON_DEMAND_DATA_SWITCH = 17;
+
+    // SIM state change event.
+    SIM_STATE_CHANGED = 18;
+
+    // Active subscription info change event.
+    ACTIVE_SUBSCRIPTION_INFO_CHANGED = 19;
+
+    // Enabled modem change event.
+    ENABLED_MODEM_CHANGED = 20;
   }
 
   enum ApnType {
-      DEFAULT = 0;
-      MMS = 1;
-      SUPL = 2;
-      DUN = 3;
-      HIPRI = 4;
-      FOTA = 5;
-      IMS = 6;
-      CBS = 7;
-      IA = 8;
-      EMERGENCY = 9;
+    APN_TYPE_UNKNOWN = 0;
+
+    APN_TYPE_DEFAULT = 1;
+
+    APN_TYPE_MMS = 2;
+
+    APN_TYPE_SUPL = 3;
+
+    APN_TYPE_DUN = 4;
+
+    APN_TYPE_HIPRI = 5;
+
+    APN_TYPE_FOTA = 6;
+
+    APN_TYPE_IMS = 7;
+
+    APN_TYPE_CBS = 8;
+
+    APN_TYPE_IA = 9;
+
+    APN_TYPE_EMERGENCY = 10;
   }
 
   enum EventState {
-      START = 0;
-      END = 1;
+    EVENT_STATE_UNKNOWN = 0;
+
+    EVENT_STATE_START = 1;
+
+    EVENT_STATE_END = 2;
   }
 
   enum NetworkValidationState {
-      /** The network under validation is initial established. */
-      AVAILABLE = 0;
+    /** The network validation state is unknown. */
+    NETWORK_VALIDATION_STATE_UNKNOWN = 0;
 
-      /** The validation is failed. */
-      FAILED = 1;
+    /** The network under validation is initial established. */
+    NETWORK_VALIDATION_STATE_AVAILABLE = 1;
 
-      /** The validation is passed. */
-      PASSED = 2;
+    /** The validation is failed. */
+    NETWORK_VALIDATION_STATE_FAILED = 2;
+
+    /** The validation is passed. */
+    NETWORK_VALIDATION_STATE_PASSED = 3;
   }
 
   message DataSwitch {
-      enum Reason {
-          /** Data switch caused by user's manual switch. */
-          MANUAL = 0;
+    enum Reason {
+      /** Data switch caused by unknown reason. */
+      DATA_SWITCH_REASON_UNKNOWN = 0;
 
-          /** Data switch caused by incoming/outgoing call. */
-          IN_CALL = 1;
+      /** Data switch caused by user's manual switch. */
+      DATA_SWITCH_REASON_MANUAL = 1;
 
-          /** Data switch caused by CBRS switch. */
-          CBRS = 2;
-      }
+      /** Data switch caused by incoming/outgoing call. */
+      DATA_SWITCH_REASON_IN_CALL = 2;
 
-      /** The reason for data switch. */
-      optional Reason reason = 1;
+      /** Data switch caused by CBRS switch. */
+      DATA_SWITCH_REASON_CBRS = 3;
+    }
 
-      /** Current state of the data switch event. */
-      optional EventState state = 2;
+    /** The reason for data switch. */
+    optional Reason reason = 1;
+
+    /** Current state of the data switch event. */
+    optional EventState state = 2;
   }
 
   message OnDemandDataSwitch {
-      /** The apn associated with this event. */
-      optional ApnType apn = 1;
+    /** The apn associated with this event. */
+    optional ApnType apn = 1;
 
-      /** Current state of the on demand data switch event. */
-      optional EventState state = 2;
+    /** Current state of the on demand data switch event. */
+    optional EventState state = 2;
   }
 
   // Setup a packet data connection
@@ -1536,17 +1559,6 @@
     optional string mccmnc = 3;
   }
 
-  message PhoneStatus {
-      /** The sim state of each active slot. */
-      repeated SimState sim_state = 1;
-
-      /**
-       * The modem state represent by a bitmap, the i-th bit(LSB) indicates the i-th modem
-       * state(0 - disabled, 1 - enabled).
-       */
-      optional int32 enabled_modem_bitmap = 2;
-  }
-
   // Time when event happened on device, in milliseconds since epoch
   optional int64 timestamp_millis = 1;
 
@@ -1598,9 +1610,6 @@
   // Carrier key change
   optional CarrierKeyChange carrier_key_change = 17;
 
-  // Phone status
-  optional PhoneStatus phone_status = 18;
-
   // Data switch event
   optional DataSwitch data_switch = 19;
 
@@ -1609,31 +1618,41 @@
 
   // On demand data switch event
   optional OnDemandDataSwitch on_demand_data_switch = 21;
+
+  // Sim state for each slot.
+  repeated SimState sim_state = 22;
+
+  // The active subscription info for a specific slot.
+  optional ActiveSubscriptionInfo active_subscription_info = 23;
+
+  // The modem state represent by a bitmap, the i-th bit(LSB) indicates the i-th modem
+  // state (0 - disabled, 1 - enabled).
+  optional int32 enabled_modem_bitmap = 24;
 }
 
 message ActiveSubscriptionInfo {
-    /** The slot index which this subscription associated with. */
-    optional int32 slot_index = 1;
+  /** The slot index which this subscription is associated with. */
+  optional int32 slot_index = 1;
 
-    /** The Carrier id of this subscription. */
-    optional int32 carrier_id = 2;
+  /** The Carrier id of this subscription. -1 indicates unknown value. */
+  optional int32 carrier_id = 2;
 
-    /** whether subscription is opportunistic. */
-    optional bool is_opportunistic = 3;
+  /** whether subscription is opportunistic (0 - false, 1 - true, -1 - unknown). */
+  optional int32 is_opportunistic = 3;
 };
 
 enum SimState {
-    /**
-     * SIM card is inserted, but the state is unknown. Typically happened when the SIM is inserted
-     * but not loaded.
-     */
-    SIM_STATE_UNKNOWN = 0;
+  /**
+   * SIM card is inserted, but the state is unknown. Typically happened when the SIM is inserted
+   * but not loaded.
+   */
+  SIM_STATE_UNKNOWN = 0;
 
-    /** No SIM card is inserted in the slot. */
-    SIM_STATE_ABSENT = 1;
+  /** No SIM card is inserted in the slot. */
+  SIM_STATE_ABSENT = 1;
 
-    /** SIM card applications have been loaded. */
-    SIM_STATE_LOADED = 2;
+  /** SIM card applications have been loaded. */
+  SIM_STATE_LOADED = 2;
 };
 
 enum TimeInterval {
@@ -2001,12 +2020,6 @@
 
   // Indicating some call events are dropped
   optional bool events_dropped = 4;
-
-  // SIM state of the active slots
-  repeated SimState sim_states = 5;
-
-  // All the active subscription information.
-  repeated ActiveSubscriptionInfo active_subscription_info = 6;
 }
 
 message SmsSession {
@@ -2221,12 +2234,6 @@
 
   // Indicating some sms session events are dropped
   optional bool events_dropped = 4;
-
-  // SIM state of the active slots.
-  repeated SimState sim_state = 5;
-
-  // All the active subscription information.
-  repeated ActiveSubscriptionInfo active_subscription_info = 6;
 }
 
 // Power stats for modem
diff --git a/src/java/com/android/internal/telephony/CellularNetworkService.java b/src/java/com/android/internal/telephony/CellularNetworkService.java
index ee10023..2e5d058 100644
--- a/src/java/com/android/internal/telephony/CellularNetworkService.java
+++ b/src/java/com/android/internal/telephony/CellularNetworkService.java
@@ -71,7 +71,7 @@
         CellularNetworkServiceProvider(int slotId) {
             super(slotId);
 
-            mPhone = PhoneFactory.getPhone(getSlotId());
+            mPhone = PhoneFactory.getPhone(getSlotIndex());
 
             mHandlerThread = new HandlerThread(CellularNetworkService.class.getSimpleName());
             mHandlerThread.start();
@@ -488,13 +488,13 @@
     }
 
     @Override
-    protected NetworkServiceProvider createNetworkServiceProvider(int slotId) {
-        if (DBG) log("Cellular network service created for slot " + slotId);
-        if (!SubscriptionManager.isValidSlotIndex(slotId)) {
-            loge("Tried to Cellular network service with invalid slotId " + slotId);
+    public NetworkServiceProvider onCreateNetworkServiceProvider(int slotIndex) {
+        if (DBG) log("Cellular network service created for slot " + slotIndex);
+        if (!SubscriptionManager.isValidSlotIndex(slotIndex)) {
+            loge("Tried to Cellular network service with invalid slotId " + slotIndex);
             return null;
         }
-        return new CellularNetworkServiceProvider(slotId);
+        return new CellularNetworkServiceProvider(slotIndex);
     }
 
     private void log(String s) {
diff --git a/src/java/com/android/internal/telephony/CellularNetworkValidator.java b/src/java/com/android/internal/telephony/CellularNetworkValidator.java
index 3e552fc..e88949b 100644
--- a/src/java/com/android/internal/telephony/CellularNetworkValidator.java
+++ b/src/java/com/android/internal/telephony/CellularNetworkValidator.java
@@ -25,6 +25,9 @@
 import android.telephony.SubscriptionManager;
 import android.util.Log;
 
+import com.android.internal.telephony.metrics.TelephonyMetrics;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent;
+
 /**
  * This class will validate whether cellular network verified by Connectivity's
  * validation process. It listens request on a specific subId, sends a network request
@@ -186,6 +189,10 @@
                 mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
                 mState = STATE_IDLE;
             }
+
+            TelephonyMetrics.getInstance().writeNetworkValidate(passed
+                    ? TelephonyEvent.NetworkValidationState.NETWORK_VALIDATION_STATE_PASSED
+                    : TelephonyEvent.NetworkValidationState.NETWORK_VALIDATION_STATE_FAILED);
         }
 
         mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -203,6 +210,10 @@
         @Override
         public void onAvailable(Network network) {
             logd("network onAvailable " + network);
+            if (ConnectivityNetworkCallback.this.mSubId == CellularNetworkValidator.this.mSubId) {
+                TelephonyMetrics.getInstance().writeNetworkValidate(
+                        TelephonyEvent.NetworkValidationState.NETWORK_VALIDATION_STATE_AVAILABLE);
+            }
         }
 
         @Override
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index 05374f1..9b24946 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -2266,6 +2266,13 @@
      */
     default void enableModem(boolean enable, Message result) {};
 
+    /**
+     * Query whether logical modem is enabled or disabled
+     *
+     * @param result a Message to return to the requester
+     */
+    default void getModemStatus(Message result) {};
+
     default List<ClientRequestStats> getClientRequestStats() {
         return null;
     }
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 6f139f6..7213fca 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -54,6 +54,7 @@
 import android.preference.PreferenceManager;
 import android.provider.Settings;
 import android.provider.Telephony;
+import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
 import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.CarrierConfigManager;
@@ -268,6 +269,8 @@
         mSettingsObserver.observe(
                 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED),
                 EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE);
+
+        loadTtyMode();
         logd("GsmCdmaPhone: constructor: sub = " + mPhoneId);
     }
 
@@ -275,8 +278,17 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             Rlog.d(LOG_TAG, "mBroadcastReceiver: action " + intent.getAction());
-            if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
+            String action = intent.getAction();
+            if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action)) {
                 sendMessage(obtainMessage(EVENT_CARRIER_CONFIG_CHANGED));
+            } else if (TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED.equals(action)) {
+                int ttyMode = intent.getIntExtra(
+                        TelecomManager.EXTRA_CURRENT_TTY_MODE, TelecomManager.TTY_MODE_OFF);
+                updateTtyMode(ttyMode);
+            } else if (TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED.equals(action)) {
+                int newPreferredTtyMode = intent.getIntExtra(
+                        TelecomManager.EXTRA_TTY_PREFERRED_MODE, TelecomManager.TTY_MODE_OFF);
+                updateUiTtyMode(newPreferredTtyMode);
             }
         }
     };
@@ -327,8 +339,12 @@
 
         mCi.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);
         mCi.registerForVoiceRadioTechChanged(this, EVENT_VOICE_RADIO_TECH_CHANGED, null);
-        mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(
-                CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
+        IntentFilter filter = new IntentFilter(
+                CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+        filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
+        filter.addAction(TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED);
+        mContext.registerReceiver(mBroadcastReceiver, filter);
+
         mCDM = new CarrierKeyDownloadManager(this);
         mCIM = new CarrierInfoManager();
     }
@@ -3868,4 +3884,47 @@
         }
         return currentConfig;
     }
+
+    private void updateTtyMode(int ttyMode) {
+        logi(String.format("updateTtyMode ttyMode=%d", ttyMode));
+        setTTYMode(telecomModeToPhoneMode(ttyMode), null);
+    }
+    private void updateUiTtyMode(int ttyMode) {
+        logi(String.format("updateUiTtyMode ttyMode=%d", ttyMode));
+        setUiTTYMode(telecomModeToPhoneMode(ttyMode), null);
+    }
+
+    /**
+     * Given a telecom TTY mode, convert to a Telephony mode equivalent.
+     * @param telecomMode Telecom TTY mode.
+     * @return Telephony phone TTY mode.
+     */
+    private static int telecomModeToPhoneMode(int telecomMode) {
+        switch (telecomMode) {
+            // AT command only has 0 and 1, so mapping VCO
+            // and HCO to FULL
+            case TelecomManager.TTY_MODE_FULL:
+            case TelecomManager.TTY_MODE_VCO:
+            case TelecomManager.TTY_MODE_HCO:
+                return Phone.TTY_MODE_FULL;
+            default:
+                return Phone.TTY_MODE_OFF;
+        }
+    }
+
+    /**
+     * Load the current TTY mode in GsmCdmaPhone based on Telecom and UI settings.
+     */
+    private void loadTtyMode() {
+        int ttyMode = TelecomManager.TTY_MODE_OFF;
+        TelecomManager telecomManager = TelecomManager.from(mContext);
+        if (telecomManager != null) {
+            ttyMode = telecomManager.getCurrentTtyMode();
+        }
+        updateTtyMode(ttyMode);
+        //Get preferred TTY mode from settings as UI Tty mode is always user preferred Tty mode.
+        ttyMode = Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.PREFERRED_TTY_MODE, TelecomManager.TTY_MODE_OFF);
+        updateUiTtyMode(ttyMode);
+    }
 }
diff --git a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
index c558721..66e4e4f 100644
--- a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
+++ b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
@@ -90,7 +90,7 @@
                 }
 
                 @Override
-                public void onDeregistered(ImsReasonInfo info) {
+                public void onUnregistered(ImsReasonInfo info) {
                     Rlog.d(TAG, "onImsDisconnected imsReasonInfo=" + info);
                     synchronized (mLock) {
                         mIsRegistered = false;
diff --git a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
index 01a78ff..616e9fe 100644
--- a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
+++ b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
@@ -22,11 +22,15 @@
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.SystemProperties;
+import android.os.storage.StorageManager;
 import android.telephony.PhoneCapability;
 import android.telephony.Rlog;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * This class manages phone's configuration which defines the potential capability (static) of the
  * phone and its current activated capability (current).
@@ -40,6 +44,8 @@
     public static final String SSSS = "";
     private static final String LOG_TAG = "PhoneCfgMgr";
     private static final int EVENT_SWITCH_DSDS_CONFIG_DONE = 100;
+    private static final int EVENT_GET_MODEM_STATUS = 101;
+    private static final int EVENT_GET_MODEM_STATUS_DONE = 102;
 
     private static PhoneConfigurationManager sInstance = null;
     private final Context mContext;
@@ -47,6 +53,8 @@
     private PhoneCapability mCurrentCapability;
     private final RadioConfig mRadioConfig;
     private final MainThreadHandler mHandler;
+    private final Phone[] mPhones;
+    private final Map<Integer, Boolean> mPhoneStatusMap;
 
     /**
      * Init method to instantiate the object
@@ -75,8 +83,20 @@
         mCurrentCapability = mStaticCapability;
         mRadioConfig = RadioConfig.getInstance(mContext);
         mHandler = new MainThreadHandler();
+        mPhoneStatusMap = new HashMap<>();
 
         notifyCapabilityChanged();
+
+        mPhones = PhoneFactory.getPhones();
+        if (!StorageManager.inCryptKeeperBounce()) {
+            for (Phone phone : mPhones) {
+                phone.mCi.registerForAvailable(mHandler, Phone.EVENT_RADIO_AVAILABLE, phone);
+            }
+        } else {
+            for (Phone phone : mPhones) {
+                phone.mCi.registerForOn(mHandler, Phone.EVENT_RADIO_ON, phone);
+            }
+        }
     }
 
     /**
@@ -96,9 +116,24 @@
     private final class MainThreadHandler extends Handler {
         @Override
         public void handleMessage(Message msg) {
+            AsyncResult ar;
+            Phone phone = null;
             switch (msg.what) {
+                case Phone.EVENT_RADIO_AVAILABLE:
+                case Phone.EVENT_RADIO_ON:
+                    log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON");
+                    if (msg.obj instanceof Phone) {
+                        phone = (Phone) msg.obj;
+                    }
+                    if (phone == null) {
+                        log("Unable to add phoneStatus to cache. "
+                                + "No phone object provided for event " + msg.what);
+                    } else {
+                        updatePhoneStatus(phone);
+                    }
+                    break;
                 case EVENT_SWITCH_DSDS_CONFIG_DONE:
-                    AsyncResult ar = (AsyncResult) msg.obj;
+                    ar = (AsyncResult) msg.obj;
                     if (ar != null && ar.exception == null) {
                         int numOfLiveModems = msg.arg1;
                         setMultiSimProperties(numOfLiveModems);
@@ -106,6 +141,17 @@
                         log(msg.what + " failure. Not switching multi-sim config." + ar.exception);
                     }
                     break;
+                case EVENT_GET_MODEM_STATUS_DONE:
+                    ar = (AsyncResult) msg.obj;
+                    if (ar != null && ar.exception == null) {
+                        int phoneId = msg.arg1;
+                        boolean enabled = (boolean) ar.result;
+                        //update the cache each time getModemStatus is requested
+                        mPhoneStatusMap.put(phoneId, enabled);
+                    } else {
+                        log(msg.what + " failure. Not updating modem status." + ar.exception);
+                    }
+                    break;
             }
         }
     }
@@ -123,6 +169,48 @@
             return;
         }
         phone.mCi.enableModem(enable, result);
+        updatePhoneStatus(phone);
+    }
+
+    /**
+     * Get phone status (enabled/disabled)
+     *
+     * @param phone which phone to operate on
+     */
+    public boolean getPhoneStatus(Phone phone) {
+        if (phone == null) {
+            log("getPhonetatus failed phone is null");
+            return false;
+        }
+
+        int phoneId = phone.getPhoneId();
+
+        //use cache if the status has already been updated/queried
+        if (mPhoneStatusMap.containsKey(phoneId)) {
+            return mPhoneStatusMap.get(phoneId);
+        } else {
+            //return false if modem status is not in cache
+            updatePhoneStatus(phone);
+            return false;
+        }
+    }
+
+    /**
+     * method to call RIL getM
+     */
+    private void updatePhoneStatus(Phone phone) {
+        Message callback = Message.obtain(
+                mHandler, EVENT_GET_MODEM_STATUS_DONE, phone.getPhoneId(), 0 /**dummy arg*/);
+        phone.mCi.getModemStatus(callback);
+    }
+
+    /**
+     * Add status of the phone to the status HashMap
+     * @param phoneId
+     * @param status
+     */
+    public void addToPhoneStatusCache(int phoneId, boolean status) {
+        mPhoneStatusMap.put(phoneId, status);
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/PhoneConfigurationModels.java b/src/java/com/android/internal/telephony/PhoneConfigurationModels.java
index fb8cc5e..aca4955 100644
--- a/src/java/com/android/internal/telephony/PhoneConfigurationModels.java
+++ b/src/java/com/android/internal/telephony/PhoneConfigurationModels.java
@@ -40,7 +40,7 @@
         List<ModemInfo> logicalModemList = new ArrayList<>();
         logicalModemList.add(modemInfo1);
         logicalModemList.add(modemInfo2);
-        DSDS_CAPABILITY = new PhoneCapability(1, 2, 0, logicalModemList, false);
+        DSDS_CAPABILITY = new PhoneCapability(1, 2, 0, logicalModemList, true);
 
         logicalModemList = new ArrayList<>();
         logicalModemList.add(modemInfo1);
diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java
index 42b3691..043de1c 100644
--- a/src/java/com/android/internal/telephony/PhoneFactory.java
+++ b/src/java/com/android/internal/telephony/PhoneFactory.java
@@ -242,7 +242,8 @@
 
                 sSubscriptionMonitor = new SubscriptionMonitor(tr, sContext, sc, numPhones);
 
-                sPhoneConfigurationManager = PhoneConfigurationManager.init(sContext);
+                sPhoneConfigurationManager = PhoneConfigurationManager.init(
+                        sContext);
 
                 sCellularNetworkValidator = CellularNetworkValidator.make(sContext);
 
diff --git a/src/java/com/android/internal/telephony/PhoneSwitcher.java b/src/java/com/android/internal/telephony/PhoneSwitcher.java
index e0c4557..d455cb4 100644
--- a/src/java/com/android/internal/telephony/PhoneSwitcher.java
+++ b/src/java/com/android/internal/telephony/PhoneSwitcher.java
@@ -16,17 +16,24 @@
 
 package com.android.internal.telephony;
 
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.telephony.PhoneStateListener.LISTEN_PHONE_CAPABILITY_CHANGE;
 import static android.telephony.PhoneStateListener.LISTEN_PRECISE_CALL_STATE;
 import static android.telephony.SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
 import static android.telephony.SubscriptionManager.INVALID_PHONE_INDEX;
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER;
+import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS;
+import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
 import android.net.MatchAllNetworkSpecifier;
+import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkFactory;
 import android.net.NetworkRequest;
@@ -38,6 +45,7 @@
 import android.os.Registrant;
 import android.os.RegistrantList;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.telephony.PhoneCapability;
 import android.telephony.PhoneStateListener;
 import android.telephony.PreciseCallState;
@@ -48,6 +56,10 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.dataconnection.DcRequest;
+import com.android.internal.telephony.metrics.TelephonyMetrics;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwitch;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.OnDemandDataSwitch;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.FileDescriptor;
@@ -65,8 +77,10 @@
  * the active phones.  Note we don't wait for data attach (which may not happen anyway).
  */
 public class PhoneSwitcher extends Handler {
-    private final static String LOG_TAG = "PhoneSwitcher";
-    private final static boolean VDBG = false;
+    private static final String LOG_TAG = "PhoneSwitcher";
+    private static final boolean VDBG = false;
+
+    private static final int DEFAULT_NETWORK_CHANGE_TIMEOUT_MS = 5000;
 
     private final List<DcRequest> mPrioritizedDcRequests = new ArrayList<DcRequest>();
     private final RegistrantList mActivePhoneRegistrants;
@@ -103,16 +117,19 @@
 
     private int mPhoneIdInCall = SubscriptionManager.INVALID_PHONE_INDEX;
 
+    private ISetOpportunisticDataCallback mSetOpptSubCallback;
+
     private static final int EVENT_DEFAULT_SUBSCRIPTION_CHANGED   = 101;
     private static final int EVENT_SUBSCRIPTION_CHANGED           = 102;
     private static final int EVENT_REQUEST_NETWORK                = 103;
     private static final int EVENT_RELEASE_NETWORK                = 104;
     private static final int EVENT_EMERGENCY_TOGGLE               = 105;
     private static final int EVENT_RADIO_CAPABILITY_CHANGED       = 106;
-    private static final int EVENT_PREFERRED_SUBSCRIPTION_CHANGED = 107;
+    private static final int EVENT_CHANGE_PREFERRED_SUBSCRIPTION  = 107;
     private static final int EVENT_RADIO_AVAILABLE                = 108;
     private static final int EVENT_PHONE_IN_CALL_CHANGED          = 109;
     private static final int EVENT_NETWORK_VALIDATION_DONE        = 110;
+    private static final int EVENT_REMOVE_DEFAULT_NETWORK_CHANGE_CALLBACK = 111;
 
     // Depending on version of IRadioConfig, we need to send either RIL_REQUEST_ALLOW_DATA if it's
     // 1.0, or RIL_REQUEST_SET_PREFERRED_DATA if it's 1.1 or later. So internally mHalCommandToUse
@@ -129,6 +146,24 @@
     // Default timeout value of network validation in millisecond.
     private final static int DEFAULT_VALIDATION_EXPIRATION_TIME = 2000;
 
+    private Boolean mHasRegisteredDefaultNetworkChangeCallback = false;
+
+    private ConnectivityManager mConnectivityManager;
+
+    private final ConnectivityManager.NetworkCallback mDefaultNetworkCallback =
+            new NetworkCallback() {
+                @Override
+                public void onAvailable(Network network) {
+                    if (mConnectivityManager.getNetworkCapabilities(network)
+                            .hasTransport(TRANSPORT_CELLULAR)) {
+                        logDataSwitchEvent(
+                                TelephonyEvent.EventState.EVENT_STATE_END,
+                                TelephonyEvent.DataSwitch.Reason.DATA_SWITCH_REASON_UNKNOWN);
+                    }
+                    removeDefaultNetworkChangeCallback();
+                }
+            };
+
     /**
      * Method to get singleton instance.
      */
@@ -150,6 +185,7 @@
         return sPhoneSwitcher;
     }
 
+    /** This constructor is only used for testing purpose. */
     @VisibleForTesting
     public PhoneSwitcher(int numPhones, Looper looper) {
         super(looper);
@@ -241,11 +277,14 @@
         } catch (RemoteException e) {
         }
 
+        mConnectivityManager =
+            (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+
         mContext.registerReceiver(mDefaultDataChangedReceiver,
                 new IntentFilter(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED));
 
         NetworkCapabilities netCap = new NetworkCapabilities();
-        netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+        netCap.addTransportType(TRANSPORT_CELLULAR);
         netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
         netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
         netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
@@ -258,6 +297,7 @@
         netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS);
         netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
         netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+        netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_MCX);
         netCap.setNetworkSpecifier(new MatchAllNetworkSpecifier());
 
         NetworkFactory networkFactory = new PhoneSwitcherNetworkRequestListener(looper, context,
@@ -294,7 +334,10 @@
                 break;
             }
             case EVENT_DEFAULT_SUBSCRIPTION_CHANGED: {
+                logDataSwitchEvent(TelephonyEvent.EventState.EVENT_STATE_START,
+                        DataSwitch.Reason.DATA_SWITCH_REASON_MANUAL);
                 onEvaluate(REQUESTS_UNCHANGED, "defaultChanged");
+                registerDefaultNetworkChangeCallback();
                 break;
             }
             case EVENT_REQUEST_NETWORK: {
@@ -313,8 +356,16 @@
                 resendRilCommands(msg);
                 break;
             }
-            case EVENT_PREFERRED_SUBSCRIPTION_CHANGED: {
-                onEvaluate(REQUESTS_UNCHANGED, "preferredDataSubscriptionIdChanged");
+            case EVENT_CHANGE_PREFERRED_SUBSCRIPTION: {
+                int subId = msg.arg1;
+                boolean needValidation = (msg.arg2 == 1);
+                ISetOpportunisticDataCallback callback =
+                        (ISetOpportunisticDataCallback) msg.obj;
+                if (SubscriptionManager.isUsableSubscriptionId(subId)) {
+                    setOpportunisticDataSubscription(subId, needValidation, callback);
+                } else {
+                    unsetOpportunisticDataSubscription(callback);
+                }
                 break;
             }
             case EVENT_RADIO_AVAILABLE: {
@@ -323,7 +374,10 @@
                 break;
             }
             case EVENT_PHONE_IN_CALL_CHANGED: {
+                logDataSwitchEvent(TelephonyEvent.EventState.EVENT_STATE_START,
+                        DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL);
                 onEvaluate(REQUESTS_UNCHANGED, "EVENT_PHONE_IN_CALL_CHANGED");
+                registerDefaultNetworkChangeCallback();
                 break;
             }
             case EVENT_NETWORK_VALIDATION_DONE: {
@@ -332,6 +386,10 @@
                 onValidationDone(subId, passed);
                 break;
             }
+            case EVENT_REMOVE_DEFAULT_NETWORK_CHANGE_CALLBACK: {
+                removeDefaultNetworkChangeCallback();
+                break;
+            }
         }
     }
 
@@ -370,7 +428,8 @@
 
     private void onRequestNetwork(NetworkRequest networkRequest) {
         final DcRequest dcRequest = new DcRequest(networkRequest, mContext);
-        if (mPrioritizedDcRequests.contains(dcRequest) == false) {
+        if (!mPrioritizedDcRequests.contains(dcRequest)) {
+            collectRequestNetworkMetrics(networkRequest);
             mPrioritizedDcRequests.add(dcRequest);
             Collections.sort(mPrioritizedDcRequests);
             onEvaluate(REQUESTS_CHANGED, "netRequest");
@@ -382,6 +441,53 @@
 
         if (mPrioritizedDcRequests.remove(dcRequest)) {
             onEvaluate(REQUESTS_CHANGED, "netReleased");
+            collectReleaseNetworkMetrics(networkRequest);
+        }
+    }
+
+    private void removeDefaultNetworkChangeCallback() {
+        synchronized (mHasRegisteredDefaultNetworkChangeCallback) {
+            if (mHasRegisteredDefaultNetworkChangeCallback) {
+                mHasRegisteredDefaultNetworkChangeCallback = false;
+                removeMessages(EVENT_REMOVE_DEFAULT_NETWORK_CHANGE_CALLBACK);
+                mConnectivityManager.unregisterNetworkCallback(mDefaultNetworkCallback);
+            }
+        }
+    }
+
+    private void registerDefaultNetworkChangeCallback() {
+        removeDefaultNetworkChangeCallback();
+
+        synchronized (mHasRegisteredDefaultNetworkChangeCallback) {
+            mHasRegisteredDefaultNetworkChangeCallback = true;
+            mConnectivityManager.registerDefaultNetworkCallback(mDefaultNetworkCallback);
+            sendMessageDelayed(
+                    obtainMessage(EVENT_REMOVE_DEFAULT_NETWORK_CHANGE_CALLBACK),
+                    DEFAULT_NETWORK_CHANGE_TIMEOUT_MS);
+        }
+    }
+
+    private void collectRequestNetworkMetrics(NetworkRequest networkRequest) {
+        // Request network for MMS will temporary disable the network on default data subscription,
+        // this only happen on multi-sim device.
+        if (mNumPhones > 1 && networkRequest.networkCapabilities.hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_MMS)) {
+            OnDemandDataSwitch onDemandDataSwitch = new OnDemandDataSwitch();
+            onDemandDataSwitch.apn = TelephonyEvent.ApnType.APN_TYPE_MMS;
+            onDemandDataSwitch.state = TelephonyEvent.EventState.EVENT_STATE_START;
+            TelephonyMetrics.getInstance().writeOnDemandDataSwitch(onDemandDataSwitch);
+        }
+    }
+
+    private void collectReleaseNetworkMetrics(NetworkRequest networkRequest) {
+        // Release network for MMS will recover the network on default data subscription, this only
+        // happen on multi-sim device.
+        if (mNumPhones > 1 && networkRequest.networkCapabilities.hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_MMS)) {
+            OnDemandDataSwitch onDemandDataSwitch = new OnDemandDataSwitch();
+            onDemandDataSwitch.apn = TelephonyEvent.ApnType.APN_TYPE_MMS;
+            onDemandDataSwitch.state = TelephonyEvent.EventState.EVENT_STATE_END;
+            TelephonyMetrics.getInstance().writeOnDemandDataSwitch(onDemandDataSwitch);
         }
     }
 
@@ -493,6 +599,10 @@
                     activate(phoneId);
                 }
             }
+
+            notifyActiveDataSubIdChanged(mSubscriptionController.getSubIdUsingPhoneId(
+                    mPreferredDataPhoneId));
+
             // Notify all registrants.
             mActivePhoneRegistrants.notifyRegistrants();
         }
@@ -688,19 +798,35 @@
      * subscription. It has to be an active subscription, and PhoneSwitcher will try to validate
      * it first if needed.
      */
-    public void setOpportunisticDataSubscription(int subId) {
+    private void setOpportunisticDataSubscription(int subId, boolean needValidation,
+            ISetOpportunisticDataCallback callback) {
         if (!mSubscriptionController.isActiveSubId(subId)) {
             log("Can't switch data to inactive subId " + subId);
+            sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER);
+            return;
+        }
+
+        if (mValidator.isValidating()
+                && (!needValidation || subId != mValidator.getSubIdInValidation())) {
+            mValidator.stopValidation();
+        }
+
+        if (subId == mPreferredDataSubId) {
+            sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_SUCCESS);
             return;
         }
 
         // If validation feature is not supported, set it directly. Otherwise,
         // start validation on the subscription first.
-        if (!CellularNetworkValidator.isValidationFeatureSupported()) {
-            setPreferredDataSubscriptionId(subId);
-        } else {
+        if (CellularNetworkValidator.isValidationFeatureSupported() && needValidation) {
+            logDataSwitchEvent(TelephonyEvent.EventState.EVENT_STATE_START,
+                    DataSwitch.Reason.DATA_SWITCH_REASON_CBRS);
+            mSetOpptSubCallback = callback;
             mValidator.validate(subId, DEFAULT_VALIDATION_EXPIRATION_TIME,
                     false, mValidationCallback);
+        } else {
+            setPreferredSubscription(subId);
+            sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_SUCCESS);
         }
     }
 
@@ -708,32 +834,57 @@
      * Unset opportunistic data subscription. It's an indication to switch Internet data back
      * from opportunistic subscription to primary subscription.
      */
-    public void unsetOpportunisticDataSubscription() {
-        if (CellularNetworkValidator.isValidationFeatureSupported()
-                && mValidator.isValidating()) {
+    private void unsetOpportunisticDataSubscription(ISetOpportunisticDataCallback callback) {
+        if (mValidator.isValidating()) {
             mValidator.stopValidation();
         }
 
         // Set mPreferredDataSubId back to DEFAULT_SUBSCRIPTION_ID. This will trigger
         // data switch to mDefaultDataSubId.
-        setPreferredDataSubscriptionId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
+        setPreferredSubscription(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
+        sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_SUCCESS);
+    }
+
+    private void sendSetOpptCallbackHelper(ISetOpportunisticDataCallback callback, int result) {
+        if (callback == null) return;
+        try {
+            callback.onComplete(result);
+        } catch (RemoteException exception) {
+            log("RemoteException " + exception);
+        }
+    }
+
+    /**
+     * Set opportunistic data subscription.
+     */
+    private void setPreferredSubscription(int subId) {
+        if (mPreferredDataSubId != subId) {
+            mPreferredDataSubId = subId;
+            logDataSwitchEvent(TelephonyEvent.EventState.EVENT_STATE_START,
+                    DataSwitch.Reason.DATA_SWITCH_REASON_CBRS);
+            onEvaluate(REQUESTS_UNCHANGED, "preferredDataSubscriptionIdChanged");
+            registerDefaultNetworkChangeCallback();
+        }
     }
 
     private void onValidationDone(int subId, boolean passed) {
         log("Network validation " + (passed ? "passed" : "failed")
                 + " on subId " + subId);
-        mValidator.stopValidation();
-        if (passed) setPreferredDataSubscriptionId(subId);
+        if (passed) setPreferredSubscription(subId);
+
+        // Trigger callback if needed
+        sendSetOpptCallbackHelper(mSetOpptSubCallback, passed ? SET_OPPORTUNISTIC_SUB_SUCCESS
+                : SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED);
+        mSetOpptSubCallback = null;
     }
 
     // TODO b/123598154: rename preferredDataSub to opportunisticSubId.
-    private void setPreferredDataSubscriptionId(int subId) {
-        if (mPreferredDataSubId != subId) {
-            log("setPreferredDataSubscriptionId subId changed to " + subId);
-            mPreferredDataSubId = subId;
-            Message msg = PhoneSwitcher.this.obtainMessage(EVENT_PREFERRED_SUBSCRIPTION_CHANGED);
-            msg.sendToTarget();
-        }
+    public void trySetPreferredSubscription(int subId, boolean needValidation,
+            ISetOpportunisticDataCallback callback) {
+        log("Try set preferred subscription to subId " + subId
+                + (needValidation ? " with " : " without ") + "validation");
+        PhoneSwitcher.this.obtainMessage(EVENT_CHANGE_PREFERRED_SUBSCRIPTION,
+                subId, needValidation ? 1 : 0, callback).sendToTarget();
     }
 
     private boolean isCallActive(Phone phone) {
@@ -750,11 +901,34 @@
                 ? HAL_COMMAND_PREFERRED_DATA : HAL_COMMAND_ALLOW_DATA;
     }
 
+    public int getPreferredDataSubscriptionId() {
+        return mPreferredDataSubId;
+    }
+
     private void log(String l) {
         Rlog.d(LOG_TAG, l);
         mLocalLog.log(l);
     }
 
+    private void logDataSwitchEvent(int state, int reason) {
+        DataSwitch dataSwitch = new DataSwitch();
+        dataSwitch.state = state;
+        dataSwitch.reason = reason;
+        TelephonyMetrics.getInstance().writeDataSwitch(dataSwitch);
+
+    }
+
+    private void notifyActiveDataSubIdChanged(int activeDataSubId) {
+        ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
+                "telephony.registry"));
+        try {
+            log("notifyActiveDataSubIdChanged to " + activeDataSubId);
+            tr.notifyActiveDataSubIdChanged(activeDataSubId);
+        } catch (RemoteException ex) {
+            // Should never happen because its always available.
+        }
+    }
+
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
         pw.println("PhoneSwitcher:");
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 1e7b026..e18e3c1 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -84,6 +84,7 @@
 import android.telephony.SmsManager;
 import android.telephony.TelephonyHistogram;
 import android.telephony.TelephonyManager;
+import android.telephony.TelephonyManager.PrefNetworkMode;
 import android.telephony.data.ApnSetting;
 import android.telephony.data.DataCallResponse;
 import android.telephony.data.DataProfile;
@@ -903,6 +904,37 @@
     }
 
     @Override
+    public void getModemStatus(Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (mRadioVersion.less(RADIO_HAL_VERSION_1_3)) {
+            if (RILJ_LOGV) riljLog("getModemStatus: not supported.");
+            if (result != null) {
+                AsyncResult.forMessage(result, null,
+                        CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+                result.sendToTarget();
+            }
+            return;
+        }
+
+        android.hardware.radio.V1_3.IRadio radioProxy13 =
+                (android.hardware.radio.V1_3.IRadio) radioProxy;
+        if (radioProxy13 != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_GET_MODEM_STATUS, result,
+                    mRILDefaultWorkSource);
+
+            if (RILJ_LOGD) {
+                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+            }
+
+            try {
+                radioProxy13.getModemStackStatus(rr.mSerial);
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "getModemStatus", e);
+            }
+        }
+    }
+
+    @Override
     public void dial(String address, boolean isEmergencyCall, EmergencyNumber emergencyNumberInfo,
                      boolean hasKnownUserIntentEmergency, int clirMode, UUSInfo uusInfo,
                      Message result) {
@@ -1438,7 +1470,8 @@
 
                     if (RILJ_LOGD) {
                         riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
-                                + ",accessNetworkType=" + accessNetworkType + ",isRoaming="
+                                + ",accessNetworkType="
+                                + AccessNetworkType.toString(accessNetworkType) + ",isRoaming="
                                 + isRoaming + ",allowRoaming=" + allowRoaming + "," + dataProfile
                                 + ",addresses=" + addresses + ",dnses=" + dnses);
                     }
@@ -1456,7 +1489,8 @@
 
                     if (RILJ_LOGD) {
                         riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
-                                + ",accessNetworkType=" + accessNetworkType + ",isRoaming="
+                                + ",accessNetworkType="
+                                + AccessNetworkType.toString(accessNetworkType) + ",isRoaming="
                                 + isRoaming + ",allowRoaming=" + allowRoaming + ","
                                 + dataProfile + ",addresses=" + addresses + ",dnses=" + dnses);
                     }
@@ -2518,7 +2552,7 @@
     }
 
     @Override
-    public void setPreferredNetworkType(int networkType , Message result) {
+    public void setPreferredNetworkType(@PrefNetworkMode int networkType , Message result) {
         IRadio radioProxy = getRadioProxy(result);
         if (radioProxy != null) {
             RILRequest rr = obtainRequest(RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, result,
@@ -2542,7 +2576,7 @@
                         (android.hardware.radio.V1_4.IRadio) radioProxy;
                 try {
                     radioProxy14.setPreferredNetworkTypeBitmap(
-                            rr.mSerial, RadioAccessFamily.getRafFromNetworkType(networkType));
+                            rr.mSerial, convertToHalRadioAccessFamily(networkType));
                 } catch (RemoteException | RuntimeException e) {
                     handleRadioProxyExceptionForRR(rr, "setPreferredNetworkTypeBitmap", e);
                 }
@@ -2550,6 +2584,13 @@
         }
     }
 
+    private static int convertToHalRadioAccessFamily(@PrefNetworkMode int networkMode) {
+        // android.hardware.radio.V1_0.RadioAccessFamily is one bit shift
+        // from TelephonyManager.NetworkTypeBitMask
+        int networkTypeBitmask = RadioAccessFamily.getRafFromNetworkType(networkMode);
+        return networkTypeBitmask << 1;
+    }
+
     @Override
     public void getPreferredNetworkType(Message result) {
         IRadio radioProxy = getRadioProxy(result);
@@ -5307,6 +5348,8 @@
                 return "RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA";
             case RIL_REQUEST_ENABLE_MODEM:
                 return "RIL_REQUEST_ENABLE_MODEM";
+            case RIL_REQUEST_GET_MODEM_STATUS:
+                return "RIL_REQUEST_GET_MODEM_STATUS";
             default: return "<unknown request>";
         }
     }
@@ -5615,7 +5658,9 @@
             ArrayList<android.hardware.radio.V1_0.CellInfo> records) {
         ArrayList<CellInfo> response = new ArrayList<CellInfo>(records.size());
 
+        final long nanotime = SystemClock.elapsedRealtimeNanos();
         for (android.hardware.radio.V1_0.CellInfo record : records) {
+            record.timeStamp = nanotime;
             response.add(CellInfo.create(record));
         }
 
@@ -5632,7 +5677,9 @@
             ArrayList<android.hardware.radio.V1_2.CellInfo> records) {
         ArrayList<CellInfo> response = new ArrayList<CellInfo>(records.size());
 
+        final long nanotime = SystemClock.elapsedRealtimeNanos();
         for (android.hardware.radio.V1_2.CellInfo record : records) {
+            record.timeStamp = nanotime;
             response.add(CellInfo.create(record));
         }
         return response;
@@ -5648,8 +5695,9 @@
             ArrayList<android.hardware.radio.V1_4.CellInfo> records) {
         ArrayList<CellInfo> response = new ArrayList<CellInfo>(records.size());
 
+        final long nanotime = SystemClock.elapsedRealtimeNanos();
         for (android.hardware.radio.V1_4.CellInfo record : records) {
-            response.add(CellInfo.create(record));
+            response.add(CellInfo.create(record, nanotime));
         }
         return response;
     }
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index baed262..fd0b011 100644
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -77,6 +77,7 @@
 import android.util.LocalLog;
 import android.util.Pair;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.StatsLog;
 import android.util.TimestampedValue;
 
@@ -174,10 +175,10 @@
     private RegistrantList mVoiceRoamingOffRegistrants = new RegistrantList();
     private RegistrantList mDataRoamingOnRegistrants = new RegistrantList();
     private RegistrantList mDataRoamingOffRegistrants = new RegistrantList();
-    protected RegistrantList mAttachedRegistrants = new RegistrantList();
-    protected RegistrantList mDetachedRegistrants = new RegistrantList();
+    protected SparseArray<RegistrantList> mAttachedRegistrants = new SparseArray<>();
+    protected SparseArray<RegistrantList> mDetachedRegistrants = new SparseArray();
     private RegistrantList mVoiceRegStateOrRatChangedRegistrants = new RegistrantList();
-    private RegistrantList mDataRegStateOrRatChangedRegistrants = new RegistrantList();
+    private SparseArray<RegistrantList> mDataRegStateOrRatChangedRegistrants = new SparseArray<>();
     private RegistrantList mNetworkAttachedRegistrants = new RegistrantList();
     private RegistrantList mNetworkDetachedRegistrants = new RegistrantList();
     private RegistrantList mPsRestrictEnabledRegistrants = new RegistrantList();
@@ -573,9 +574,9 @@
                 CarrierServiceStateTracker.CARRIER_EVENT_VOICE_REGISTRATION, null);
         registerForNetworkDetached(mCSST,
                 CarrierServiceStateTracker.CARRIER_EVENT_VOICE_DEREGISTRATION, null);
-        registerForDataConnectionAttached(mCSST,
+        registerForDataConnectionAttached(TransportType.WWAN, mCSST,
                 CarrierServiceStateTracker.CARRIER_EVENT_DATA_REGISTRATION, null);
-        registerForDataConnectionDetached(mCSST,
+        registerForDataConnectionDetached(TransportType.WWAN, mCSST,
                 CarrierServiceStateTracker.CARRIER_EVENT_DATA_DEREGISTRATION, null);
         registerForImsCapabilityChanged(mCSST,
                 CarrierServiceStateTracker.CARRIER_EVENT_IMS_CAPABILITIES_CHANGED, null);
@@ -602,8 +603,15 @@
         }
 
         // If we are previously in service, we need to notify that we are out of service now.
-        if (mSS != null && mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE) {
-            mDetachedRegistrants.notifyRegistrants();
+        for (int transport : mTransportManager.getAvailableTransports()) {
+            if (mSS != null) {
+                NetworkRegistrationState nrs = mSS.getNetworkRegistrationState(
+                        NetworkRegistrationState.DOMAIN_PS, transport);
+                if (nrs != null && nrs.isInService()
+                        && mDetachedRegistrants.get(transport) != null) {
+                    mDetachedRegistrants.get(transport).notifyRegistrants();
+                }
+            }
         }
 
         mSS = new ServiceState();
@@ -672,7 +680,9 @@
 
         // Tell everybody that the registration state and RAT have changed.
         notifyVoiceRegStateRilRadioTechnologyChanged();
-        notifyDataRegStateRilRadioTechnologyChanged();
+        for (int transport : mTransportManager.getAvailableTransports()) {
+            notifyDataRegStateRilRadioTechnologyChanged(transport);
+        }
     }
 
     @VisibleForTesting
@@ -738,14 +748,24 @@
      * AsyncResult in msg.obj where AsyncResult#result contains the
      * new RAT as an Integer Object.
      */
-    protected void notifyDataRegStateRilRadioTechnologyChanged() {
-        int rat = mSS.getRilDataRadioTechnology();
-        int drs = mSS.getDataRegState();
-        if (DBG) log("notifyDataRegStateRilRadioTechnologyChanged: drs=" + drs + " rat=" + rat);
+    protected void notifyDataRegStateRilRadioTechnologyChanged(int transport) {
+        NetworkRegistrationState nrs = mSS.getNetworkRegistrationState(
+                NetworkRegistrationState.DOMAIN_PS, transport);
+        if (nrs != null) {
+            int rat = ServiceState.networkTypeToRilRadioTechnology(
+                    nrs.getAccessNetworkTechnology());
+            int drs = regCodeToServiceState(nrs.getRegState());
+            if (DBG) {
+                log("notifyDataRegStateRilRadioTechnologyChanged: drs=" + drs + " rat=" + rat);
+            }
 
+            RegistrantList registrantList = mDataRegStateOrRatChangedRegistrants.get(transport);
+            if (registrantList != null) {
+                registrantList.notifyResult(new Pair<>(drs, rat));
+            }
+        }
         mPhone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
-                ServiceState.rilRadioTechnologyToString(rat));
-        mDataRegStateOrRatChangedRegistrants.notifyResult(new Pair<Integer, Integer>(drs, rat));
+                ServiceState.rilRadioTechnologyToString(mSS.getRilDataRadioTechnology()));
     }
 
     /**
@@ -1747,8 +1767,7 @@
                          * Roaming Indicator shall be sent if device is registered
                          * on a CDMA or EVDO system.
                          */
-                        boolean isRoamIndForHomeSystem = isRoamIndForHomeSystem(
-                                Integer.toString(mRoamingIndicator));
+                        boolean isRoamIndForHomeSystem = isRoamIndForHomeSystem(mRoamingIndicator);
                         if (mNewSS.getDataRoaming() == isRoamIndForHomeSystem) {
                             log("isRoamIndForHomeSystem=" + isRoamIndForHomeSystem
                                     + ", override data roaming to " + !isRoamIndForHomeSystem);
@@ -1978,8 +1997,7 @@
                     // list of ERIs for home system, mCdmaRoaming is true.
                     boolean cdmaRoaming =
                             regCodeIsRoaming(registrationState)
-                                    && !isRoamIndForHomeSystem(
-                                            Integer.toString(roamingIndicator));
+                                    && !isRoamIndForHomeSystem(roamingIndicator);
                     mNewSS.setVoiceRoaming(cdmaRoaming);
                     mRoamingIndicator = roamingIndicator;
                     mIsInPrl = (systemIsInPrl == 0) ? false : true;
@@ -2259,20 +2277,22 @@
      * Determine whether a roaming indicator is in the carrier-specified list of ERIs for
      * home system
      *
-     * @param roamInd roaming indicator in String
+     * @param roamInd roaming indicator
      * @return true if the roamInd is in the carrier-specified list of ERIs for home network
      */
-    private boolean isRoamIndForHomeSystem(String roamInd) {
+    private boolean isRoamIndForHomeSystem(int roamInd) {
         // retrieve the carrier-specified list of ERIs for home system
-        String[] homeRoamIndicators = Resources.getSystem()
-                .getStringArray(com.android.internal.R.array.config_cdma_home_system);
+        final PersistableBundle config = getCarrierConfig();
+        int[] homeRoamIndicators = config.getIntArray(CarrierConfigManager
+                    .KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY);
+
         log("isRoamIndForHomeSystem: homeRoamIndicators=" + Arrays.toString(homeRoamIndicators));
 
         if (homeRoamIndicators != null) {
             // searches through the comma-separated list for a match,
             // return true if one is found.
-            for (String homeRoamInd : homeRoamIndicators) {
-                if (homeRoamInd.equals(roamInd)) {
+            for (int homeRoamInd : homeRoamIndicators) {
+                if (homeRoamInd == roamInd) {
                     return true;
                 }
             }
@@ -2962,16 +2982,48 @@
                 mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE
                         && mNewSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE;
 
-        boolean hasDataAttached =
-                mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE
-                        && mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE;
+        SparseBooleanArray hasDataAttached = new SparseBooleanArray(
+                mTransportManager.getAvailableTransports().length);
+        SparseBooleanArray hasDataDetached = new SparseBooleanArray(
+                mTransportManager.getAvailableTransports().length);
+        SparseBooleanArray hasRilDataRadioTechnologyChanged = new SparseBooleanArray(
+                mTransportManager.getAvailableTransports().length);
+        SparseBooleanArray hasDataRegStateChanged = new SparseBooleanArray(
+                mTransportManager.getAvailableTransports().length);
+        boolean anyDataRegChanged = false;
+        boolean anyDataRatChanged = false;
+        for (int transport : mTransportManager.getAvailableTransports()) {
+            NetworkRegistrationState oldNrs = mSS.getNetworkRegistrationState(
+                    NetworkRegistrationState.DOMAIN_PS, transport);
+            NetworkRegistrationState newNrs = mNewSS.getNetworkRegistrationState(
+                    NetworkRegistrationState.DOMAIN_PS, transport);
 
-        boolean hasDataDetached =
-                mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE
-                        && mNewSS.getDataRegState() != ServiceState.STATE_IN_SERVICE;
+            boolean changed = (oldNrs == null || !oldNrs.isInService())
+                    && (newNrs != null && newNrs.isInService());
+            hasDataAttached.put(transport, changed);
 
-        boolean hasDataRegStateChanged =
-                mSS.getDataRegState() != mNewSS.getDataRegState();
+            changed = (oldNrs != null && oldNrs.isInService())
+                    && (newNrs == null || !newNrs.isInService());
+            hasDataDetached.put(transport, changed);
+
+            int oldRAT = oldNrs != null ? oldNrs.getAccessNetworkTechnology()
+                    : TelephonyManager.NETWORK_TYPE_UNKNOWN;
+            int newRAT = newNrs != null ? newNrs.getAccessNetworkTechnology()
+                    : TelephonyManager.NETWORK_TYPE_UNKNOWN;
+            hasRilDataRadioTechnologyChanged.put(transport, oldRAT != newRAT);
+            if (oldRAT != newRAT) {
+                anyDataRatChanged = true;
+            }
+
+            int oldRegState = oldNrs != null ? oldNrs.getRegState()
+                    : NetworkRegistrationState.REG_STATE_UNKNOWN;
+            int newRegState = newNrs != null ? newNrs.getRegState()
+                    : NetworkRegistrationState.REG_STATE_UNKNOWN;
+            hasDataRegStateChanged.put(transport, oldRegState != newRegState);
+            if (oldRegState != newRegState) {
+                anyDataRegChanged = true;
+            }
+        }
 
         boolean hasVoiceRegStateChanged =
                 mSS.getVoiceRegState() != mNewSS.getVoiceRegState();
@@ -3001,9 +3053,6 @@
         boolean hasRilVoiceRadioTechnologyChanged =
                 mSS.getRilVoiceRadioTechnology() != mNewSS.getRilVoiceRadioTechnology();
 
-        boolean hasRilDataRadioTechnologyChanged =
-                mSS.getRilDataRadioTechnology() != mNewSS.getRilDataRadioTechnology();
-
         boolean hasChanged = !mNewSS.equals(mSS);
 
         boolean hasVoiceRoamingOn = !mSS.getVoiceRoaming() && mNewSS.getVoiceRoaming();
@@ -3070,7 +3119,7 @@
         }
 
         // Add an event log when connection state changes
-        if (hasVoiceRegStateChanged || hasDataRegStateChanged) {
+        if (hasVoiceRegStateChanged || anyDataRegChanged) {
             EventLog.writeEvent(mPhone.isPhoneTypeGsm() ? EventLogTags.GSM_SERVICE_STATE_CHANGE :
                             EventLogTags.CDMA_SERVICE_STATE_CHANGE,
                     mSS.getVoiceRegState(), mSS.getDataRegState(),
@@ -3127,19 +3176,13 @@
             updatePhoneObject();
         }
 
-        TelephonyManager tm =
-                (TelephonyManager) mPhone.getContext().getSystemService(Context.TELEPHONY_SERVICE);
-
-        if (hasRilDataRadioTechnologyChanged) {
+        TelephonyManager tm = (TelephonyManager) mPhone.getContext().getSystemService(
+                Context.TELEPHONY_SERVICE);
+        if (anyDataRatChanged) {
             tm.setDataNetworkTypeForPhone(mPhone.getPhoneId(), mSS.getRilDataRadioTechnology());
             StatsLog.write(StatsLog.MOBILE_RADIO_TECHNOLOGY_CHANGED,
-                    ServiceState.rilRadioTechnologyToNetworkType(mSS.getRilDataRadioTechnology()),
-                    mPhone.getPhoneId());
-
-            if (ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
-                    == mSS.getRilDataRadioTechnology()) {
-                log("pollStateDone: IWLAN enabled");
-            }
+                    ServiceState.rilRadioTechnologyToNetworkType(
+                            mSS.getRilDataRadioTechnology()), mPhone.getPhoneId());
         }
 
         if (hasRegistered) {
@@ -3159,9 +3202,6 @@
             updateSpnDisplay();
 
             tm.setNetworkOperatorNameForPhone(mPhone.getPhoneId(), mSS.getOperatorAlpha());
-
-            String prevOperatorNumeric = tm.getNetworkOperatorForPhone(mPhone.getPhoneId());
-            String prevCountryIsoCode = tm.getNetworkCountryIso(mPhone.getPhoneId());
             String operatorNumeric = mSS.getOperatorNumeric();
 
             if (!mPhone.isPhoneTypeGsm()) {
@@ -3213,34 +3253,56 @@
             TelephonyMetrics.getInstance().writeServiceStateChanged(mPhone.getPhoneId(), mSS);
         }
 
-        if (hasDataAttached || has4gHandoff || hasDataDetached || hasRegistered
-                || hasDeregistered) {
+        boolean shouldLogAttachedChange = false;
+        boolean shouldLogRatChange = false;
+
+        if (hasRegistered || hasDeregistered) {
+            shouldLogAttachedChange = true;
+        }
+
+        if (has4gHandoff) {
+            mAttachedRegistrants.get(TransportType.WWAN).notifyRegistrants();
+            shouldLogAttachedChange = true;
+        }
+
+        if (hasRilVoiceRadioTechnologyChanged) {
+            shouldLogRatChange = true;
+            notifySignalStrength();
+        }
+
+        for (int transport : mTransportManager.getAvailableTransports()) {
+            if (hasRilDataRadioTechnologyChanged.get(transport)) {
+                shouldLogRatChange = true;
+                notifySignalStrength();
+            }
+
+            if (hasDataRegStateChanged.get(transport)
+                    || hasRilDataRadioTechnologyChanged.get(transport)) {
+                notifyDataRegStateRilRadioTechnologyChanged(transport);
+                mPhone.notifyDataConnection();
+            }
+
+            if (hasDataAttached.get(transport)) {
+                shouldLogAttachedChange = true;
+                mAttachedRegistrants.get(transport).notifyRegistrants();
+            }
+            if (hasDataDetached.get(transport)) {
+                shouldLogAttachedChange = true;
+                mDetachedRegistrants.get(transport).notifyRegistrants();
+            }
+        }
+
+        if (shouldLogAttachedChange) {
             logAttachChange();
         }
-
-        if (hasDataAttached || has4gHandoff) {
-            mAttachedRegistrants.notifyRegistrants();
-        }
-
-        if (hasDataDetached) {
-            mDetachedRegistrants.notifyRegistrants();
-        }
-
-        if (hasRilDataRadioTechnologyChanged || hasRilVoiceRadioTechnologyChanged) {
+        if (shouldLogRatChange) {
             logRatChange();
-
-            notifySignalStrength();
         }
 
         if (hasVoiceRegStateChanged || hasRilVoiceRadioTechnologyChanged) {
             notifyVoiceRegStateRilRadioTechnologyChanged();
         }
 
-        if (hasDataRegStateChanged || hasRilDataRadioTechnologyChanged) {
-            notifyDataRegStateRilRadioTechnologyChanged();
-            mPhone.notifyDataConnection();
-        }
-
         if (hasVoiceRoamingOn || hasVoiceRoamingOff || hasDataRoamingOn || hasDataRoamingOff) {
             logRoamingChange();
         }
@@ -4020,38 +4082,72 @@
 
     /**
      * Registration point for transition into DataConnection attached.
+     * @param transport Transport type
      * @param h handler to notify
      * @param what what code of message when delivered
      * @param obj placed in Message.obj
      */
-    public void registerForDataConnectionAttached(Handler h, int what, Object obj) {
+    public void registerForDataConnectionAttached(int transport, Handler h, int what, Object obj) {
         Registrant r = new Registrant(h, what, obj);
-        mAttachedRegistrants.add(r);
+        if (mAttachedRegistrants.get(transport) == null) {
+            mAttachedRegistrants.put(transport, new RegistrantList());
+        }
+        mAttachedRegistrants.get(transport).add(r);
 
-        if (getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE) {
-            r.notifyRegistrant();
+        if (mSS != null) {
+            NetworkRegistrationState netRegState = mSS.getNetworkRegistrationState(
+                    NetworkRegistrationState.DOMAIN_PS, transport);
+            if (netRegState == null || netRegState.isInService()) {
+                r.notifyRegistrant();
+            }
         }
     }
-    public void unregisterForDataConnectionAttached(Handler h) {
-        mAttachedRegistrants.remove(h);
+
+    /**
+     * Unregister for data attached event
+     *
+     * @param transport Transport type
+     * @param h Handler to notify
+     */
+    public void unregisterForDataConnectionAttached(int transport, Handler h) {
+        if (mAttachedRegistrants.get(transport) != null) {
+            mAttachedRegistrants.get(transport).remove(h);
+        }
     }
 
     /**
      * Registration point for transition into DataConnection detached.
+     * @param transport Transport type
      * @param h handler to notify
      * @param what what code of message when delivered
      * @param obj placed in Message.obj
      */
-    public void registerForDataConnectionDetached(Handler h, int what, Object obj) {
+    public void registerForDataConnectionDetached(int transport, Handler h, int what, Object obj) {
         Registrant r = new Registrant(h, what, obj);
-        mDetachedRegistrants.add(r);
+        if (mDetachedRegistrants.get(transport) == null) {
+            mDetachedRegistrants.put(transport, new RegistrantList());
+        }
+        mDetachedRegistrants.get(transport).add(r);
 
-        if (getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
-            r.notifyRegistrant();
+        if (mSS != null) {
+            NetworkRegistrationState netRegState = mSS.getNetworkRegistrationState(
+                    NetworkRegistrationState.DOMAIN_PS, transport);
+            if (netRegState != null && !netRegState.isInService()) {
+                r.notifyRegistrant();
+            }
         }
     }
-    public void unregisterForDataConnectionDetached(Handler h) {
-        mDetachedRegistrants.remove(h);
+
+    /**
+     * Unregister for data detatched event
+     *
+     * @param transport Transport type
+     * @param h Handler to notify
+     */
+    public void unregisterForDataConnectionDetached(int transport, Handler h) {
+        if (mDetachedRegistrants.get(transport) != null) {
+            mDetachedRegistrants.get(transport).remove(h);
+        }
     }
 
     /**
@@ -4078,17 +4174,31 @@
      * new radio technology will be returned AsyncResult#result as an Integer Object.
      * The AsyncResult will be in the notification Message#obj.
      *
+     * @param transport Transport
      * @param h handler to notify
      * @param what what code of message when delivered
      * @param obj placed in Message.obj
      */
-    public void registerForDataRegStateOrRatChanged(Handler h, int what, Object obj) {
+    public void registerForDataRegStateOrRatChanged(int transport, Handler h, int what,
+                                                    Object obj) {
         Registrant r = new Registrant(h, what, obj);
-        mDataRegStateOrRatChangedRegistrants.add(r);
-        notifyDataRegStateRilRadioTechnologyChanged();
+        if (mDataRegStateOrRatChangedRegistrants.get(transport) == null) {
+            mDataRegStateOrRatChangedRegistrants.put(transport, new RegistrantList());
+        }
+        mDataRegStateOrRatChangedRegistrants.get(transport).add(r);
+        notifyDataRegStateRilRadioTechnologyChanged(transport);
     }
-    public void unregisterForDataRegStateOrRatChanged(Handler h) {
-        mDataRegStateOrRatChangedRegistrants.remove(h);
+
+    /**
+     * Unregister for data registration state changed or RAT changed event
+     *
+     * @param transport Transport
+     * @param h The handler
+     */
+    public void unregisterForDataRegStateOrRatChanged(int transport, Handler h) {
+        if (mDataRegStateOrRatChangedRegistrants.get(transport) != null) {
+            mDataRegStateOrRatChangedRegistrants.get(transport).remove(h);
+        }
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java
index f89ba4d..12e5845 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -2690,16 +2690,14 @@
     }
 
     @Override
-    public void setPreferredDataSubscriptionId(int subId) {
+    public void setPreferredDataSubscriptionId(int subId, boolean needValidation,
+            ISetOpportunisticDataCallback callback) {
         enforceModifyPhoneState("setPreferredDataSubscriptionId");
         final long token = Binder.clearCallingIdentity();
 
         try {
-            if (SubscriptionManager.isUsableSubscriptionId(subId)) {
-                PhoneSwitcher.getInstance().setOpportunisticDataSubscription(subId);
-            } else {
-                PhoneSwitcher.getInstance().unsetOpportunisticDataSubscription();
-            }
+            PhoneSwitcher.getInstance().trySetPreferredSubscription(
+                    subId, needValidation, callback);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -2708,17 +2706,12 @@
     @Override
     public int getPreferredDataSubscriptionId() {
         enforceReadPrivilegedPhoneState("getPreferredDataSubscriptionId");
-        return mPreferredDataSubId;
-    }
+        final long token = Binder.clearCallingIdentity();
 
-    private void notifyPreferredDataSubIdChanged() {
-        ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
-                "telephony.registry"));
         try {
-            if (DBG) logd("notifyPreferredDataSubIdChanged:");
-            tr.notifyPreferredDataSubIdChanged(mPreferredDataSubId);
-        } catch (RemoteException ex) {
-            // Should never happen because its always available.
+            return PhoneSwitcher.getInstance().getPreferredDataSubscriptionId();
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/TelephonyTester.java b/src/java/com/android/internal/telephony/TelephonyTester.java
index 0ab6ec8..e054183 100644
--- a/src/java/com/android/internal/telephony/TelephonyTester.java
+++ b/src/java/com/android/internal/telephony/TelephonyTester.java
@@ -24,6 +24,7 @@
 import android.os.BadParcelableException;
 import android.os.Build;
 import android.os.Bundle;
+import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.ims.ImsCallProfile;
@@ -148,10 +149,12 @@
                 if (DBG) log("sIntentReceiver.onReceive: action=" + action);
                 if (action.equals(mPhone.getActionDetached())) {
                     log("simulate detaching");
-                    mPhone.getServiceStateTracker().mDetachedRegistrants.notifyRegistrants();
+                    mPhone.getServiceStateTracker().mDetachedRegistrants.get(TransportType.WWAN)
+                            .notifyRegistrants();
                 } else if (action.equals(mPhone.getActionAttached())) {
                     log("simulate attaching");
-                    mPhone.getServiceStateTracker().mAttachedRegistrants.notifyRegistrants();
+                    mPhone.getServiceStateTracker().mAttachedRegistrants.get(TransportType.WWAN)
+                            .notifyRegistrants();
                 } else if (action.equals(ACTION_TEST_CONFERENCE_EVENT_PACKAGE)) {
                     log("inject simulated conference event package");
                     handleTestConferenceEventPackage(context,
diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
index 26d9ec7..d7f0ae3 100644
--- a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
+++ b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
@@ -625,6 +625,10 @@
             if (apnType != ApnSetting.TYPE_NONE) error = true;
             apnType = ApnSetting.TYPE_EMERGENCY;
         }
+        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_MCX)) {
+            if (apnType != ApnSetting.TYPE_NONE) error = true;
+            apnType = ApnSetting.TYPE_MCX;
+        }
         if (error) {
             // TODO: If this error condition is removed, the framework's handling of
             // NET_CAPABILITY_NOT_RESTRICTED will need to be updated so requests for
diff --git a/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java b/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
index ae69631..41b8dab 100644
--- a/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
+++ b/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
@@ -67,7 +67,7 @@
         private CellularDataServiceProvider(int slotId) {
             super(slotId);
 
-            mPhone = PhoneFactory.getPhone(getSlotId());
+            mPhone = PhoneFactory.getPhone(getSlotIndex());
 
             mHandlerThread = new HandlerThread(CellularDataService.class.getSimpleName());
             mHandlerThread.start();
@@ -125,10 +125,10 @@
         }
 
         @Override
-        public void setupDataCall(int radioTechnology, DataProfile dataProfile, boolean isRoaming,
+        public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
                                   boolean allowRoaming, int reason, LinkProperties linkProperties,
                                   DataServiceCallback callback) {
-            if (DBG) log("setupDataCall " + getSlotId());
+            if (DBG) log("setupDataCall " + getSlotIndex());
 
             Message message = null;
             // Only obtain the message when the caller wants a callback. If the caller doesn't care
@@ -138,13 +138,13 @@
                 mCallbackMap.put(message, callback);
             }
 
-            mPhone.mCi.setupDataCall(radioTechnology, dataProfile, isRoaming, allowRoaming, reason,
-                    linkProperties, message);
+            mPhone.mCi.setupDataCall(accessNetworkType, dataProfile, isRoaming, allowRoaming,
+                    reason, linkProperties, message);
         }
 
         @Override
         public void deactivateDataCall(int cid, int reason, DataServiceCallback callback) {
-            if (DBG) log("deactivateDataCall " + getSlotId());
+            if (DBG) log("deactivateDataCall " + getSlotIndex());
 
             Message message = null;
             // Only obtain the message when the caller wants a callback. If the caller doesn't care
@@ -160,7 +160,7 @@
         @Override
         public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming,
                                         DataServiceCallback callback) {
-            if (DBG) log("setInitialAttachApn " + getSlotId());
+            if (DBG) log("setInitialAttachApn " + getSlotIndex());
 
             Message message = null;
             // Only obtain the message when the caller wants a callback. If the caller doesn't care
@@ -176,7 +176,7 @@
         @Override
         public void setDataProfile(List<DataProfile> dps, boolean isRoaming,
                                    DataServiceCallback callback) {
-            if (DBG) log("setDataProfile " + getSlotId());
+            if (DBG) log("setDataProfile " + getSlotIndex());
 
             Message message = null;
             // Only obtain the message when the caller wants a callback. If the caller doesn't care
@@ -191,7 +191,7 @@
 
         @Override
         public void getDataCallList(DataServiceCallback callback) {
-            if (DBG) log("getDataCallList " + getSlotId());
+            if (DBG) log("getDataCallList " + getSlotIndex());
 
             Message message = null;
             // Only obtain the message when the caller wants a callback. If the caller doesn't care
@@ -211,13 +211,13 @@
     }
 
     @Override
-    public DataServiceProvider createDataServiceProvider(int slotId) {
-        log("Cellular data service created for slot " + slotId);
-        if (!SubscriptionManager.isValidSlotIndex(slotId)) {
-            loge("Tried to cellular data service with invalid slotId " + slotId);
+    public DataServiceProvider onCreateDataServiceProvider(int slotIndex) {
+        log("Cellular data service created for slot " + slotIndex);
+        if (!SubscriptionManager.isValidSlotIndex(slotIndex)) {
+            loge("Tried to cellular data service with invalid slotId " + slotIndex);
             return null;
         }
-        return new CellularDataServiceProvider(slotId);
+        return new CellularDataServiceProvider(slotIndex);
     }
 
     private void log(String s) {
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index 51dc0ee..f3623bd 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -41,8 +41,10 @@
 import android.os.Message;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.provider.Telephony;
 import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.DataFailCause;
+import android.telephony.NetworkRegistrationState;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
@@ -109,6 +111,9 @@
 
     private static final String NETWORK_TYPE = "MOBILE";
 
+    private static final String RAT_NAME_5G = "nr";
+    private static final String RAT_NAME_EVDO = "evdo";
+
     // The data connection providing default Internet connection will have a higher score of 50.
     // Other connections will have a slightly lower score of 45. The intention is other connections
     // will not cause ConnectivityService to tear down default internet connection. For example,
@@ -881,17 +886,25 @@
         return true;
     }
 
+    /**
+     * TCP buffer size config based on the ril technology. There are 6 parameters
+     * read_min, read_default, read_max, write_min, write_default, write_max in the TCP buffer
+     * config string and they are separated by a comma. The unit of these parameters is byte.
+     */
     private static final String TCP_BUFFER_SIZES_GPRS = "4092,8760,48000,4096,8760,48000";
     private static final String TCP_BUFFER_SIZES_EDGE = "4093,26280,70800,4096,16384,70800";
     private static final String TCP_BUFFER_SIZES_UMTS = "58254,349525,1048576,58254,349525,1048576";
-    private static final String TCP_BUFFER_SIZES_1XRTT= "16384,32768,131072,4096,16384,102400";
+    private static final String TCP_BUFFER_SIZES_1XRTT = "16384,32768,131072,4096,16384,102400";
     private static final String TCP_BUFFER_SIZES_EVDO = "4094,87380,262144,4096,16384,262144";
-    private static final String TCP_BUFFER_SIZES_EHRPD= "131072,262144,1048576,4096,16384,524288";
-    private static final String TCP_BUFFER_SIZES_HSDPA= "61167,367002,1101005,8738,52429,262114";
+    private static final String TCP_BUFFER_SIZES_EHRPD = "131072,262144,1048576,4096,16384,524288";
+    private static final String TCP_BUFFER_SIZES_HSDPA = "61167,367002,1101005,8738,52429,262114";
     private static final String TCP_BUFFER_SIZES_HSPA = "40778,244668,734003,16777,100663,301990";
-    private static final String TCP_BUFFER_SIZES_LTE  =
+    private static final String TCP_BUFFER_SIZES_LTE =
             "524288,1048576,2097152,262144,524288,1048576";
-    private static final String TCP_BUFFER_SIZES_HSPAP= "122334,734003,2202010,32040,192239,576717";
+    private static final String TCP_BUFFER_SIZES_HSPAP =
+            "122334,734003,2202010,32040,192239,576717";
+    private static final String TCP_BUFFER_SIZES_NR =
+            "2097152,6291456,16777216,512000,2097152,8388608";
 
     private void updateTcpBufferSizes(int rilRat) {
         String sizes = null;
@@ -906,7 +919,13 @@
         if (rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0 ||
                 rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A ||
                 rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B) {
-            ratName = "evdo";
+            ratName = RAT_NAME_EVDO;
+        }
+
+        // NR 5G Non-Standalone use LTE cell as the primary cell, the ril technology is LTE in this
+        // case. We use NR 5G TCP buffer size when connected to NR 5G Non-Standalone network.
+        if (rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_LTE && isNRConnected()) {
+            ratName = RAT_NAME_5G;
         }
 
         // in the form: "ratname:rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max"
@@ -954,7 +973,12 @@
                     break;
                 case ServiceState.RIL_RADIO_TECHNOLOGY_LTE:
                 case ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA:
-                    sizes = TCP_BUFFER_SIZES_LTE;
+                    // Use NR 5G TCP buffer size when connected to NR 5G Non-Standalone network.
+                    if (isNRConnected()) {
+                        sizes = TCP_BUFFER_SIZES_NR;
+                    } else {
+                        sizes = TCP_BUFFER_SIZES_LTE;
+                    }
                     break;
                 case ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP:
                     sizes = TCP_BUFFER_SIZES_HSPAP;
@@ -1125,6 +1149,10 @@
                         result.addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS);
                         break;
                     }
+                    case PhoneConstants.APN_TYPE_MCX: {
+                        result.addCapability(NetworkCapabilities.NET_CAPABILITY_MCX);
+                        break;
+                    }
                     default:
                 }
             }
@@ -1191,6 +1219,27 @@
     }
 
     /**
+     * @return {@code True} if 464xlat should be skipped.
+     */
+    @VisibleForTesting
+    public boolean shouldSkip464Xlat() {
+        switch (mApnSetting.getSkip464Xlat()) {
+            case Telephony.Carriers.SKIP_464XLAT_ENABLE:
+                return true;
+            case Telephony.Carriers.SKIP_464XLAT_DISABLE:
+                return false;
+            case Telephony.Carriers.SKIP_464XLAT_DEFAULT:
+            default:
+                break;
+        }
+
+        // As default, return true if ims and no internet
+        final NetworkCapabilities nc = getNetworkCapabilities();
+        return nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
+                && !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+    }
+
+    /**
      * @return {@code} true iff. {@code address} is a literal IPv4 or IPv6 address.
      */
     @VisibleForTesting
@@ -1358,7 +1407,8 @@
             if (DBG) log("DcDefaultState: enter");
 
             // Register for DRS or RAT change
-            mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(getHandler(),
+            mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(
+                    mDataServiceManager.getTransportType(), getHandler(),
                     DataConnection.EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED, null);
 
             mPhone.getServiceStateTracker().registerForDataRoamingOn(getHandler(),
@@ -1374,7 +1424,8 @@
             if (DBG) log("DcDefaultState: exit");
 
             // Unregister for DRS or RAT change.
-            mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(getHandler());
+            mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(
+                    mDataServiceManager.getTransportType(), getHandler());
 
             mPhone.getServiceStateTracker().unregisterForDataRoamingOn(getHandler());
             mPhone.getServiceStateTracker().unregisterForDataRoamingOff(getHandler());
@@ -1803,6 +1854,9 @@
             }
             misc.subscriberId = mPhone.getSubscriberId();
 
+            // set skip464xlat if it is not default otherwise
+            misc.skip464xlat = shouldSkip464Xlat();
+
             mRestrictedNetworkOverride = shouldRestrictNetwork();
             mUnmeteredUseOnly = isUnmeteredUseOnly();
 
@@ -2763,6 +2817,12 @@
         return "{" + toStringSimple() + " mApnContexts=" + mApnContexts + "}";
     }
 
+    /** Check if the device is connected to NR 5G Non-Standalone network. */
+    private boolean isNRConnected() {
+        return mPhone.getServiceState().getNrStatus()
+                == NetworkRegistrationState.NR_STATUS_CONNECTED;
+    }
+
     private void dumpToLog() {
         dump(null, new PrintWriter(new StringWriter(0)) {
             @Override
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index 9015be4..6e477ce 100755
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -66,6 +66,7 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.CellLocation;
 import android.telephony.DataFailCause;
+import android.telephony.NetworkRegistrationState;
 import android.telephony.PcoData;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
@@ -128,6 +129,25 @@
     private static final boolean VDBG_STALL = false; // STOPSHIP if true
     private static final boolean RADIO_TESTS = false;
 
+    /**
+     * These constants exist here because ConnectivityManager.TYPE_xxx constants are deprecated and
+     * new ones will not be added (for instance NETWORK_TYPE_MCX below).
+     * For backward compatibility, the values here need to be the same as
+     * ConnectivityManager.TYPE_xxx because networkAttributes overlay uses those values.
+     */
+    private static final int NETWORK_TYPE_DEFAULT = ConnectivityManager.TYPE_MOBILE;
+    private static final int NETWORK_TYPE_MMS = ConnectivityManager.TYPE_MOBILE_MMS;
+    private static final int NETWORK_TYPE_SUPL = ConnectivityManager.TYPE_MOBILE_SUPL;
+    private static final int NETWORK_TYPE_DUN = ConnectivityManager.TYPE_MOBILE_DUN;
+    private static final int NETWORK_TYPE_HIPRI = ConnectivityManager.TYPE_MOBILE_HIPRI;
+    private static final int NETWORK_TYPE_FOTA = ConnectivityManager.TYPE_MOBILE_FOTA;
+    private static final int NETWORK_TYPE_IMS = ConnectivityManager.TYPE_MOBILE_IMS;
+    private static final int NETWORK_TYPE_CBS = ConnectivityManager.TYPE_MOBILE_CBS;
+    private static final int NETWORK_TYPE_IA = ConnectivityManager.TYPE_MOBILE_IA;
+    private static final int NETWORK_TYPE_EMERGENCY = ConnectivityManager.TYPE_MOBILE_EMERGENCY;
+    private static final int NETWORK_TYPE_MCX = 1001;  // far away from ConnectivityManager.TYPE_xxx
+                                                       // constants as MCX isn't defined there.
+
     @IntDef(value = {
             REQUEST_TYPE_NORMAL,
             REQUEST_TYPE_HANDOVER,
@@ -733,9 +753,9 @@
     }
 
     public void registerServiceStateTrackerEvents() {
-        mPhone.getServiceStateTracker().registerForDataConnectionAttached(this,
+        mPhone.getServiceStateTracker().registerForDataConnectionAttached(mTransportType, this,
                 DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null);
-        mPhone.getServiceStateTracker().registerForDataConnectionDetached(this,
+        mPhone.getServiceStateTracker().registerForDataConnectionDetached(mTransportType, this,
                 DctConstants.EVENT_DATA_CONNECTION_DETACHED, null);
         mPhone.getServiceStateTracker().registerForDataRoamingOn(this,
                 DctConstants.EVENT_ROAMING_ON, null);
@@ -745,18 +765,19 @@
                 DctConstants.EVENT_PS_RESTRICT_ENABLED, null);
         mPhone.getServiceStateTracker().registerForPsRestrictedDisabled(this,
                 DctConstants.EVENT_PS_RESTRICT_DISABLED, null);
-        mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(this,
+        mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(mTransportType, this,
                 DctConstants.EVENT_DATA_RAT_CHANGED, null);
     }
 
     public void unregisterServiceStateTrackerEvents() {
-        mPhone.getServiceStateTracker().unregisterForDataConnectionAttached(this);
-        mPhone.getServiceStateTracker().unregisterForDataConnectionDetached(this);
+        mPhone.getServiceStateTracker().unregisterForDataConnectionAttached(mTransportType, this);
+        mPhone.getServiceStateTracker().unregisterForDataConnectionDetached(mTransportType, this);
         mPhone.getServiceStateTracker().unregisterForDataRoamingOn(this);
         mPhone.getServiceStateTracker().unregisterForDataRoamingOff(this);
         mPhone.getServiceStateTracker().unregisterForPsRestrictedEnabled(this);
         mPhone.getServiceStateTracker().unregisterForPsRestrictedDisabled(this);
-        mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(this);
+        mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(mTransportType,
+                this);
     }
 
     private void registerForAllEvents() {
@@ -969,42 +990,45 @@
                 com.android.internal.R.array.networkAttributes);
         for (String networkConfigString : networkConfigStrings) {
             NetworkConfig networkConfig = new NetworkConfig(networkConfigString);
-            ApnContext apnContext = null;
+            ApnContext apnContext;
 
             switch (networkConfig.type) {
-            case ConnectivityManager.TYPE_MOBILE:
-                apnContext = addApnContext(PhoneConstants.APN_TYPE_DEFAULT, networkConfig);
-                break;
-            case ConnectivityManager.TYPE_MOBILE_MMS:
-                apnContext = addApnContext(PhoneConstants.APN_TYPE_MMS, networkConfig);
-                break;
-            case ConnectivityManager.TYPE_MOBILE_SUPL:
-                apnContext = addApnContext(PhoneConstants.APN_TYPE_SUPL, networkConfig);
-                break;
-            case ConnectivityManager.TYPE_MOBILE_DUN:
-                apnContext = addApnContext(PhoneConstants.APN_TYPE_DUN, networkConfig);
-                break;
-            case ConnectivityManager.TYPE_MOBILE_HIPRI:
-                apnContext = addApnContext(PhoneConstants.APN_TYPE_HIPRI, networkConfig);
-                break;
-            case ConnectivityManager.TYPE_MOBILE_FOTA:
-                apnContext = addApnContext(PhoneConstants.APN_TYPE_FOTA, networkConfig);
-                break;
-            case ConnectivityManager.TYPE_MOBILE_IMS:
-                apnContext = addApnContext(PhoneConstants.APN_TYPE_IMS, networkConfig);
-                break;
-            case ConnectivityManager.TYPE_MOBILE_CBS:
-                apnContext = addApnContext(PhoneConstants.APN_TYPE_CBS, networkConfig);
-                break;
-            case ConnectivityManager.TYPE_MOBILE_IA:
-                apnContext = addApnContext(PhoneConstants.APN_TYPE_IA, networkConfig);
-                break;
-            case ConnectivityManager.TYPE_MOBILE_EMERGENCY:
-                apnContext = addApnContext(PhoneConstants.APN_TYPE_EMERGENCY, networkConfig);
-                break;
-            default:
-                log("initApnContexts: skipping unknown type=" + networkConfig.type);
-                continue;
+                case NETWORK_TYPE_DEFAULT:
+                    apnContext = addApnContext(PhoneConstants.APN_TYPE_DEFAULT, networkConfig);
+                    break;
+                case NETWORK_TYPE_MMS:
+                    apnContext = addApnContext(PhoneConstants.APN_TYPE_MMS, networkConfig);
+                    break;
+                case NETWORK_TYPE_SUPL:
+                    apnContext = addApnContext(PhoneConstants.APN_TYPE_SUPL, networkConfig);
+                    break;
+                case NETWORK_TYPE_DUN:
+                    apnContext = addApnContext(PhoneConstants.APN_TYPE_DUN, networkConfig);
+                    break;
+                case NETWORK_TYPE_HIPRI:
+                    apnContext = addApnContext(PhoneConstants.APN_TYPE_HIPRI, networkConfig);
+                    break;
+                case NETWORK_TYPE_FOTA:
+                    apnContext = addApnContext(PhoneConstants.APN_TYPE_FOTA, networkConfig);
+                    break;
+                case NETWORK_TYPE_IMS:
+                    apnContext = addApnContext(PhoneConstants.APN_TYPE_IMS, networkConfig);
+                    break;
+                case NETWORK_TYPE_CBS:
+                    apnContext = addApnContext(PhoneConstants.APN_TYPE_CBS, networkConfig);
+                    break;
+                case NETWORK_TYPE_IA:
+                    apnContext = addApnContext(PhoneConstants.APN_TYPE_IA, networkConfig);
+                    break;
+                case NETWORK_TYPE_EMERGENCY:
+                    apnContext = addApnContext(PhoneConstants.APN_TYPE_EMERGENCY, networkConfig);
+                    break;
+                case NETWORK_TYPE_MCX:
+                    apnContext = addApnContext(PhoneConstants.APN_TYPE_MCX, networkConfig);
+                    break;
+                default:
+                    log("initApnContexts: skipping unknown type=" + networkConfig.type);
+                    continue;
             }
             log("initApnContexts: apnContext=" + apnContext);
         }
@@ -1219,7 +1243,7 @@
         boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
         boolean radioStateFromCarrier = mPhone.getServiceStateTracker().getPowerStateFromCarrier();
         // TODO: Remove this hack added by ag/641832.
-        int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
+        int radioTech = getDataRat();
         if (radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) {
             desiredPowerState = true;
             radioStateFromCarrier = true;
@@ -1427,7 +1451,7 @@
                 apnContext.requestLog(str);
                 apnContext.setState(DctConstants.State.IDLE);
             }
-            int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
+            int radioTech = getDataRat();
             apnContext.setConcurrentVoiceAndDataAllowed(mPhone.getServiceStateTracker()
                     .isConcurrentVoiceAndDataAllowed());
             if (apnContext.getState() == DctConstants.State.IDLE) {
@@ -1674,7 +1698,7 @@
             log("fetchDunApns: net.tethering.noprovisioning=true ret: empty list");
             return new ArrayList<ApnSetting>(0);
         }
-        int bearer = mPhone.getServiceState().getRilDataRadioTechnology();
+        int bearer = getDataRat();
         ArrayList<ApnSetting> dunCandidates = new ArrayList<ApnSetting>();
         ArrayList<ApnSetting> retDunSettings = new ArrayList<ApnSetting>();
 
@@ -1765,7 +1789,7 @@
      */
     private boolean teardownForDun() {
         // CDMA always needs to do this the profile id is correct
-        final int rilRat = mPhone.getServiceState().getRilDataRadioTechnology();
+        final int rilRat = getDataRat();
         if (ServiceState.isCdma(rilRat)) return true;
 
         ArrayList<ApnSetting> apns = fetchDunApns();
@@ -1855,7 +1879,7 @@
         // On GSM/LTE we can share existing apn connections provided they support
         // this type.
         if (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DUN)
-                || ServiceState.isGsm(mPhone.getServiceState().getRilDataRadioTechnology())) {
+                || ServiceState.isGsm(getDataRat())) {
             dataConnection = checkForCompatibleConnectedApnContext(apnContext);
             if (dataConnection != null) {
                 // Get the apn setting used by the data connection
@@ -2107,9 +2131,8 @@
         boolean retry = true;
         String reason = apnContext.getReason();
 
-        if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ||
-                (isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology())
-                 && isHigherPriorityApnContextActive(apnContext))) {
+        if (Phone.REASON_RADIO_TURNED_OFF.equals(reason) || (isOnlySingleDcAllowed(getDataRat())
+                && isHigherPriorityApnContextActive(apnContext))) {
             retry = false;
         }
         return retry;
@@ -2409,8 +2432,7 @@
             cleanUpConnectionInternal(true, releaseType, apnContext);
         }
 
-        if (isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology())
-                && !isHigherPriorityApnContextActive(apnContext)) {
+        if (isOnlySingleDcAllowed(getDataRat()) && !isHigherPriorityApnContextActive(apnContext)) {
             if (DBG) log("disableApn:isOnlySingleDcAllowed true & higher priority APN disabled");
             // If the highest priority APN is disabled and only single
             // data call is allowed, try to setup data call on other connectable APN.
@@ -2842,9 +2864,8 @@
                         cause, cid, mTelephonyManager.getNetworkType());
             }
             ApnSetting apn = apnContext.getApnSetting();
-            mPhone.notifyPreciseDataConnectionFailed(
-                    apnContext.getApnType(), apn != null ? apn.getApnName()
-                    : "unknown", cause);
+            mPhone.notifyPreciseDataConnectionFailed(apnContext.getApnType(),
+                    apn != null ? apn.getApnName() : null, cause);
 
             // Compose broadcast intent send to the specific carrier signaling receivers
             Intent intent = new Intent(TelephonyIntents
@@ -2984,7 +3005,7 @@
             }
             apnContext.setApnSetting(null);
             apnContext.setDataConnection(null);
-            if (isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology())) {
+            if (isOnlySingleDcAllowed(getDataRat())) {
                 if(DBG) log("onDisconnectDone: isOnlySigneDcAllowed true so setup single apn");
                 setupDataOnConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION,
                         RetryFailures.ALWAYS);
@@ -3180,7 +3201,8 @@
             dest.isEnabled(), networkTypeBitmask, dest.getProfileId(),
             (dest.isPersistent() || src.isPersistent()), dest.getMaxConns(),
             dest.getWaitTime(), dest.getMaxConnsTime(), dest.getMtu(), dest.getMvnoType(),
-            dest.getMvnoMatchData(), dest.getApnSetId(), dest.getCarrierId());
+            dest.getMvnoMatchData(), dest.getApnSetId(), dest.getCarrierId(),
+            dest.getSkip464Xlat());
     }
 
     private DataConnection createDataConnection() {
@@ -3503,8 +3525,7 @@
                 break;
 
             case DctConstants.EVENT_DATA_RAT_CHANGED:
-                if (mPhone.getServiceState().getRilDataRadioTechnology()
-                        == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
+                if (getDataRat() == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
                     // unknown rat is an exception for data rat change. It's only received when out
                     // of service and is not applicable for apn bearer bitmask. We should bypass the
                     // check of waiting apn list and keep the data connection on, and no need to
@@ -4114,8 +4135,7 @@
         if (mAllApnSettings.isEmpty()) {
             cleanUpAllConnectionsInternal(detach, Phone.REASON_APN_CHANGED);
         } else {
-            int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
-            if (radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
+            if (getDataRat() == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
                 // unknown rat is an exception for data rat change. Its only received when out of
                 // service and is not applicable for apn bearer bitmask. We should bypass the check
                 // of waiting apn list and keep the data connection on.
@@ -4124,8 +4144,7 @@
             for (ApnContext apnContext : mApnContexts.values()) {
                 ArrayList<ApnSetting> currentWaitingApns = apnContext.getWaitingApns();
                 ArrayList<ApnSetting> waitingApns = buildWaitingApns(
-                        apnContext.getApnType(),
-                        mPhone.getServiceState().getRilDataRadioTechnology());
+                        apnContext.getApnType(), getDataRat());
                 if (VDBG) log("new waitingApns:" + waitingApns);
                 if ((currentWaitingApns != null)
                         && ((waitingApns.size() != currentWaitingApns.size())
@@ -4738,4 +4757,14 @@
         }
         return "UNKNOWN";
     }
+
+    private int getDataRat() {
+        ServiceState ss = mPhone.getServiceState();
+        NetworkRegistrationState nrs = ss.getNetworkRegistrationState(
+                NetworkRegistrationState.DOMAIN_PS, mTransportType);
+        if (nrs != null) {
+            return ServiceState.networkTypeToRilRadioTechnology(nrs.getAccessNetworkTechnology());
+        }
+        return ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
+    }
 }
diff --git a/src/java/com/android/internal/telephony/TransportManager.java b/src/java/com/android/internal/telephony/dataconnection/TransportManager.java
similarity index 100%
rename from src/java/com/android/internal/telephony/TransportManager.java
rename to src/java/com/android/internal/telephony/dataconnection/TransportManager.java
diff --git a/src/java/com/android/internal/telephony/ims/RcsMessageStoreController.java b/src/java/com/android/internal/telephony/ims/RcsMessageStoreController.java
index ffe4bac..fd00dff 100644
--- a/src/java/com/android/internal/telephony/ims/RcsMessageStoreController.java
+++ b/src/java/com/android/internal/telephony/ims/RcsMessageStoreController.java
@@ -131,6 +131,9 @@
         synchronized (RcsMessageStoreController.class) {
             if (sInstance == null) {
                 sInstance = new RcsMessageStoreController(context.getContentResolver());
+                if (ServiceManager.getService(RCS_SERVICE_NAME) == null) {
+                    ServiceManager.addService(RCS_SERVICE_NAME, sInstance);
+                }
             } else {
                 Rlog.e(TAG, "init() called multiple times! sInstance = " + sInstance);
             }
@@ -138,20 +141,8 @@
         return sInstance;
     }
 
-    private RcsMessageStoreController(ContentResolver contentResolver) {
-        mContentResolver = contentResolver;
-        mParticipantQueryHelper = new RcsParticipantQueryHelper(contentResolver);
-        mMessageQueryHelper = new RcsMessageQueryHelper(contentResolver);
-        mThreadQueryHelper = new RcsThreadQueryHelper(contentResolver, mParticipantQueryHelper);
-        mEventQueryHelper = new RcsEventQueryHelper(contentResolver);
-        mMessageStoreUtil = new RcsMessageStoreUtil(contentResolver);
-        if (ServiceManager.getService(RCS_SERVICE_NAME) == null) {
-            ServiceManager.addService(RCS_SERVICE_NAME, this);
-        }
-    }
-
     @VisibleForTesting
-    public RcsMessageStoreController(ContentResolver contentResolver, Void unused) {
+    public RcsMessageStoreController(ContentResolver contentResolver) {
         mContentResolver = contentResolver;
         mParticipantQueryHelper = new RcsParticipantQueryHelper(contentResolver);
         mMessageQueryHelper = new RcsMessageQueryHelper(contentResolver);
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
index ab39212..79322e5 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
@@ -272,10 +272,13 @@
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
         mWakeLock.setReferenceCounted(false);
 
-        if (mDefaultPhone.getServiceStateTracker() != null) {
-            mDefaultPhone.getServiceStateTracker()
-                    .registerForDataRegStateOrRatChanged(this,
-                            EVENT_DEFAULT_PHONE_DATA_STATE_CHANGED, null);
+        if (mDefaultPhone.getServiceStateTracker() != null
+                && mDefaultPhone.getTransportManager() != null) {
+            for (int transport : mDefaultPhone.getTransportManager().getAvailableTransports()) {
+                mDefaultPhone.getServiceStateTracker()
+                        .registerForDataRegStateOrRatChanged(transport, this,
+                                EVENT_DEFAULT_PHONE_DATA_STATE_CHANGED, null);
+            }
         }
         // Sets the Voice reg state to STATE_OUT_OF_SERVICE and also queries the data service
         // state. We don't ever need the voice reg state to be anything other than in or out of
@@ -301,8 +304,10 @@
 
         //Force all referenced classes to unregister their former registered events
         if (mDefaultPhone != null && mDefaultPhone.getServiceStateTracker() != null) {
-            mDefaultPhone.getServiceStateTracker().
-                    unregisterForDataRegStateOrRatChanged(this);
+            for (int transport : mDefaultPhone.getTransportManager().getAvailableTransports()) {
+                mDefaultPhone.getServiceStateTracker()
+                        .unregisterForDataRegStateOrRatChanged(transport, this);
+            }
             mDefaultPhone.unregisterForServiceStateChanged(this);
         }
     }
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index b78932b..0a6ed7b 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -113,6 +113,7 @@
 import java.util.Map;
 import java.util.Queue;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.regex.Pattern;
@@ -499,8 +500,12 @@
 
 
     //***** Constructors
-
     public ImsPhoneCallTracker(ImsPhone phone) {
+        this(phone, phone.getContext().getMainExecutor());
+    }
+
+    @VisibleForTesting
+    public ImsPhoneCallTracker(ImsPhone phone, Executor executor) {
         this.mPhone = phone;
 
         mMetrics = TelephonyMetrics.getInstance();
@@ -523,6 +528,7 @@
         mVtDataUsageSnapshot = new NetworkStats(currentTime, 1);
         mVtDataUsageUidSnapshot = new NetworkStats(currentTime, 1);
 
+        // Allow the executor to be specified for testing.
         mImsManagerConnector = new ImsManager.Connector(phone.getContext(), phone.getPhoneId(),
                 new ImsManager.Connector.Listener() {
                     @Override
@@ -535,7 +541,7 @@
                     public void connectionUnavailable() {
                         stopListeningForCalls();
                     }
-                });
+                }, executor);
         mImsManagerConnector.connect();
     }
 
@@ -2973,7 +2979,7 @@
                 }
 
                 @Override
-                public void onDeregistered(ImsReasonInfo imsReasonInfo) {
+                public void onUnregistered(ImsReasonInfo imsReasonInfo) {
                     if (DBG) log("onImsDisconnected imsReasonInfo=" + imsReasonInfo);
                     mPhone.setServiceState(ServiceState.STATE_OUT_OF_SERVICE);
                     mPhone.setImsRegistered(false);
@@ -3257,6 +3263,7 @@
                 ImsPhoneConnection oldConnection = findConnection(callInfo.first);
                 if (oldConnection == null) {
                     sendCallStartFailedDisconnect(callInfo.first, callInfo.second);
+                    break;
                 }
                 mForegroundCall.detach(oldConnection);
                 removeConnection(oldConnection);
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java
index 72f3a38..6f23b2a 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java
@@ -38,6 +38,7 @@
 import android.os.ResultReceiver;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.Rlog;
+import android.telephony.ims.ImsCallForwardInfo;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.ImsSsData;
 import android.telephony.ims.ImsSsInfo;
@@ -54,6 +55,7 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.uicc.IccRecords;
 
+import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -1531,15 +1533,17 @@
                 sb.append(getErrorMessage(ar));
             }
         } else {
-            ImsSsInfo[] infos = (ImsSsInfo[])ar.result;
-            if (infos.length == 0) {
+            List<ImsSsInfo> infos = (List<ImsSsInfo>) ar.result;
+            if (infos.size() == 0) {
                 sb.append(mContext.getText(com.android.internal.R.string.serviceDisabled));
             } else {
-                for (int i = 0, s = infos.length; i < s ; i++) {
-                    if (infos[i].getIncomingCommunicationBarringNumber() != null) {
-                        sb.append("Num: " + infos[i].getIncomingCommunicationBarringNumber()
-                                + " status: " + infos[i].getStatus() + "\n");
-                    } else if (infos[i].getStatus() == 1) {
+                ImsSsInfo info;
+                for (int i = 0, s = infos.size(); i < s; i++) {
+                    info = infos.get(i);
+                    if (info.getIncomingCommunicationBarringNumber() != null) {
+                        sb.append("Num: " + info.getIncomingCommunicationBarringNumber()
+                                + " status: " + info.getStatus() + "\n");
+                    } else if (info.getStatus() == 1) {
                         sb.append(mContext.getText(com.android.internal
                                 .R.string.serviceEnabled));
                     } else {
@@ -1772,8 +1776,16 @@
                     onQueryClirComplete(new AsyncResult(null, clirInfo, ex));
                 } else if (ssData.isTypeCF()) {
                     Rlog.d(LOG_TAG, "CALL FORWARD INTERROGATION");
-                    onQueryCfComplete(new AsyncResult(null, mPhone
-                            .handleCfQueryResult(ssData.getCallForwardInfo()), ex));
+                    // Have to translate to an array, since the modem still returns it in the
+                    // ImsCallForwardInfo[] format.
+                    List<ImsCallForwardInfo> mCfInfos = ssData.getCallForwardInfo();
+                    ImsCallForwardInfo[] mCfInfosCompat = null;
+                    if (mCfInfos != null) {
+                        mCfInfosCompat = new ImsCallForwardInfo[mCfInfos.size()];
+                        mCfInfosCompat = mCfInfos.toArray(mCfInfosCompat);
+                    }
+                    onQueryCfComplete(new AsyncResult(null, mPhone.handleCfQueryResult(
+                            mCfInfosCompat), ex));
                 } else if (ssData.isTypeBarring()) {
                     onSuppSvcQueryComplete(new AsyncResult(null, ssData.getSuppServiceInfoCompat(),
                             ex));
diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java b/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java
index 56db4ba..8a97579 100644
--- a/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java
+++ b/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java
@@ -19,6 +19,7 @@
 import static com.android.internal.telephony.nano.TelephonyProto.ImsCapabilities;
 import static com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState;
 import static com.android.internal.telephony.nano.TelephonyProto.RilDataCall;
+import static com.android.internal.telephony.nano.TelephonyProto.SimState;
 import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent;
 import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierIdMatching;
 import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierKeyChange;
@@ -30,10 +31,16 @@
 import static com.android.internal.telephony.nano.TelephonyProto.TelephonySettings;
 
 import android.os.SystemClock;
+import android.telephony.TelephonyManager;
+import android.util.SparseArray;
 
-import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.PhoneStatus;
+import com.android.internal.telephony.nano.TelephonyProto.ActiveSubscriptionInfo;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwitch;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.OnDemandDataSwitch;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.Type;
 
+import java.util.Arrays;
+
 public class TelephonyEventBuilder {
     private final TelephonyEvent mEvent = new TelephonyEvent();
 
@@ -41,6 +48,11 @@
         return mEvent;
     }
 
+    /** The event is not related to any phone id. */
+    public TelephonyEventBuilder() {
+        this(-1 /* phoneId */);
+    }
+
     public TelephonyEventBuilder(int phoneId) {
         this(SystemClock.elapsedRealtime(), phoneId);
     }
@@ -137,12 +149,53 @@
         return this;
     }
 
-    /**
-     * Set and build phone status changed event.
-     */
-    public TelephonyEventBuilder setPhoneStatusChange(PhoneStatus phoneStatus) {
-        mEvent.type = Type.PHONE_STATUS_CHANGED;
-        mEvent.phoneStatus = phoneStatus;
+    /** Set and build SIM state change event. */
+    public TelephonyEventBuilder setSimStateChange(SparseArray<Integer> simStates) {
+        int phoneCount = TelephonyManager.getDefault().getPhoneCount();
+        mEvent.simState = new int[phoneCount];
+        Arrays.fill(mEvent.simState, SimState.SIM_STATE_UNKNOWN);
+        mEvent.type = Type.SIM_STATE_CHANGED;
+        for (int i = 0; i < simStates.size(); i++) {
+            int key = simStates.keyAt(i);
+            if (0 <= key && key < phoneCount) {
+                mEvent.simState[key] = simStates.get(key);
+            }
+        }
+        return this;
+    }
+
+    /** Set and build subscription info change event. */
+    public TelephonyEventBuilder setActiveSubscriptionInfoChange(ActiveSubscriptionInfo info) {
+        mEvent.type = Type.ACTIVE_SUBSCRIPTION_INFO_CHANGED;
+        mEvent.activeSubscriptionInfo = info;
+        return this;
+    }
+
+    /** Set and build enabled modem bitmap change event. */
+    public TelephonyEventBuilder setEnabledModemBitmap(int enabledModemBitmap) {
+        mEvent.type = Type.ENABLED_MODEM_CHANGED;
+        mEvent.enabledModemBitmap = enabledModemBitmap;
+        return this;
+    }
+
+    /** Set and build data switch event. */
+    public TelephonyEventBuilder setDataSwitch(DataSwitch dataSwitch) {
+        mEvent.type = TelephonyEvent.Type.DATA_SWITCH;
+        mEvent.dataSwitch = dataSwitch;
+        return this;
+    }
+
+    /** Set and build network validation event. */
+    public TelephonyEventBuilder setNetworkValidate(int networkValidationState) {
+        mEvent.type = TelephonyEvent.Type.NETWORK_VALIDATE;
+        mEvent.networkValidationState = networkValidationState;
+        return this;
+    }
+
+    /** Set and build on demand data switch event. */
+    public TelephonyEventBuilder setOnDemandDataSwitch(OnDemandDataSwitch onDemandDataSwitch) {
+        mEvent.type = TelephonyEvent.Type.ON_DEMAND_DATA_SWITCH;
+        mEvent.onDemandDataSwitch = onDemandDataSwitch;
         return this;
     }
 }
diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
index fa7f18c..39cdea4 100644
--- a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
+++ b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
@@ -86,8 +86,9 @@
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierIdMatching;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierIdMatchingResult;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierKeyChange;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwitch;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.ModemRestart;
-import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.PhoneStatus;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.OnDemandDataSwitch;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilDeactivateDataCall;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilDeactivateDataCall.DeactivateReason;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCall;
@@ -598,7 +599,18 @@
             addTelephonyEvent(event);
         }
 
-        writePhoneStatusChangedEvent();
+        for (int i = 0; i < mLastActiveSubscriptionInfos.size(); i++) {
+            final int key = mLastActiveSubscriptionInfos.keyAt(i);
+            TelephonyEvent event = new TelephonyEventBuilder(mStartElapsedTimeMs, key)
+                    .setActiveSubscriptionInfoChange(mLastActiveSubscriptionInfos.get(key)).build();
+            addTelephonyEvent(event);
+        }
+
+        addTelephonyEvent(new TelephonyEventBuilder(mStartElapsedTimeMs, -1 /* phoneId */)
+                .setSimStateChange(mLastSimState).build());
+
+        addTelephonyEvent(new TelephonyEventBuilder(mStartElapsedTimeMs, -1 /* phoneId */)
+                .setEnabledModemBitmap(mLastEnabledModemBitmap).build());
     }
 
     /**
@@ -655,6 +667,16 @@
         log.endTime = new TelephonyProto.Time();
         log.endTime.systemTimestampMillis = System.currentTimeMillis();
         log.endTime.elapsedTimestampMillis = SystemClock.elapsedRealtime();
+
+        // Log the last active subscription information.
+        ActiveSubscriptionInfo[] activeSubscriptionInfo =
+                new ActiveSubscriptionInfo[mLastActiveSubscriptionInfos.size()];
+        for (int i = 0; i < mLastActiveSubscriptionInfos.size(); i++) {
+            int key = mLastActiveSubscriptionInfos.keyAt(i);
+            activeSubscriptionInfo[key] = mLastActiveSubscriptionInfos.get(key);
+        }
+        log.lastActiveSubscriptionInfo = activeSubscriptionInfo;
+
         return log;
     }
 
@@ -664,19 +686,41 @@
         Integer lastSimState = mLastSimState.get(phoneId);
         if (lastSimState == null || !lastSimState.equals(state)) {
             mLastSimState.put(phoneId, state);
-            writePhoneStatusChangedEvent();
+            addTelephonyEvent(new TelephonyEventBuilder().setSimStateChange(mLastSimState).build());
         }
     }
 
     /** Update active subscription info list. */
     public void updateActiveSubscriptionInfoList(List<SubscriptionInfo> subInfos) {
-        mLastActiveSubscriptionInfos.clear();
+        List<Integer> inActivePhoneList = new ArrayList<>();
+        for (int i = 0; i < mLastActiveSubscriptionInfos.size(); i++) {
+            inActivePhoneList.add(mLastActiveSubscriptionInfos.keyAt(i));
+        }
+
         for (SubscriptionInfo info : subInfos) {
             int phoneId = SubscriptionManager.getPhoneId(info.getSubscriptionId());
+            inActivePhoneList.removeIf(value -> value.equals(phoneId));
             ActiveSubscriptionInfo activeSubscriptionInfo = new ActiveSubscriptionInfo();
-            activeSubscriptionInfo.isOpportunistic = info.isOpportunistic();
+            activeSubscriptionInfo.slotIndex = phoneId;
+            activeSubscriptionInfo.isOpportunistic = info.isOpportunistic() ? 1 : 0;
             activeSubscriptionInfo.carrierId = info.getCarrierId();
-            mLastActiveSubscriptionInfos.put(phoneId, activeSubscriptionInfo);
+            if (isDifferentSubscriptionInfo(
+                    mLastActiveSubscriptionInfos.get(phoneId), activeSubscriptionInfo)) {
+                addTelephonyEvent(new TelephonyEventBuilder(phoneId)
+                        .setActiveSubscriptionInfoChange(activeSubscriptionInfo).build());
+
+                mLastActiveSubscriptionInfos.put(phoneId, activeSubscriptionInfo);
+            }
+        }
+
+        for (int phoneId : inActivePhoneList) {
+            mLastActiveSubscriptionInfos.remove(phoneId);
+            ActiveSubscriptionInfo invalidSubInfo = new ActiveSubscriptionInfo();
+            invalidSubInfo.slotIndex = phoneId;
+            invalidSubInfo.carrierId = -1;
+            invalidSubInfo.isOpportunistic = -1;
+            addTelephonyEvent(new TelephonyEventBuilder(phoneId)
+                    .setActiveSubscriptionInfoChange(invalidSubInfo).build());
         }
     }
 
@@ -684,28 +728,8 @@
     public void updateEnabledModemBitmap(int enabledModemBitmap) {
         if (mLastEnabledModemBitmap == enabledModemBitmap) return;
         mLastEnabledModemBitmap = enabledModemBitmap;
-        writePhoneStatusChangedEvent();
-    }
-
-    /** Write the event of phone status changed. */
-    public void writePhoneStatusChangedEvent() {
-        int phoneCount = TelephonyManager.getDefault().getPhoneCount();
-        PhoneStatus phoneStatus = new PhoneStatus();
-        phoneStatus.enabledModemBitmap = mLastEnabledModemBitmap;
-        phoneStatus.simState = new int[phoneCount];
-        Arrays.fill(phoneStatus.simState, SimState.SIM_STATE_ABSENT);
-        for (int i = 0; i < mLastSimState.size(); i++) {
-            int phoneId = mLastSimState.keyAt(i);
-            if (SubscriptionManager.isValidPhoneId(phoneId)) {
-                phoneStatus.simState[phoneId] = mLastSimState.get(phoneId);
-            }
-        }
-
-        // Phone status is not associated with any phone id, so set the phone id to -1 for the phone
-        // status changed event.
-        addTelephonyEvent(new TelephonyEventBuilder(-1 /* phoneId */)
-                .setPhoneStatusChange(phoneStatus)
-                .build());
+        addTelephonyEvent(new TelephonyEventBuilder()
+                .setEnabledModemBitmap(mLastEnabledModemBitmap).build());
     }
 
     /**
@@ -1709,6 +1733,32 @@
     }
 
     /**
+     * Write network validation event.
+     * @param networkValidationState the network validation state.
+     */
+    public void writeNetworkValidate(int networkValidationState) {
+        addTelephonyEvent(
+                new TelephonyEventBuilder().setNetworkValidate(networkValidationState).build());
+    }
+
+    /**
+     * Write data switch event.
+     * @param dataSwitch the reason and state of data switch.
+     */
+    public void writeDataSwitch(DataSwitch dataSwitch) {
+        addTelephonyEvent(new TelephonyEventBuilder().setDataSwitch(dataSwitch).build());
+    }
+
+    /**
+     * Write on demand data switch event.
+     * @param onDemandDataSwitch the apn and state of on demand data switch.
+     */
+    public void writeOnDemandDataSwitch(OnDemandDataSwitch onDemandDataSwitch) {
+        addTelephonyEvent(
+                new TelephonyEventBuilder().setOnDemandDataSwitch(onDemandDataSwitch).build());
+    }
+
+    /**
      * Write phone state changed event
      *
      * @param phoneId Phone id
@@ -2434,4 +2484,14 @@
                 return SimState.SIM_STATE_UNKNOWN;
         }
     }
+
+    private static boolean isDifferentSubscriptionInfo(
+            ActiveSubscriptionInfo oldInfo, ActiveSubscriptionInfo newInfo) {
+        if (oldInfo == null || newInfo == null) {
+            return oldInfo == newInfo;
+        }
+
+        return oldInfo.slotIndex != newInfo.slotIndex || oldInfo.carrierId != newInfo.carrierId
+                || oldInfo.isOpportunistic != newInfo.isOpportunistic;
+    }
 }
diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java
index 23eabad..99f3aa5 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccController.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccController.java
@@ -16,6 +16,9 @@
 
 package com.android.internal.telephony.uicc;
 
+import static android.telephony.TelephonyManager.UNINITIALIZED_CARD_ID;
+import static android.telephony.TelephonyManager.UNSUPPORTED_CARD_ID;
+
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
@@ -128,6 +131,8 @@
     // The array index is the card ID (int).
     // This mapping exists to expose card-based functionality without exposing the EID, which is
     // considered sensetive information.
+    // mCardStrings is populated using values from the IccSlotStatus and IccCardStatus. For
+    // HAL < 1.2, these do not contain the EID or the ICCID, so mCardStrings will be empty
     private ArrayList<String> mCardStrings;
 
     // This is the card ID of the default eUICC. It starts as UNINITIALIZED_CARD_ID.
@@ -213,7 +218,7 @@
 
         mLauncher = new UiccStateChangedLauncher(c, this);
         mCardStrings = loadCardStrings();
-        mDefaultEuiccCardId = TelephonyManager.UNINITIALIZED_CARD_ID;
+        mDefaultEuiccCardId = UNINITIALIZED_CARD_ID;
     }
 
     private int getSlotIdFromPhoneId(int phoneId) {
@@ -555,7 +560,8 @@
 
         if (eidIsNotSupported(status)) {
             // we will never get EID from the HAL, so set mDefaultEuiccCardId to UNSUPPORTED_CARD_ID
-            mDefaultEuiccCardId = TelephonyManager.UNSUPPORTED_CARD_ID;
+            if (DBG) log("eid is not supported");
+            mDefaultEuiccCardId = UNSUPPORTED_CARD_ID;
         }
         mPhoneIdToSlotId[index] = slotId;
 
@@ -589,7 +595,7 @@
         // EID may be unpopulated if RadioConfig<1.2
         // If so, just register for EID loaded and skip this stuff
         if (isEuicc && cardString == null
-                && mDefaultEuiccCardId != TelephonyManager.UNSUPPORTED_CARD_ID) {
+                && mDefaultEuiccCardId != UNSUPPORTED_CARD_ID) {
             ((EuiccCard) card).registerForEidReady(this, EVENT_EID_READY, index);
         }
 
@@ -633,18 +639,24 @@
      * to match to a card ID.
      *
      * @return the matching cardId, or UNINITIALIZED_CARD_ID if the card string does not map to a
-     * currently loaded cardId
+     * currently loaded cardId, or UNSUPPORTED_CARD_ID if the device does not support card IDs
      */
     public int convertToPublicCardId(String cardString) {
-        if (TextUtils.isEmpty(cardString)) {
-            return TelephonyManager.UNINITIALIZED_CARD_ID;
+        if (mDefaultEuiccCardId == UNSUPPORTED_CARD_ID) {
+            // even if cardString is not an EID, if EID is not supported (e.g. HAL < 1.2) we can't
+            // guarentee a working card ID implementation, so return UNSUPPORTED_CARD_ID
+            return UNSUPPORTED_CARD_ID;
         }
+        if (TextUtils.isEmpty(cardString)) {
+            return UNINITIALIZED_CARD_ID;
+        }
+
         if (cardString.length() < EID_LENGTH) {
             cardString = IccUtils.stripTrailingFs(cardString);
         }
         int id = mCardStrings.indexOf(cardString);
         if (id == -1) {
-            return TelephonyManager.UNINITIALIZED_CARD_ID;
+            return UNINITIALIZED_CARD_ID;
         } else {
             return id;
         }
@@ -916,7 +928,7 @@
         // set mCardStrings and the defaultEuiccCardId using the now available EID
         String eid = ((EuiccCard) card).getEid();
         addCardId(eid);
-        if (mDefaultEuiccCardId == TelephonyManager.UNINITIALIZED_CARD_ID) {
+        if (mDefaultEuiccCardId == UNINITIALIZED_CARD_ID) {
             // TODO(b/122738148) the default eUICC should not be removable
             mDefaultEuiccCardId = convertToPublicCardId(eid);
             log("onEidReady: eid=" + eid + " slot=" + slotId + " mDefaultEuiccCardId="
diff --git a/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java b/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java
index 57f33ce..aa37ff7 100644
--- a/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java
+++ b/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java
@@ -226,7 +226,7 @@
     public void testRegistrationCallbackNoCallbackIfUnknown() throws RemoteException {
         mRegBinder.addRegistrationCallback(mCallback2);
         // Verify that if we have never set the registration state, we do not callback immediately
-        // with onDeregistered.
+        // with onUnregistered.
         verify(mCallback2, never()).onDeregistered(any(ImsReasonInfo.class));
     }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierRestrictionRulesTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierRestrictionRulesTest.java
index 1eac933..fdefa1d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierRestrictionRulesTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierRestrictionRulesTest.java
@@ -207,7 +207,7 @@
         list.add(new CarrierIdentifier(MCC4, MNC4, null, null, null, null));
         list.add(new CarrierIdentifier(MCC5, MNC5, null, null, null, null));
 
-        List<Boolean> result = rules.isCarrierIdentifiersAllowed(list);
+        List<Boolean> result = rules.areCarrierIdentifiersAllowed(list);
 
         List<Boolean> expected =
                 Arrays.asList(true, true, true, true, true, true, true, true, true, true, true);
@@ -247,7 +247,7 @@
         list.add(new CarrierIdentifier(MCC4, MNC4, null, null, null, null));
         list.add(new CarrierIdentifier(MCC5, MNC5, null, null, null, null));
 
-        List<Boolean> result = rules.isCarrierIdentifiersAllowed(list);
+        List<Boolean> result = rules.areCarrierIdentifiersAllowed(list);
 
         List<Boolean> expected =
                 Arrays.asList(true, true, true, true, true, true, true,
@@ -282,7 +282,7 @@
         list.add(new CarrierIdentifier(MCC1, MNC3, null, null, null, null));
         list.add(new CarrierIdentifier(MCC1, MNC4, null, null, null, null));
 
-        List<Boolean> result = rules.isCarrierIdentifiersAllowed(list);
+        List<Boolean> result = rules.areCarrierIdentifiersAllowed(list);
 
         List<Boolean> expected = Arrays.asList(true, true, true, true, false, false);
         assertTrue(result.equals(expected));
@@ -309,7 +309,7 @@
         list.add(new CarrierIdentifier(MCC4, MNC4, null, null, null, null));
         list.add(new CarrierIdentifier(MCC5, MNC5, null, null, null, null));
 
-        List<Boolean> result = rules.isCarrierIdentifiersAllowed(list);
+        List<Boolean> result = rules.areCarrierIdentifiersAllowed(list);
 
         List<Boolean> expected = Arrays.asList(true, true, true, true);
         assertTrue(result.equals(expected));
@@ -335,7 +335,7 @@
         list.add(new CarrierIdentifier(MCC4, MNC4, null, null, null, null));
         list.add(new CarrierIdentifier(MCC5, MNC5, null, null, null, null));
 
-        List<Boolean> result = rules.isCarrierIdentifiersAllowed(list);
+        List<Boolean> result = rules.areCarrierIdentifiersAllowed(list);
 
         List<Boolean> expected = Arrays.asList(false, false, false);
         assertTrue(result.equals(expected));
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityNrTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityNrTest.java
index e6e8590..ed7fc1c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityNrTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityNrTest.java
@@ -45,7 +45,7 @@
 
         // THEN the get method should return correct value
         assertThat(cellIdentityNr.getType()).isEqualTo(CellInfo.TYPE_NR);
-        assertThat(cellIdentityNr.getChannelNumber()).isEqualTo(NRARFCN);
+        assertThat(cellIdentityNr.getNrarfcn()).isEqualTo(NRARFCN);
         assertThat(cellIdentityNr.getPci()).isEqualTo(PCI);
         assertThat(cellIdentityNr.getTac()).isEqualTo(TAC);
         assertThat(cellIdentityNr.getOperatorAlphaLong()).isEqualTo(ALPHAL);
@@ -95,7 +95,7 @@
         // THEN the new object is equal to the old one
         assertThat(anotherCellIdentityNr).isEqualTo(anotherCellIdentityNr);
         assertThat(anotherCellIdentityNr.getType()).isEqualTo(CellInfo.TYPE_NR);
-        assertThat(anotherCellIdentityNr.getChannelNumber()).isEqualTo(NRARFCN);
+        assertThat(anotherCellIdentityNr.getNrarfcn()).isEqualTo(NRARFCN);
         assertThat(anotherCellIdentityNr.getPci()).isEqualTo(PCI);
         assertThat(anotherCellIdentityNr.getTac()).isEqualTo(TAC);
         assertThat(anotherCellIdentityNr.getOperatorAlphaLong()).isEqualTo(ALPHAL);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
index 7746bd5..d5f400b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
@@ -386,13 +386,14 @@
         assertTrue(mDataAllowed[0]);
 
         // Set sub 2 as preferred sub should make phone 1 activated and phone 0 deactivated.
-        mPhoneSwitcher.setOpportunisticDataSubscription(2);
+        mPhoneSwitcher.trySetPreferredSubscription(2, false, null);
         waitABit();
         assertFalse(mDataAllowed[0]);
         assertTrue(mDataAllowed[1]);
 
         // Unset preferred sub should make default data sub (phone 0 / sub 1) activated again.
-        mPhoneSwitcher.unsetOpportunisticDataSubscription();
+        mPhoneSwitcher.trySetPreferredSubscription(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+                false, null);
         waitABit();
         assertTrue(mDataAllowed[0]);
         assertFalse(mDataAllowed[1]);
@@ -441,7 +442,7 @@
         assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest(mmsRequest, 1));
 
         // Set sub 2 as preferred sub should make phone 1 preferredDataModem
-        mPhoneSwitcher.setOpportunisticDataSubscription(2);
+        mPhoneSwitcher.trySetPreferredSubscription(2, false, null);
         waitABit();
         verify(mMockRadioConfig).setPreferredDataModem(eq(1), any());
         verify(mActivePhoneSwitchHandler, times(2)).sendMessageAtTime(any(), anyLong());
@@ -454,7 +455,8 @@
         clearInvocations(mActivePhoneSwitchHandler);
 
         // Unset preferred sub should make phone0 preferredDataModem again.
-        mPhoneSwitcher.unsetOpportunisticDataSubscription();
+        mPhoneSwitcher.trySetPreferredSubscription(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+                false, null);
         waitABit();
         verify(mMockRadioConfig).setPreferredDataModem(eq(0), any());
         verify(mActivePhoneSwitchHandler, times(2)).sendMessageAtTime(any(), anyLong());
@@ -640,7 +642,13 @@
         doReturn(mDefaultDataSub).when(mSubscriptionController).getDefaultDataSubId();
         doAnswer(invocation -> {
             int phoneId = (int) invocation.getArguments()[0];
-            return mSlotIndexToSubId[phoneId][0];
+            if (phoneId == SubscriptionManager.INVALID_PHONE_INDEX) {
+                return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+            } else if (phoneId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
+                return mSlotIndexToSubId[0][0];
+            } else {
+                return mSlotIndexToSubId[phoneId][0];
+            }
         }).when(mSubscriptionController).getSubIdUsingPhoneId(anyInt());
 
         doAnswer(invocation -> {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
index 6ad5b8f..2f20579 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
@@ -903,7 +903,8 @@
 
         waitForMs(100);
 
-        sst.registerForDataConnectionAttached(mTestHandler, EVENT_DATA_CONNECTION_ATTACHED, null);
+        sst.registerForDataConnectionAttached(TransportType.WWAN, mTestHandler,
+                EVENT_DATA_CONNECTION_ATTACHED, null);
 
         // set service state in service and trigger events to post message on handler
         mSimulatedCommands.setVoiceRegState(NetworkRegistrationState.REG_STATE_ROAMING);
@@ -925,7 +926,7 @@
         waitForMs(100);
 
         // Unregister registrant
-        sst.unregisterForDataConnectionAttached(mTestHandler);
+        sst.unregisterForDataConnectionAttached(TransportType.WWAN, mTestHandler);
 
         // set service state in service
         mSimulatedCommands.setVoiceRegState(NetworkRegistrationState.REG_STATE_ROAMING);
@@ -949,7 +950,8 @@
 
         waitForMs(100);
 
-        sst.registerForDataConnectionAttached(mTestHandler, EVENT_DATA_CONNECTION_ATTACHED, null);
+        sst.registerForDataConnectionAttached(TransportType.WWAN, mTestHandler,
+                EVENT_DATA_CONNECTION_ATTACHED, null);
 
         // set service state in service and trigger events to post message on handler
         mSimulatedCommands.setVoiceRegState(NetworkRegistrationState.REG_STATE_ROAMING);
@@ -971,7 +973,7 @@
         waitForMs(100);
 
         // Unregister registrant
-        sst.unregisterForDataConnectionAttached(mTestHandler);
+        sst.unregisterForDataConnectionAttached(TransportType.WWAN, mTestHandler);
 
         // set service state in service
         mSimulatedCommands.setVoiceRegState(NetworkRegistrationState.REG_STATE_ROAMING);
@@ -993,7 +995,8 @@
         mSimulatedCommands.setDataRegState(NetworkRegistrationState.REG_STATE_ROAMING);
         mSimulatedCommands.notifyNetworkStateChanged();
 
-        sst.registerForDataConnectionDetached(mTestHandler, EVENT_DATA_CONNECTION_DETACHED, null);
+        sst.registerForDataConnectionDetached(TransportType.WWAN, mTestHandler,
+                EVENT_DATA_CONNECTION_DETACHED, null);
 
         // set service state out of service and trigger events to post message on handler
         mSimulatedCommands.setVoiceRegState(NetworkRegistrationState.REG_STATE_UNKNOWN);
@@ -1015,7 +1018,7 @@
         waitForMs(100);
 
         // Unregister registrant
-        sst.unregisterForDataConnectionDetached(mTestHandler);
+        sst.unregisterForDataConnectionDetached(TransportType.WWAN, mTestHandler);
 
         // set service state out of service
         mSimulatedCommands.setVoiceRegState(NetworkRegistrationState.REG_STATE_UNKNOWN);
@@ -1050,11 +1053,12 @@
     @Test
     @MediumTest
     public void testRegisterForDataRegStateOrRatChange() {
-        int drs = NetworkRegistrationState.REG_STATE_HOME;
+        int drs = ServiceState.STATE_IN_SERVICE;
         int rat = sst.mSS.RIL_RADIO_TECHNOLOGY_LTE;
         sst.mSS.setRilDataRadioTechnology(rat);
         sst.mSS.setDataRegState(drs);
-        sst.registerForDataRegStateOrRatChanged(mTestHandler, EVENT_DATA_RAT_CHANGED, null);
+        sst.registerForDataRegStateOrRatChanged(TransportType.WWAN, mTestHandler,
+                EVENT_DATA_RAT_CHANGED, null);
 
         waitForMs(100);
 
@@ -1062,7 +1066,8 @@
         ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
         verify(mTestHandler).sendMessageAtTime(messageArgumentCaptor.capture(), anyLong());
         assertEquals(EVENT_DATA_RAT_CHANGED, messageArgumentCaptor.getValue().what);
-        assertEquals(new Pair<Integer, Integer>(drs, rat),
+        assertEquals(new Pair<Integer, Integer>(ServiceState.STATE_IN_SERVICE,
+                        ServiceState.RIL_RADIO_TECHNOLOGY_LTE),
                 ((AsyncResult)messageArgumentCaptor.getValue().obj).result);
     }
 
@@ -1423,7 +1428,8 @@
 
         sst.registerForDataRoamingOff(mTestHandler, EVENT_DATA_ROAMING_OFF, null, true);
         sst.registerForVoiceRoamingOff(mTestHandler, EVENT_VOICE_ROAMING_OFF, null);
-        sst.registerForDataConnectionDetached(mTestHandler, EVENT_DATA_CONNECTION_DETACHED, null);
+        sst.registerForDataConnectionDetached(TransportType.WWAN, mTestHandler,
+                EVENT_DATA_CONNECTION_DETACHED, null);
 
         // Call functions which would trigger posting of message on test handler
         doReturn(false).when(mPhone).isPhoneTypeGsm();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java
index 35bab98..576ee33 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java
@@ -15,8 +15,8 @@
  */
 package com.android.internal.telephony;
 
+import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBID_CHANGE;
 import static android.telephony.PhoneStateListener.LISTEN_PHONE_CAPABILITY_CHANGE;
-import static android.telephony.PhoneStateListener.LISTEN_PREFERRED_DATA_SUBID_CHANGE;
 import static android.telephony.PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED;
 
 import static org.junit.Assert.assertEquals;
@@ -44,7 +44,7 @@
     private PhoneStateListener mPhoneStateListener;
     private TelephonyRegistry mTelephonyRegistry;
     private PhoneCapability mPhoneCapability;
-    private int mPreferredSubId;
+    private int mActiveSubId;
     private int mSrvccState = -1;
 
     public class PhoneStateListenerWrapper extends PhoneStateListener {
@@ -60,8 +60,8 @@
             setReady(true);
         }
         @Override
-        public void onPreferredDataSubIdChanged(int preferredSubId) {
-            mPreferredSubId = preferredSubId;
+        public void onActiveDataSubIdChanged(int activeSubId) {
+            mActiveSubId = activeSubId;
             setReady(true);
         }
     }
@@ -121,23 +121,23 @@
 
 
     @Test @SmallTest
-    public void testPreferredDataSubChanged() {
+    public void testActiveDataSubChanged() {
         // mTelephonyRegistry.listen with notifyNow = true should trigger callback immediately.
         setReady(false);
-        int preferredSubId = 0;
-        mTelephonyRegistry.notifyPreferredDataSubIdChanged(preferredSubId);
+        int activeSubId = 0;
+        mTelephonyRegistry.notifyActiveDataSubIdChanged(activeSubId);
         mTelephonyRegistry.listen(mContext.getOpPackageName(),
                 mPhoneStateListener.callback,
-                LISTEN_PREFERRED_DATA_SUBID_CHANGE, true);
+                LISTEN_ACTIVE_DATA_SUBID_CHANGE, true);
         waitUntilReady();
-        assertEquals(preferredSubId, mPreferredSubId);
+        assertEquals(activeSubId, mActiveSubId);
 
         // notifyPhoneCapabilityChanged with a new capability. Callback should be triggered.
         setReady(false);
-        mPreferredSubId = 1;
-        mTelephonyRegistry.notifyPreferredDataSubIdChanged(preferredSubId);
+        mActiveSubId = 1;
+        mTelephonyRegistry.notifyActiveDataSubIdChanged(activeSubId);
         waitUntilReady();
-        assertEquals(preferredSubId, mPreferredSubId);
+        assertEquals(activeSubId, mActiveSubId);
     }
 
     /**
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index a18fb28..2b330db 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -45,6 +45,7 @@
 import android.provider.BlockedNumberContract;
 import android.provider.Settings;
 import android.telephony.AccessNetworkConstants.TransportType;
+import android.telephony.NetworkRegistrationState;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -143,6 +144,8 @@
     @Mock
     protected ServiceState mServiceState;
     @Mock
+    protected NetworkRegistrationState mNetworkRegistrationState;
+    @Mock
     protected SimulatedCommandsVerifier mSimulatedCommandsVerifier;
     @Mock
     protected IDeviceIdleController mIDeviceIdleController;
@@ -491,6 +494,8 @@
         doReturn(TransportType.WWAN).when(mTransportManager).getCurrentTransport(anyInt());
         doReturn(true).when(mDataEnabledSettings).isDataEnabled();
         doReturn(true).when(mDataEnabledSettings).isInternalDataEnabled();
+        doReturn(mNetworkRegistrationState).when(mServiceState).getNetworkRegistrationState(
+                anyInt(), anyInt());
 
         //SIM
         doReturn(1).when(mTelephonyManager).getSimCount();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java
index b4ce3e3..3be4104 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java
@@ -129,6 +129,7 @@
         assertEquals(a1.getMvnoMatchData(), a2.getMvnoMatchData());
         assertEquals(a1.getNetworkTypeBitmask(), a2.getNetworkTypeBitmask());
         assertEquals(a1.getApnSetId(), a2.getApnSetId());
+        assertEquals(a1.getSkip464Xlat(), a2.getSkip464Xlat());
     }
 
     @Test
@@ -229,7 +230,7 @@
         expectedApn = ApnSetting.makeApnSetting(
                 -1, "12345", "Name", "apn", "", -1, null, "", -1, "", "", 0,
                 mmsTypesBitmask, ApnSetting.PROTOCOL_IPV6, ApnSetting.PROTOCOL_IP, true,
-                0, 0, false, 0, 0, 0, 0, ApnSetting.MVNO_TYPE_SPN, "testspn", 3, -1);
+                0, 0, false, 0, 0, 0, 0, ApnSetting.MVNO_TYPE_SPN, "testspn", 3, -1, -1);
         assertApnSettingEqual(expectedApn, ApnSetting.fromString(testString));
 
         // A v6 string with carrierId=100
@@ -239,7 +240,17 @@
         expectedApn = ApnSetting.makeApnSetting(
             -1, "12345", "Name", "apn", "", -1, null, "", -1, "", "", 0,
             mmsTypesBitmask, ApnSetting.PROTOCOL_IPV6, ApnSetting.PROTOCOL_IP, true,
-            0, 0, false, 0, 0, 0, 0, ApnSetting.MVNO_TYPE_SPN, "testspn", 3, 100);
+            0, 0, false, 0, 0, 0, 0, ApnSetting.MVNO_TYPE_SPN, "testspn", 3, 100, -1);
+        assertApnSettingEqual(expectedApn, ApnSetting.fromString(testString));
+
+        // A v7 string with skip_464xlat=1
+        testString =
+            "[ApnSettingV7] Name,apn,,,,,,,,,123,45,,mms|*,IPV6,IP,true,0,,,,,,,spn,testspn,0,3,"
+                + "-1, 1";
+        expectedApn = ApnSetting.makeApnSetting(
+            -1, "12345", "Name", "apn", "", -1, null, "", -1, "", "", 0,
+            mmsTypesBitmask, ApnSetting.PROTOCOL_IPV6, ApnSetting.PROTOCOL_IP, true,
+            0, 0, false, 0, 0, 0, 0, ApnSetting.MVNO_TYPE_SPN, "testspn", 3, -1, 1);
         assertApnSettingEqual(expectedApn, ApnSetting.fromString(testString));
 
         // Return no apn if insufficient fields given.
@@ -279,7 +290,7 @@
         expectedApns.add(ApnSetting.makeApnSetting(
                 -1, "12346", "Name1", "apn2", "", -1, null, "", -1, "", "", 0,
                 mmsTypesBitmask, ApnSetting.PROTOCOL_IPV6, ApnSetting.PROTOCOL_IP, true,
-                0, 0, false, 0, 0, 0, 0, -1, "", 3, -1));
+                0, 0, false, 0, 0, 0, 0, -1, "", 3, -1, -1));
         assertApnSettingsEqual(expectedApns, ApnSetting.arrayFromString(testString));
     }
 
@@ -292,9 +303,9 @@
                 null, null, -1, "user", "password", 0,
                 ApnSetting.TYPE_DEFAULT, ApnSetting.PROTOCOL_IPV6, ApnSetting.PROTOCOL_IP, true,
                 4096, 0, false, 0, 0, 0, 0, ApnSetting.MVNO_TYPE_SPN, "");
-        String expected = "[ApnSettingV6] Name, 99, 12345, apn, null, "
+        String expected = "[ApnSettingV7] Name, 99, 12345, apn, null, "
                 + "null, null, null, 10, 0, hipri | default, "
-                + "IPV6, IP, true, 0, false, 0, 0, 0, 0, spn, , false, 4096, 0, -1";
+                + "IPV6, IP, true, 0, false, 0, 0, 0, 0, spn, , false, 4096, 0, -1, -1";
         assertEquals(expected, apn.toString());
 
         final int networkTypeBitmask = 1 << (14 - 1);
@@ -302,10 +313,10 @@
                 99, "12345", "Name", "apn", null, 10,
                 null, null, -1, "user", "password", 0,
                 ApnSetting.TYPE_DEFAULT, ApnSetting.PROTOCOL_IPV6, ApnSetting.PROTOCOL_IP, true,
-                networkTypeBitmask, 0, false, 0, 0, 0, 0, ApnSetting.MVNO_TYPE_SPN, "", 3, -1);
-        expected = "[ApnSettingV6] Name, 99, 12345, apn, null, "
+                networkTypeBitmask, 0, false, 0, 0, 0, 0, ApnSetting.MVNO_TYPE_SPN, "", 3, -1, 1);
+        expected = "[ApnSettingV7] Name, 99, 12345, apn, null, "
                 + "null, null, null, 10, 0, hipri | default, "
-                + "IPV6, IP, true, 0, false, 0, 0, 0, 0, spn, , false, 8192, 3, -1";
+                + "IPV6, IP, true, 0, false, 0, 0, 0, 0, spn, , false, 8192, 3, -1, 1";
         assertEquals(expected, apn.toString());
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
index 7fd6f35..6289e31 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
@@ -157,6 +157,93 @@
             -1,                     // mvno_type
             "");                    // mnvo_match_data
 
+    private ApnSetting mApn3 = ApnSetting.makeApnSetting(
+            2164,                   // id
+            "44010",                // numeric
+            "sp-mode",              // name
+            "spmode.ne.jp",         // apn
+            null,                   // proxy
+            -1,                     // port
+            null,                   // mmsc
+            null,                   // mmsproxy
+            -1,                     // mmsport
+            "",                     // user
+            "",                     // password
+            -1,                     // authtype
+            ApnSetting.TYPE_DEFAULT, // types
+            ApnSetting.PROTOCOL_IPV6, // protocol
+            ApnSetting.PROTOCOL_IP, // roaming_protocol
+            true,                   // carrier_enabled
+            0,                      // networktype_bitmask
+            0,                      // profile_id
+            false,                  // modem_cognitive
+            0,                      // max_conns
+            0,                      // wait_time
+            0,                      // max_conns_time
+            0,                      // mtu
+            -1,                     // mvno_type
+            "",                     // mnvo_match_data
+            0,                      // apn_set_id
+            -1,                     // carrier_id
+            1);                     // skip_464xlat
+
+    private ApnSetting mApn4 = ApnSetting.makeApnSetting(
+            2164,                   // id
+            "44010",                // numeric
+            "sp-mode",              // name
+            "spmode.ne.jp",         // apn
+            null,                   // proxy
+            -1,                     // port
+            null,                   // mmsc
+            null,                   // mmsproxy
+            -1,                     // mmsport
+            "",                     // user
+            "",                     // password
+            -1,                     // authtype
+            ApnSetting.TYPE_IMS,    // types
+            ApnSetting.PROTOCOL_IPV6, // protocol
+            ApnSetting.PROTOCOL_IP, // roaming_protocol
+            true,                   // carrier_enabled
+            0,                      // networktype_bitmask
+            0,                      // profile_id
+            false,                  // modem_cognitive
+            0,                      // max_conns
+            0,                      // wait_time
+            0,                      // max_conns_time
+            0,                      // mtu
+            -1,                     // mvno_type
+            "");                    // mnvo_match_data
+
+    private ApnSetting mApn5 = ApnSetting.makeApnSetting(
+            2164,                   // id
+            "44010",                // numeric
+            "sp-mode",              // name
+            "spmode.ne.jp",         // apn
+            null,                   // proxy
+            -1,                     // port
+            null,                   // mmsc
+            null,                   // mmsproxy
+            -1,                     // mmsport
+            "",                     // user
+            "",                     // password
+            -1,                     // authtype
+            ApnSetting.TYPE_IMS,    // types
+            ApnSetting.PROTOCOL_IPV6, // protocol
+            ApnSetting.PROTOCOL_IP, // roaming_protocol
+            true,                   // carrier_enabled
+            0,                      // networktype_bitmask
+            0,                      // profile_id
+            false,                  // modem_cognitive
+            0,                      // max_conns
+            0,                      // wait_time
+            0,                      // max_conns_time
+            0,                      // mtu
+            -1,                     // mvno_type
+            "",                     // mnvo_match_data
+            0,                      // apn_set_id
+            -1,                     // carrier_id
+            0);                     // skip_464xlat
+
     private class DataConnectionTestHandler extends HandlerThread {
 
         private DataConnectionTestHandler(String name) {
@@ -510,6 +597,44 @@
     }
 
     @Test
+    public void testShouldSkip464Xlat() throws Exception {
+        assertFalse(testShouldSkip464XlatEvent(mApn1));
+        disconnectEvent();
+
+        assertTrue(testShouldSkip464XlatEvent(mApn3));
+        disconnectEvent();
+
+        assertTrue(testShouldSkip464XlatEvent(mApn4));
+        disconnectEvent();
+
+        assertFalse(testShouldSkip464XlatEvent(mApn5));
+        disconnectEvent();
+    }
+
+    private boolean testShouldSkip464XlatEvent(ApnSetting apn) throws Exception {
+        Method method = DataConnection.class.getDeclaredMethod("shouldSkip464Xlat");
+        method.setAccessible(true);
+
+        doReturn(apn).when(mApnContext).getApnSetting();
+        connectEvent();
+        logd(getNetworkCapabilities().toString());
+
+        return (Boolean) method.invoke(mDc);
+    }
+
+    private void connectEvent() throws Exception {
+        mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp);
+        waitForMs(200);
+        assertEquals("DcActiveState", getCurrentState().getName());
+    }
+
+    private void disconnectEvent() throws Exception {
+        mDc.sendMessage(DataConnection.EVENT_DISCONNECT, mDcp);
+        waitForMs(100);
+        assertEquals("DcInactiveState", getCurrentState().getName());
+    }
+
+    @Test
     @SmallTest
     public void testIsIpAddress() throws Exception {
         // IPv4
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 8d8a080..29fc9fa 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
@@ -61,6 +61,7 @@
 import android.os.PersistableBundle;
 import android.provider.Settings;
 import android.provider.Telephony;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.CarrierConfigManager;
 import android.telephony.ServiceState;
@@ -229,7 +230,8 @@
                                     Telephony.Carriers.MVNO_MATCH_DATA,
                                     Telephony.Carriers.NETWORK_TYPE_BITMASK,
                                     Telephony.Carriers.APN_SET_ID,
-                                    Telephony.Carriers.CARRIER_ID});
+                                    Telephony.Carriers.CARRIER_ID,
+                                    Telephony.Carriers.SKIP_464XLAT});
 
                     mc.addRow(new Object[]{
                             2163,                   // id
@@ -260,7 +262,8 @@
                             "",                     // mnvo_match_data
                             NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask
                             0,                      // apn_set_id
-                            -1                      // carrier_id
+                            -1,                     // carrier_id
+                            -1                      // skip_464xlat
                     });
 
                     mc.addRow(new Object[]{
@@ -292,7 +295,8 @@
                             "",                     // mnvo_match_data
                             NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask
                             0,                      // apn_set_id
-                            -1                      // carrier_id
+                            -1,                     // carrier_id
+                            -1                      // skip_464xlat
                     });
 
                     mc.addRow(new Object[]{
@@ -324,7 +328,8 @@
                             "",                     // mnvo_match_data
                             0,                      // network_type_bitmask
                             0,                      // apn_set_id
-                            -1                      // carrier_id
+                            -1,                     // carrier_id
+                            -1                      // skip_464xlat
                     });
 
                     mc.addRow(new Object[]{
@@ -356,7 +361,8 @@
                             "",                     // mnvo_match_data
                             NETWORK_TYPE_EHRPD_BITMASK, // network_type_bitmask
                             0,                      // apn_set_id
-                            -1                      // carrier_id
+                            -1,                     // carrier_id
+                            -1                      // skip_464xlat
                     });
 
                     mc.addRow(new Object[]{
@@ -388,7 +394,8 @@
                             "",                     // mnvo_match_data
                             0,                      // network_type_bitmask
                             0,                      // apn_set_id
-                            -1                      // carrier_id
+                            -1,                     // carrier_id
+                            -1                      // skip_464xlat
                     });
 
                     return mc;
@@ -422,6 +429,8 @@
         doReturn("fake.action_attached").when(mPhone).getActionAttached();
         doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_LTE).when(mServiceState)
                 .getRilDataRadioTechnology();
+        doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mNetworkRegistrationState)
+                .getAccessNetworkTechnology();
 
         mContextFixture.putStringArrayResource(com.android.internal.R.array.networkAttributes,
                 sNetworkAttributes);
@@ -443,6 +452,8 @@
 
         ((MockContentResolver) mContext.getContentResolver()).addProvider(
                 Telephony.Carriers.CONTENT_URI.getAuthority(), mApnSettingContentProvider);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 0);
 
         doReturn(true).when(mSimRecords).getRecordsLoaded();
         doReturn(PhoneConstants.State.IDLE).when(mCT).getState();
@@ -592,8 +603,7 @@
         ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
         // Verify if RIL command was sent properly.
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
-                eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
-                        mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+                eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
@@ -641,8 +651,7 @@
         ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
         // Verify if RIL command was sent properly.
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
-                eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
-                        mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+                eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
@@ -666,8 +675,7 @@
         dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
         // Verify if RIL command was sent properly.
         verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
-                eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
-                        mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+                eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN2, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
@@ -698,8 +706,7 @@
 
         ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
         verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
-                eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
-                        mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+                eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, NETWORK_TYPE_LTE_BITMASK);
@@ -752,8 +759,7 @@
 
         ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
         verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
-                eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
-                        mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+                eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
@@ -808,8 +814,7 @@
         waitForMs(200);
         ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
-                eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
-                        mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+                eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN3, 2, 64, 0, 0);
@@ -859,7 +864,7 @@
         mDct.sendMessage(mDct.obtainMessage(intArgumentCaptor.getValue(), null));
         waitForMs(100);
 
-        verify(mSST, times(1)).registerForDataConnectionAttached(eq(mDct),
+        verify(mSST, times(1)).registerForDataConnectionAttached(eq(TransportType.WWAN), eq(mDct),
                 intArgumentCaptor.capture(), eq(null));
         // Ideally this should send EVENT_DATA_CONNECTION_ATTACHED");
         mDct.sendMessage(mDct.obtainMessage(intArgumentCaptor.getValue(), null));
@@ -878,7 +883,7 @@
         // The auto attach flag should be reset after update
         assertFalse(mDct.getAutoAttachOnCreation());
 
-        verify(mSST, times(1)).registerForDataConnectionDetached(eq(mDct),
+        verify(mSST, times(1)).registerForDataConnectionDetached(eq(TransportType.WWAN), eq(mDct),
                 intArgumentCaptor.capture(), eq(null));
         // Ideally this should send EVENT_DATA_CONNECTION_DETACHED
         mDct.sendMessage(mDct.obtainMessage(intArgumentCaptor.getValue(), null));
@@ -916,8 +921,7 @@
 
         ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
         verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
-                eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
-                        mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+                eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, NETWORK_TYPE_LTE_BITMASK);
@@ -959,8 +963,7 @@
         waitForMs(200);
 
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
-                eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
-                        mServiceState.getRilDataRadioTechnology())), any(DataProfile.class),
+                eq(AccessNetworkType.EUTRAN), any(DataProfile.class),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
     }
@@ -1013,8 +1016,7 @@
         waitForMs(200);
 
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
-                eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
-                        mServiceState.getRilDataRadioTechnology())), any(DataProfile.class),
+                eq(AccessNetworkType.EUTRAN), any(DataProfile.class),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
     }
@@ -1135,8 +1137,8 @@
     @SmallTest
     public void testTrySetupDefaultOnIWLAN() throws Exception {
         initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
-        doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN).when(mServiceState)
-                .getRilDataRadioTechnology();
+        doReturn(TelephonyManager.NETWORK_TYPE_IWLAN).when(mNetworkRegistrationState)
+                .getAccessNetworkTechnology();
 
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT});
@@ -1188,8 +1190,8 @@
     @Test
     @SmallTest
     public void testUpdateWaitingApnListOnDataRatChange() throws Exception {
-        doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD).when(mServiceState)
-                .getRilDataRadioTechnology();
+        doReturn(TelephonyManager.NETWORK_TYPE_EHRPD).when(mNetworkRegistrationState)
+                .getAccessNetworkTechnology();
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT});
         mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
@@ -1206,8 +1208,7 @@
         ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
         // Verify if RIL command was sent properly.
         verify(mSimulatedCommandsVerifier).setupDataCall(
-                eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
-                        mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+                eq(AccessNetworkType.CDMA2000), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN4, 0, 21, 2, NETWORK_TYPE_EHRPD_BITMASK);
@@ -1215,8 +1216,8 @@
 
         //data rat change from ehrpd to lte
         logd("Sending EVENT_DATA_RAT_CHANGED");
-        doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_LTE).when(mServiceState)
-                .getRilDataRadioTechnology();
+        doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mNetworkRegistrationState)
+                .getAccessNetworkTechnology();
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null));
         waitForMs(200);
 
@@ -1239,8 +1240,7 @@
 
         // Verify if RIL command was sent properly.
         verify(mSimulatedCommandsVerifier).setupDataCall(
-                eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
-                        mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+                eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
@@ -1308,8 +1308,8 @@
     @Test
     @SmallTest
     public void testDataRatChangeOOS() throws Exception {
-        doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD).when(mServiceState)
-                .getRilDataRadioTechnology();
+        doReturn(TelephonyManager.NETWORK_TYPE_EHRPD).when(mNetworkRegistrationState)
+                .getAccessNetworkTechnology();
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT});
         mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
@@ -1326,8 +1326,7 @@
         ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
         // Verify if RIL command was sent properly.
         verify(mSimulatedCommandsVerifier).setupDataCall(
-                eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
-                        mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+                eq(AccessNetworkType.CDMA2000), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN4, 0, 21, 2, NETWORK_TYPE_EHRPD_BITMASK);
@@ -1335,8 +1334,8 @@
 
         // Data rat change from ehrpd to unknown due to OOS
         logd("Sending EVENT_DATA_RAT_CHANGED");
-        doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN).when(mServiceState)
-                .getRilDataRadioTechnology();
+        doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN).when(mNetworkRegistrationState)
+                .getAccessNetworkTechnology();
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null));
         waitForMs(200);
 
@@ -1346,8 +1345,8 @@
                 any(Message.class));
 
         // Data rat resume from unknown to ehrpd
-        doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD).when(mServiceState)
-                .getRilDataRadioTechnology();
+        doReturn(TelephonyManager.NETWORK_TYPE_EHRPD).when(mNetworkRegistrationState)
+                .getAccessNetworkTechnology();
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null));
         waitForMs(200);
 
@@ -1434,9 +1433,6 @@
     @Test
     @SmallTest
     public void testNetworkStatusChangedRecoveryOFF() throws Exception {
-        ContentResolver resolver = mContext.getContentResolver();
-        Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 0);
-
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
         mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null);
@@ -1452,8 +1448,7 @@
 
         ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
         verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
-                eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
-                mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+                eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
@@ -1494,8 +1489,7 @@
 
         ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
         verify(mSimulatedCommandsVerifier, timeout(TEST_TIMEOUT).times(2)).setupDataCall(
-                eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
-                mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+                eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
@@ -1511,10 +1505,6 @@
         waitForMs(200);
 
         verify(mSimulatedCommandsVerifier, times(1)).getDataCallList(any(Message.class));
-
-        // reset the setting at the end of this test
-        Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 0);
-        waitForMs(200);
     }
 
     @FlakyTest
@@ -1541,8 +1531,7 @@
 
         ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
         verify(mSimulatedCommandsVerifier, timeout(TEST_TIMEOUT).times(2)).setupDataCall(
-                eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
-                mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+                eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
@@ -1556,10 +1545,6 @@
         verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall(
                 eq(DataService.REQUEST_REASON_NORMAL), anyInt(),
                 any(Message.class));
-
-        // reset the setting at the end of this test
-        Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 0);
-        waitForMs(200);
     }
 
 
@@ -1586,8 +1571,7 @@
 
         ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
-                eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
-                mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+                eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
@@ -1599,9 +1583,6 @@
 
         // expected to get preferred network type
         verify(mSST, times(1)).reRegisterNetwork(eq(null));
-
-        // reset the setting at the end of this test
-        Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 0);
     }
 
     @Test
@@ -1627,8 +1608,7 @@
 
         ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
-                eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
-                mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+                eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
                 any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
@@ -1640,9 +1620,6 @@
 
         // expected to get preferred network type
         verify(mSST, times(1)).powerOffRadioSafely();
-
-        // reset the setting at the end of this test
-        Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 0);
     }
 
     private void verifyDataEnabledChangedMessage(boolean enabled, int reason) {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsManagerTest.java
index ab0d061..294c5bb 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsManagerTest.java
@@ -34,7 +34,9 @@
 import android.telephony.ims.ImsMmTelManager;
 import android.telephony.ims.ProvisioningManager;
 import android.telephony.ims.stub.ImsConfigImplBase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.ims.ImsConfig;
 import com.android.ims.ImsManager;
@@ -44,10 +46,12 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
 
 import java.util.Hashtable;
 
+@RunWith(AndroidJUnit4.class)
 public class ImsManagerTest extends TelephonyTest {
     private static final String UNSET_PROVISIONED_STRING = "unset";
     private static final boolean ENHANCED_4G_MODE_DEFAULT_VAL = true;
@@ -57,10 +61,14 @@
     private static final boolean VT_IMS_ENABLE_DEFAULT_VAL = true;
     private static final boolean WFC_IMS_EDITABLE_VAL = true;
     private static final boolean WFC_IMS_NOT_EDITABLE_VAL = false;
+    private static final boolean WFC_IMS_ROAMING_EDITABLE_VAL = true;
+    private static final boolean WFC_IMS_ROAMING_NOT_EDITABLE_VAL = false;
     private static final int WFC_IMS_MODE_DEFAULT_VAL =
             ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED;
     private static final int WFC_IMS_ROAMING_MODE_DEFAULT_VAL =
             ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED;
+    private static final boolean WFC_USE_HOME_MODE_FOR_ROAMING_VAL = true;
+    private static final boolean WFC_NOT_USE_HOME_MODE_FOR_ROAMING_VAL = false;
 
     PersistableBundle mBundle;
     @Mock IBinder mBinder;
@@ -78,6 +86,8 @@
         super.setUp("ImsManagerTest");
         mPhoneId = mPhone.getPhoneId();
         mBundle = mContextFixture.getCarrierConfigBundle();
+        // Force MmTelFeatureConnection to create an executor using Looper.myLooper().
+        doReturn(null).when(mContext).getMainLooper();
 
         doReturn(mSubId).when(mSubscriptionController).getSubId(mPhoneId);
 
@@ -101,6 +111,8 @@
                 ENHANCED_4G_MODE_EDITABLE);
         mBundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL,
                 WFC_IMS_EDITABLE_VAL);
+        mBundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL,
+                WFC_IMS_ROAMING_EDITABLE_VAL);
         mBundle.putBoolean(CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL,
                 WFC_IMS_ENABLE_DEFAULT_VAL);
         mBundle.putBoolean(CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL,
@@ -112,6 +124,9 @@
         mBundle.putBoolean(CarrierConfigManager.KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL,
                 ENHANCED_4G_MODE_DEFAULT_VAL);
         mBundle.putBoolean(CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, true);
+        mBundle.putBoolean(
+                CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL,
+                WFC_NOT_USE_HOME_MODE_FOR_ROAMING_VAL);
     }
 
     @Test @SmallTest
@@ -647,6 +662,98 @@
                 eq(WFC_IMS_MODE_DEFAULT_VAL));
     }
 
+    /**
+     * Tests the operation of getWfcMode when the configuration to use the home network mode when
+     * roaming for WFC is false. First, it checks that the user setting for WFC_IMS_ROAMING_MODE is
+     * returned when WFC roaming is set to editable. Then, it switches the WFC roaming mode to not
+     * editable and ensures that the default WFC roaming mode is returned.
+     *
+     * Preconditions:
+     *  - CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL = false
+     */
+    @Test @SmallTest
+    public void getWfcMode_useWfcHomeModeConfigFalse_shouldUseWfcRoamingMode() {
+        // Set some values that are different than the defaults for WFC mode.
+        doReturn(String.valueOf(ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY))
+                .when(mSubscriptionController).getSubscriptionProperty(
+                anyInt(),
+                eq(SubscriptionManager.WFC_IMS_MODE),
+                anyString());
+        doReturn(String.valueOf(ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED))
+                .when(mSubscriptionController).getSubscriptionProperty(
+                anyInt(),
+                eq(SubscriptionManager.WFC_IMS_ROAMING_MODE),
+                anyString());
+
+        ImsManager imsManager = getImsManagerAndInitProvisionedValues();
+
+        // Check that use the WFC roaming network mode.
+        assertEquals(ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED,
+                imsManager.getWfcMode(true));
+        verify(mSubscriptionController, times(1)).getSubscriptionProperty(
+                anyInt(),
+                eq(SubscriptionManager.WFC_IMS_ROAMING_MODE),
+                anyString());
+
+        // Set WFC roaming network mode to not editable.
+        mBundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL,
+                WFC_IMS_ROAMING_NOT_EDITABLE_VAL);
+
+        // Check that use the default WFC roaming network mode.
+        assertEquals(WFC_IMS_ROAMING_MODE_DEFAULT_VAL, imsManager.getWfcMode(true));
+        verify(mSubscriptionController, times(1)).getSubscriptionProperty(
+                anyInt(),
+                eq(SubscriptionManager.WFC_IMS_ROAMING_MODE),
+                anyString());
+    }
+
+    /**
+     * Tests the operation of getWfcMode when the configuration to use the home network mode when
+     * roaming for WFC is true independent of whether or not the WFC roaming mode is editable.
+     *
+     * Preconditions:
+     *  - CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL = true
+     */
+    @Test @SmallTest
+    public void getWfcMode_useWfcHomeModeConfigTrue_shouldUseWfcHomeMode() {
+        // Set some values that are different than the defaults for WFC mode.
+        doReturn(String.valueOf(ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY))
+                .when(mSubscriptionController).getSubscriptionProperty(
+                anyInt(),
+                eq(SubscriptionManager.WFC_IMS_MODE),
+                anyString());
+        doReturn(String.valueOf(ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED))
+                .when(mSubscriptionController).getSubscriptionProperty(
+                anyInt(),
+                eq(SubscriptionManager.WFC_IMS_ROAMING_MODE),
+                anyString());
+
+        // Set to use WFC home network mode in roaming network.
+        mBundle.putBoolean(
+                CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL,
+                WFC_USE_HOME_MODE_FOR_ROAMING_VAL);
+
+        ImsManager imsManager = getImsManagerAndInitProvisionedValues();
+
+        // Check that use the WFC home network mode.
+        assertEquals(ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY, imsManager.getWfcMode(true));
+        verify(mSubscriptionController, times(1)).getSubscriptionProperty(
+                anyInt(),
+                eq(SubscriptionManager.WFC_IMS_MODE),
+                anyString());
+
+        // Set WFC home network mode to not editable.
+        mBundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL,
+                WFC_IMS_NOT_EDITABLE_VAL);
+
+        // Check that use the default WFC home network mode.
+        assertEquals(WFC_IMS_MODE_DEFAULT_VAL, imsManager.getWfcMode(true));
+        verify(mSubscriptionController, times(1)).getSubscriptionProperty(
+                anyInt(),
+                eq(SubscriptionManager.WFC_IMS_MODE),
+                anyString());
+    }
+
     private ImsManager getImsManagerAndInitProvisionedValues() {
         when(mImsConfigImplBaseMock.getConfigInt(anyInt()))
                 .thenAnswer(invocation ->  {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/RcsMessageStoreControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/RcsMessageStoreControllerTest.java
index 25cfb20..39ec048 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/RcsMessageStoreControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/RcsMessageStoreControllerTest.java
@@ -65,7 +65,7 @@
         mContentResolver = (MockContentResolver) mContext.getContentResolver();
         mContentResolver.addProvider("rcs", mFakeRcsProvider);
 
-        mRcsMessageStoreController = new RcsMessageStoreController(mContentResolver, null);
+        mRcsMessageStoreController = new RcsMessageStoreController(mContentResolver);
     }
 
     @After
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
index e8a002c..d1a33a0 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
@@ -110,7 +110,7 @@
         }
         @Override
         public void onLooperPrepared() {
-            mCTUT = new ImsPhoneCallTracker(mImsPhone);
+            mCTUT = new ImsPhoneCallTracker(mImsPhone, Runnable::run);
             mCTUT.addReasonCodeRemapping(null, "Wifi signal lost.", ImsReasonInfo.CODE_WIFI_LOST);
             mCTUT.addReasonCodeRemapping(501, "Call answered elsewhere.",
                     ImsReasonInfo.CODE_ANSWERED_ELSEWHERE);
@@ -272,7 +272,7 @@
     @SmallTest
     public void testImsDeregistered() {
         // when IMS is deregistered
-        mRegistrationCallback.onDeregistered(new ImsReasonInfo());
+        mRegistrationCallback.onUnregistered(new ImsReasonInfo());
         // then service state should be OUT_OF_SERVICE and ImsPhone state set to not registered
         verify(mImsPhone).setServiceState(eq(ServiceState.STATE_OUT_OF_SERVICE));
         verify(mImsPhone).setImsRegistered(eq(false));
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
index 2555488..6432d05 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
@@ -285,7 +285,7 @@
         mImsPhoneUT.dispose();
         assertEquals(0, list.size());
         verify(mImsCT).dispose();
-        verify(mSST).unregisterForDataRegStateOrRatChanged(mImsPhoneUT);
+        verify(mSST, times(2)).unregisterForDataRegStateOrRatChanged(anyInt(), eq(mImsPhoneUT));
     }
 
     @Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
index 984b583..412cc1b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
@@ -427,12 +427,12 @@
     }
 
     @Override
-    public void notifyRadioPowerStateChanged(int state) {
+    public void notifyActiveDataSubIdChanged(int subId) {
         throw new RuntimeException("Not implemented");
     }
 
     @Override
-    public void notifyPreferredDataSubIdChanged(int subId) {
+    public void notifyRadioPowerStateChanged(int state) {
         throw new RuntimeException("Not implemented");
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java
index c95b91a..7cb6d78 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java
@@ -109,8 +109,9 @@
                 mIccCardStatus.mImsSubscriptionAppIndex =
                         mIccCardStatus.mGsmUmtsSubscriptionAppIndex = -1;
         mSimulatedCommands.setIccCardStatus(mIccCardStatus);
-        // slotIndex should be invalid when testing with older versions (before 1.2) of hal
-        mIccCardStatus.physicalSlotIndex = UiccController.INVALID_SLOT_ID;
+        // for testing we pretend slotIndex is set. In reality it would be invalid on older versions
+        // (before 1.2) of hal
+        mIccCardStatus.physicalSlotIndex = 0;
         mUiccControllerHandlerThread = new UiccControllerHandlerThread(TAG);
         mUiccControllerHandlerThread.start();
         waitUntilReady();
@@ -235,6 +236,7 @@
         ics.atr = "abcdef0123456789abcdef";
         ics.iccid = "123451234567890";
         ics.eid = "A1B2C3D4";
+        ics.physicalSlotIndex = 0;
         AsyncResult ar = new AsyncResult(null, ics, null);
         Message msg = Message.obtain(mUiccControllerUT, EVENT_GET_ICC_STATUS_DONE, ar);
         mUiccControllerUT.handleMessage(msg);
@@ -325,6 +327,7 @@
         ics.setUniversalPinState(3 /* disabled */);
         ics.atr = "abcdef0123456789abcdef";
         ics.iccid = "123451234567890";
+        ics.physicalSlotIndex = 0;
         AsyncResult ar = new AsyncResult(null, ics, null);
         Message msg = Message.obtain(mUiccControllerUT, EVENT_GET_ICC_STATUS_DONE, ar);
         mUiccControllerUT.handleMessage(msg);