Merge "Gate default with explicit flag" into main
diff --git a/flags/data.aconfig b/flags/data.aconfig
index e65f8e4..152660b 100644
--- a/flags/data.aconfig
+++ b/flags/data.aconfig
@@ -1,6 +1,20 @@
 package: "com.android.internal.telephony.flags"
 
 flag {
+  name: "auto_switch_allow_roaming"
+  namespace: "telephony"
+  description: "Allow using roaming network as target if user allows it from settings."
+  bug: "306488039"
+}
+
+flag {
+  name: "auto_data_switch_rat_ss"
+  namespace: "telephony"
+  description: "Whether switch for better rat and signal strength"
+  bug:"260928808"
+}
+
+flag {
   name: "use_alarm_callback"
   namespace: "telephony"
   description: "Use alarm callback instead of broadcast."
@@ -69,4 +83,3 @@
   description: "notify data activity changed for slot id"
   bug: "309896936"
 }
-
diff --git a/flags/ims.aconfig b/flags/ims.aconfig
index 0fa1f1e..94c933c 100644
--- a/flags/ims.aconfig
+++ b/flags/ims.aconfig
@@ -27,3 +27,10 @@
     description: "This flag is created to prevent unnecessary updates when multiple provisioning items to update ims service are changed."
     bug:"302281114"
 }
+
+flag {
+    name: "add_rat_related_suggested_action_to_ims_registration"
+    namespace: "telephony"
+    description: "This flag is for adding suggested actions related to RAT to ims registration"
+    bug:"290573256"
+}
diff --git a/flags/misc.aconfig b/flags/misc.aconfig
index 159d462..c7140f5 100644
--- a/flags/misc.aconfig
+++ b/flags/misc.aconfig
@@ -63,3 +63,10 @@
   description: "Enable Telephony Analytics information of Service State , Sms and Call scenarios"
   bug: "309896524"
 }
+
+flag {
+  name: "show_call_id_and_call_waiting_in_additional_settings_menu"
+  namespace: "telephony"
+  description: "Expose carrier config KEY_ADDITIONAL_SETTINGS_CALLER_ID_VISIBILITY_BOOL and KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL."
+  bug: "310264981"
+}
diff --git a/flags/network.aconfig b/flags/network.aconfig
index 299a2a0..27489f4 100644
--- a/flags/network.aconfig
+++ b/flags/network.aconfig
@@ -13,3 +13,10 @@
   description: "Allow carriers to hide the roaming (R) icon when roaming."
   bug: "301467052"
 }
+
+flag {
+  name: "enable_identifier_disclosure_transparency"
+  namespace: "telephony"
+  description: "Allows the framework to register for CellularIdentifierDisclosure events and emit notifications to the user about them"
+  bug: "276752426"
+}
diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java
index 3f3d297..b33b732 100644
--- a/src/java/com/android/internal/telephony/BaseCommands.java
+++ b/src/java/com/android/internal/telephony/BaseCommands.java
@@ -119,6 +119,7 @@
     protected RegistrantList mNotifyAnbrRegistrants = new RegistrantList();
     protected RegistrantList mTriggerImsDeregistrationRegistrants = new RegistrantList();
     protected RegistrantList mImeiInfoRegistrants = new RegistrantList();
+    protected RegistrantList mCellularIdentifierDisclosedRegistrants = new RegistrantList();
 
     @UnsupportedAppUsage
     protected Registrant mGsmSmsRegistrant;
@@ -1183,4 +1184,14 @@
     public void registerForImeiMappingChanged(Handler h, int what, Object obj) {
         mImeiInfoRegistrants.add(h, what, obj);
     }
+
+    @Override
+    public void registerForCellularIdentifierDisclosures(Handler h, int what, Object obj) {
+        mCellularIdentifierDisclosedRegistrants.add(h, what, obj);
+    }
+
+    @Override
+    public void unregisterForCellularIdentifierDisclosures(Handler h) {
+        mCellularIdentifierDisclosedRegistrants.remove(h);
+    }
 }
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index 6b40040..91e6fab 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -2927,4 +2927,17 @@
      * @param result Callback message to receive the result.
      */
     default void isSecurityAlgorithmsUpdatedEnabled(Message result) {}
+
+    /**
+     * Registers for cellular identifier disclosure events.
+     */
+    default void registerForCellularIdentifierDisclosures(
+            @NonNull Handler h, int what, @Nullable Object obj) {}
+
+    /**
+     * Unregisters for cellular identifier disclosure events.
+     *
+     * @param h Handler to be removed from the registrant list.
+     */
+    default void unregisterForCellularIdentifierDisclosures(@NonNull Handler h) {}
 }
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index d912187..3ef7164 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -80,6 +80,7 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.CellBroadcastIdRange;
 import android.telephony.CellIdentity;
+import android.telephony.CellularIdentifierDisclosure;
 import android.telephony.ImsiEncryptionInfo;
 import android.telephony.LinkCapacityEstimate;
 import android.telephony.NetworkScanRequest;
@@ -116,6 +117,7 @@
 import com.android.internal.telephony.imsphone.ImsPhoneMmiCode;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.telephony.metrics.VoiceCallSessionStats;
+import com.android.internal.telephony.security.CellularIdentifierDisclosureNotifier;
 import com.android.internal.telephony.subscription.SubscriptionInfoInternal;
 import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionManagerServiceCallback;
 import com.android.internal.telephony.test.SimulatedRadioControl;
@@ -298,6 +300,8 @@
     private final SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionsChangedListener;
     private final CallWaitingController mCallWaitingController;
 
+    private CellularIdentifierDisclosureNotifier mIdentifierDisclosureNotifier;
+
     // Set via Carrier Config
     private boolean mIsN1ModeAllowedByCarrier = true;
     // Set via a call to the method on Phone; the only caller is IMS, and all of this code will
@@ -515,6 +519,20 @@
         mCIM = new CarrierInfoManager();
 
         mCi.registerForImeiMappingChanged(this, EVENT_IMEI_MAPPING_CHANGED, null);
+
+        if (mFeatureFlags.enableIdentifierDisclosureTransparency()) {
+            logi(
+                    "enable_identifier_disclosure_transparency is on. Registering for cellular "
+                            + "identifier disclosures from phone "
+                            + getPhoneId());
+            mIdentifierDisclosureNotifier =
+                    mTelephonyComponentFactory
+                            .inject(CellularIdentifierDisclosureNotifier.class.getName())
+                            .makeIdentifierDisclosureNotifier();
+            mCi.registerForCellularIdentifierDisclosures(
+                    this, EVENT_CELL_IDENTIFIER_DISCLOSURE, null);
+        }
+
         initializeCarrierApps();
     }
 
@@ -3663,6 +3681,26 @@
                 parseImeiInfo(msg);
                 break;
 
+            case EVENT_CELL_IDENTIFIER_DISCLOSURE:
+                logd("EVENT_CELL_IDENTIFIER_DISCLOSURE phoneId = " + getPhoneId());
+
+                ar = (AsyncResult) msg.obj;
+                if (ar == null || ar.result == null || ar.exception != null) {
+                    Rlog.e(
+                            LOG_TAG,
+                            "Failed to process cellular identifier disclosure",
+                            ar.exception);
+                    break;
+                }
+
+                CellularIdentifierDisclosure disclosure = (CellularIdentifierDisclosure) ar.result;
+                if (mFeatureFlags.enableIdentifierDisclosureTransparency()
+                        && mIdentifierDisclosureNotifier != null
+                        && disclosure != null) {
+                    mIdentifierDisclosureNotifier.addDisclosure(disclosure);
+                }
+                break;
+
             default:
                 super.handleMessage(msg);
         }
diff --git a/src/java/com/android/internal/telephony/NetworkIndication.java b/src/java/com/android/internal/telephony/NetworkIndication.java
index 3f345e0..d86c090 100644
--- a/src/java/com/android/internal/telephony/NetworkIndication.java
+++ b/src/java/com/android/internal/telephony/NetworkIndication.java
@@ -44,6 +44,7 @@
 import android.telephony.BarringInfo;
 import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
+import android.telephony.CellularIdentifierDisclosure;
 import android.telephony.EmergencyRegResult;
 import android.telephony.LinkCapacityEstimate;
 import android.telephony.NetworkRegistrationInfo;
@@ -436,7 +437,11 @@
             mRil.unsljLogRet(RIL_UNSOL_CELLULAR_IDENTIFIER_DISCLOSED, identifierDisclsoure);
         }
 
-        // TODO (b/276752426) notify registrants of identifier disclosure
+        CellularIdentifierDisclosure disclosure =
+                RILUtils.convertCellularIdentifierDisclosure(identifierDisclsoure);
+
+        mRil.mCellularIdentifierDisclosedRegistrants.notifyRegistrants(
+                new AsyncResult(null, disclosure, null));
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index b991b8e..cc1d4a4 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -254,7 +254,8 @@
     protected static final int EVENT_GET_N1_MODE_ENABLED_DONE = 69;
     protected static final int EVENT_SET_N1_MODE_ENABLED_DONE = 70;
     protected static final int EVENT_IMEI_MAPPING_CHANGED = 71;
-    protected static final int EVENT_LAST = EVENT_IMEI_MAPPING_CHANGED;
+    protected static final int EVENT_CELL_IDENTIFIER_DISCLOSURE = 72;
+    protected static final int EVENT_LAST = EVENT_CELL_IDENTIFIER_DISCLOSURE;
 
     // For shared prefs.
     private static final String GSM_ROAMING_LIST_OVERRIDE_PREFIX = "gsm_roaming_list_";
diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java
index 3560048..0cbc035 100644
--- a/src/java/com/android/internal/telephony/PhoneFactory.java
+++ b/src/java/com/android/internal/telephony/PhoneFactory.java
@@ -265,7 +265,8 @@
 
                 sPhoneSwitcher = TelephonyComponentFactory.getInstance().inject(
                         PhoneSwitcher.class.getName()).
-                        makePhoneSwitcher(maxActivePhones, sContext, Looper.myLooper());
+                        makePhoneSwitcher(maxActivePhones, sContext, Looper.myLooper(),
+                                featureFlags);
 
                 sProxyController = ProxyController.getInstance(context);
 
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 998d572..e608e4d 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -5087,7 +5087,7 @@
     public void setCellularIdentifierTransparencyEnabled(boolean enable, Message result) {
         RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class);
         if (!canMakeRequest(
-                "setCellularIdentifierDisclosedEnabled",
+                "setCellularIdentifierTransparencyEnabled",
                 networkProxy,
                 result,
                 RADIO_HAL_VERSION_2_2)) {
@@ -5103,9 +5103,12 @@
         }
 
         radioServiceInvokeHelper(
-            HAL_SERVICE_NETWORK, rr, "setCellularIdentifierDisclosedEnabled", () -> {
-              networkProxy.setCellularIdentifierTransparencyEnabled(rr.mSerial, enable);
-        });
+                HAL_SERVICE_NETWORK,
+                rr,
+                "setCellularIdentifierTransparencyEnabled",
+                () -> {
+                    networkProxy.setCellularIdentifierTransparencyEnabled(rr.mSerial, enable);
+                });
     }
 
     /**
@@ -5115,7 +5118,7 @@
     public void isCellularIdentifierTransparencyEnabled(Message result) {
         RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class);
         if (!canMakeRequest(
-                "isCellularIdentifierDisclosedEnabled",
+                "isCellularIdentifierTransparencyEnabled",
                 networkProxy,
                 result,
                 RADIO_HAL_VERSION_2_2)) {
@@ -5130,9 +5133,12 @@
         }
 
         radioServiceInvokeHelper(
-            HAL_SERVICE_NETWORK, rr, "isCellularIdentifierDisclosedEnabled", () -> {
-              networkProxy.isCellularIdentifierTransparencyEnabled(rr.mSerial);
-        });
+                HAL_SERVICE_NETWORK,
+                rr,
+                "isCellularIdentifierTransparencyEnabled",
+                () -> {
+                    networkProxy.isCellularIdentifierTransparencyEnabled(rr.mSerial);
+                });
     }
 
    /**
diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java
index cb5684f..94f2e96 100644
--- a/src/java/com/android/internal/telephony/RILUtils.java
+++ b/src/java/com/android/internal/telephony/RILUtils.java
@@ -323,6 +323,7 @@
 import android.telephony.CellSignalStrengthNr;
 import android.telephony.CellSignalStrengthTdscdma;
 import android.telephony.CellSignalStrengthWcdma;
+import android.telephony.CellularIdentifierDisclosure;
 import android.telephony.ClosedSubscriberGroupInfo;
 import android.telephony.DomainSelectionService;
 import android.telephony.EmergencyRegResult;
@@ -5675,6 +5676,20 @@
         }
     }
 
+    /** Convert an AIDL-based CellularIdentifierDisclosure to its Java wrapper. */
+    public static CellularIdentifierDisclosure convertCellularIdentifierDisclosure(
+            android.hardware.radio.network.CellularIdentifierDisclosure identifierDisclsoure) {
+        if (identifierDisclsoure == null) {
+            return null;
+        }
+
+        return new CellularIdentifierDisclosure(
+                identifierDisclsoure.protocolMessage,
+                identifierDisclsoure.identifier,
+                identifierDisclsoure.plmn,
+                identifierDisclsoure.isEmergency);
+    }
+
     private static void logd(String log) {
         Rlog.d("RILUtils", log);
     }
diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
index 74d1786..74094a3 100644
--- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
+++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
@@ -47,6 +47,7 @@
 import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
 import com.android.internal.telephony.nitz.NitzStateMachineImpl;
+import com.android.internal.telephony.security.CellularIdentifierDisclosureNotifier;
 import com.android.internal.telephony.uicc.IccCardStatus;
 import com.android.internal.telephony.uicc.UiccCard;
 import com.android.internal.telephony.uicc.UiccProfile;
@@ -480,8 +481,8 @@
     }
 
     public PhoneSwitcher makePhoneSwitcher(int maxDataAttachModemCount, Context context,
-            Looper looper) {
-        return PhoneSwitcher.make(maxDataAttachModemCount, context, looper);
+            Looper looper, @NonNull FeatureFlags featureFlags) {
+        return PhoneSwitcher.make(maxDataAttachModemCount, context, looper, featureFlags);
     }
 
     /**
@@ -565,4 +566,9 @@
             @NonNull DataSettingsManager.DataSettingsManagerCallback callback) {
         return new DataSettingsManager(phone, dataNetworkController, looper, callback);
     }
+
+    /** Create CellularIdentifierDisclosureNotifier. */
+    public CellularIdentifierDisclosureNotifier makeIdentifierDisclosureNotifier() {
+        return CellularIdentifierDisclosureNotifier.getInstance();
+    }
 }
diff --git a/src/java/com/android/internal/telephony/data/AutoDataSwitchController.java b/src/java/com/android/internal/telephony/data/AutoDataSwitchController.java
index 0ea0598..e8cd8f0 100644
--- a/src/java/com/android/internal/telephony/data/AutoDataSwitchController.java
+++ b/src/java/com/android/internal/telephony/data/AutoDataSwitchController.java
@@ -47,6 +47,7 @@
 
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.subscription.SubscriptionInfoInternal;
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
 import com.android.internal.telephony.util.NotificationChannelController;
@@ -125,6 +126,7 @@
 
     private final @NonNull LocalLog mLocalLog = new LocalLog(128);
     private final @NonNull Context mContext;
+    private final @NonNull FeatureFlags mFlags;
     private final @NonNull SubscriptionManagerService mSubscriptionManagerService;
     private final @NonNull PhoneSwitcher mPhoneSwitcher;
     private final @NonNull AutoDataSwitchControllerCallback mPhoneSwitcherCallback;
@@ -167,15 +169,29 @@
      * switch to.
      */
     private static class PhoneSignalStatus {
+        /**
+         * How preferred the current phone is.
+         */
+        enum UsableState {
+            HOME(1), ROAMING_ENABLED(0), NOT_USABLE(-1);
+            /**
+             * The higher the score, the more preferred.
+             * HOME is preferred over ROAMING assuming roaming is metered.
+             */
+            final int mScore;
+            UsableState(int score) {
+                this.mScore = score;
+            }
+        }
         /** The phone */
-        private final @NonNull Phone mPhone;
+        @NonNull private final Phone mPhone;
         /** Data registration state of the phone */
-        private @RegistrationState int mDataRegState = NetworkRegistrationInfo
+        @RegistrationState private int mDataRegState = NetworkRegistrationInfo
                 .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING;
         /** Current Telephony display info of the phone */
-        private @NonNull TelephonyDisplayInfo mDisplayInfo;
+        @NonNull private TelephonyDisplayInfo mDisplayInfo;
         /** Signal strength of the phone */
-        private @NonNull SignalStrength mSignalStrength;
+        @NonNull private SignalStrength mSignalStrength;
         /** {@code true} if this slot is listening for events. */
         private boolean mListeningForEvents;
         private PhoneSignalStatus(@NonNull Phone phone) {
@@ -193,11 +209,28 @@
                     ? mPhone.getDataNetworkController().getDataConfigManager()
                             .getAutoDataSwitchScore(mDisplayInfo, mSignalStrength) : 0;
         }
+
+        /**
+         * @return The current usable state of the phone.
+         */
+        private UsableState getUsableState() {
+            switch (mDataRegState) {
+                case NetworkRegistrationInfo.REGISTRATION_STATE_HOME:
+                    return UsableState.HOME;
+                case NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING:
+                    return mPhone.getDataRoamingEnabled()
+                            ? UsableState.ROAMING_ENABLED : UsableState.NOT_USABLE;
+                default:
+                    return UsableState.NOT_USABLE;
+            }
+        }
+
         @Override
         public String toString() {
             return "{phone " + mPhone.getPhoneId()
                     + " score=" + getRatSignalScore() + " dataRegState="
                     + NetworkRegistrationInfo.registrationStateToString(mDataRegState)
+                    + " " + getUsableState()
                     + " display=" + mDisplayInfo + " signalStrength=" + mSignalStrength.getLevel()
                     + " listeningForEvents=" + mListeningForEvents
                     + "}";
@@ -238,10 +271,11 @@
      * @param phoneSwitcherCallback Callback for phone switcher to execute.
      */
     public AutoDataSwitchController(@NonNull Context context, @NonNull Looper looper,
-            @NonNull PhoneSwitcher phoneSwitcher,
+            @NonNull PhoneSwitcher phoneSwitcher, @NonNull FeatureFlags featureFlags,
             @NonNull AutoDataSwitchControllerCallback phoneSwitcherCallback) {
         super(looper);
         mContext = context;
+        mFlags = featureFlags;
         mSubscriptionManagerService = SubscriptionManagerService.getInstance();
         mPhoneSwitcher = phoneSwitcher;
         mPhoneSwitcherCallback = phoneSwitcherCallback;
@@ -275,7 +309,7 @@
     }
 
     /** Notify subscriptions changed. */
-    public void notifySubscriptionsChanged() {
+    public void notifySubscriptionsMappingChanged() {
         sendEmptyMessage(EVENT_SUBSCRIPTIONS_CHANGED);
     }
 
@@ -291,16 +325,19 @@
                 .collect(Collectors.toSet());
         // Track events only if there are at least two active visible subscriptions.
         if (activePhoneIds.size() < 2) activePhoneIds.clear();
+        boolean changed = false;
         for (int phoneId = 0; phoneId < mPhonesSignalStatus.length; phoneId++) {
             if (activePhoneIds.contains(phoneId)
                     && !mPhonesSignalStatus[phoneId].mListeningForEvents) {
                 registerAllEventsForPhone(phoneId);
+                changed = true;
             } else if (!activePhoneIds.contains(phoneId)
                     && mPhonesSignalStatus[phoneId].mListeningForEvents) {
                 unregisterAllEventsForPhone(phoneId);
+                changed = true;
             }
         }
-        logl("onSubscriptionChanged: " + Arrays.toString(mPhonesSignalStatus));
+        if (changed) logl("onSubscriptionChanged: " + Arrays.toString(mPhonesSignalStatus));
     }
 
     /**
@@ -362,7 +399,7 @@
             case EVENT_SERVICE_STATE_CHANGED:
                 ar = (AsyncResult) msg.obj;
                 phoneId = (int) ar.userObj;
-                onRegistrationStateChanged(phoneId);
+                onServiceStateChanged(phoneId);
                 break;
             case EVENT_DISPLAY_INFO_CHANGED:
                 ar = (AsyncResult) msg.obj;
@@ -396,7 +433,7 @@
     /**
      * Called when registration state changed.
      */
-    private void onRegistrationStateChanged(int phoneId) {
+    private void onServiceStateChanged(int phoneId) {
         Phone phone = PhoneFactory.getPhone(phoneId);
         if (phone != null && isActiveModemPhone(phoneId)) {
             int oldRegState = mPhonesSignalStatus[phoneId].mDataRegState;
@@ -409,7 +446,7 @@
                 mPhonesSignalStatus[phoneId].mDataRegState = newRegState;
                 if (isInService(oldRegState) != isInService(newRegState)
                         || isHomeService(oldRegState) != isHomeService(newRegState)) {
-                    log("onRegistrationStateChanged: phone " + phoneId + " "
+                    log("onServiceStateChanged: phone " + phoneId + " "
                             + NetworkRegistrationInfo.registrationStateToString(oldRegState)
                             + " -> "
                             + NetworkRegistrationInfo.registrationStateToString(newRegState));
@@ -562,35 +599,92 @@
             boolean backToDefault = false;
             boolean needValidation = true;
 
-            if (mDefaultNetworkIsOnNonCellular) {
-                log(debugMessage.append(", back to default as default network")
-                        .append(" is active on nonCellular transport").toString());
-                backToDefault = true;
-                needValidation = false;
-            } else if (!isHomeService(mPhonesSignalStatus[preferredPhoneId].mDataRegState)) {
-                log(debugMessage.append(", back to default as backup phone lost HOME registration")
-                        .toString());
-                backToDefault = true;
-                needValidation = false;
-            } else if (isRatSignalStrengthBasedSwitchEnabled()) {
-                int defaultScore = mPhonesSignalStatus[defaultDataPhoneId].getRatSignalScore();
-                int currentScore = mPhonesSignalStatus[preferredPhoneId].getRatSignalScore();
-                if ((defaultScore - currentScore) > mScoreTolerance) {
-                    log(debugMessage
-                            .append(", back to default as default phone has higher score ")
-                            .append(defaultScore).append(" versus current ")
-                            .append(currentScore).toString());
+            if (mFlags.autoSwitchAllowRoaming()) {
+                if (mDefaultNetworkIsOnNonCellular) {
+                    debugMessage.append(", back to default as default network")
+                            .append(" is active on nonCellular transport");
+                    backToDefault = true;
+                    needValidation = false;
+                } else {
+                    PhoneSignalStatus.UsableState defaultUsableState =
+                            mPhonesSignalStatus[defaultDataPhoneId].getUsableState();
+                    PhoneSignalStatus.UsableState currentUsableState =
+                            mPhonesSignalStatus[preferredPhoneId].getUsableState();
+
+                    boolean isCurrentUsable = currentUsableState.mScore
+                            > PhoneSignalStatus.UsableState.NOT_USABLE.mScore;
+
+                    if (currentUsableState.mScore < defaultUsableState.mScore) {
+                        debugMessage.append(", back to default phone ").append(preferredPhoneId)
+                                .append(" : ").append(defaultUsableState)
+                                .append(" , backup phone: ").append(currentUsableState);
+
+                        backToDefault = true;
+                        // Require validation if the current preferred phone is usable.
+                        needValidation = isCurrentUsable && mRequirePingTestBeforeSwitch;
+                    } else if (defaultUsableState.mScore == currentUsableState.mScore) {
+                        debugMessage.append(", default phone ").append(preferredPhoneId)
+                                .append(" : ").append(defaultUsableState)
+                                .append(" , backup phone: ").append(currentUsableState);
+
+                        if (isCurrentUsable) {
+                            // Both phones are usable.
+                            if (isRatSignalStrengthBasedSwitchEnabled()) {
+                                int defaultScore = mPhonesSignalStatus[defaultDataPhoneId]
+                                        .getRatSignalScore();
+                                int currentScore = mPhonesSignalStatus[preferredPhoneId]
+                                        .getRatSignalScore();
+                                if ((defaultScore - currentScore) > mScoreTolerance) {
+                                    debugMessage
+                                            .append(", back to default for higher score ")
+                                            .append(defaultScore).append(" versus current ")
+                                            .append(currentScore);
+                                    backToDefault = true;
+                                    needValidation = mRequirePingTestBeforeSwitch;
+                                }
+                            } else {
+                                // Only OOS/in service switch is enabled, switch back.
+                                debugMessage.append(", back to default as it's usable. ");
+                                backToDefault = true;
+                                needValidation = mRequirePingTestBeforeSwitch;
+                            }
+                        } else {
+                            debugMessage.append(", back to default as both phones are unusable.");
+                            backToDefault = true;
+                            needValidation = false;
+                        }
+                    }
+                }
+            } else {
+                if (mDefaultNetworkIsOnNonCellular) {
+                    debugMessage.append(", back to default as default network")
+                            .append(" is active on nonCellular transport");
+                    backToDefault = true;
+                    needValidation = false;
+                } else if (!isHomeService(mPhonesSignalStatus[preferredPhoneId].mDataRegState)) {
+                    debugMessage.append(", back to default as backup phone lost HOME registration");
+                    backToDefault = true;
+                    needValidation = false;
+                } else if (isRatSignalStrengthBasedSwitchEnabled()) {
+                    int defaultScore = mPhonesSignalStatus[defaultDataPhoneId].getRatSignalScore();
+                    int currentScore = mPhonesSignalStatus[preferredPhoneId].getRatSignalScore();
+                    if ((defaultScore - currentScore) > mScoreTolerance) {
+                        debugMessage
+                                .append(", back to default as default phone has higher score ")
+                                .append(defaultScore).append(" versus current ")
+                                .append(currentScore);
+                        backToDefault = true;
+                        needValidation = mRequirePingTestBeforeSwitch;
+                    }
+                } else if (isInService(mPhonesSignalStatus[defaultDataPhoneId].mDataRegState)) {
+                    debugMessage.append(", back to default as the default is back to service ");
                     backToDefault = true;
                     needValidation = mRequirePingTestBeforeSwitch;
                 }
-            } else if (isInService(mPhonesSignalStatus[defaultDataPhoneId].mDataRegState)) {
-                log(debugMessage.append(", back to default as the default is back to service ")
-                        .toString());
-                backToDefault = true;
-                needValidation = mRequirePingTestBeforeSwitch;
             }
 
             if (backToDefault) {
+                log(debugMessage.toString());
                 mSelectedTargetPhoneId = defaultDataPhoneId;
                 startStabilityCheck(DEFAULT_PHONE_INDEX, needValidation);
             } else {
@@ -625,20 +719,60 @@
             return INVALID_PHONE_INDEX;
         }
 
-        // check whether primary and secondary signal status are worth switching
-        if (!isRatSignalStrengthBasedSwitchEnabled()
-                && isInService(mPhonesSignalStatus[defaultPhoneId].mDataRegState)) {
-            debugMessage.append(", no candidate as default phone is in service");
-            return INVALID_PHONE_INDEX;
+        if (mFlags.autoSwitchAllowRoaming()) {
+            // check whether primary and secondary signal status are worth switching
+            if (!isRatSignalStrengthBasedSwitchEnabled()
+                    && isHomeService(mPhonesSignalStatus[defaultPhoneId].mDataRegState)) {
+                debugMessage.append(", no candidate as default phone is in HOME service");
+                return INVALID_PHONE_INDEX;
+            }
+        } else {
+            // check whether primary and secondary signal status are worth switching
+            if (!isRatSignalStrengthBasedSwitchEnabled()
+                    && isInService(mPhonesSignalStatus[defaultPhoneId].mDataRegState)) {
+                debugMessage.append(", no candidate as default phone is in service");
+                return INVALID_PHONE_INDEX;
+            }
         }
-        for (int phoneId = 0; phoneId < mPhonesSignalStatus.length; phoneId++) {
-            if (phoneId != defaultPhoneId
-                    // the alternative phone must have HOME availability
-                    && isHomeService(mPhonesSignalStatus[phoneId].mDataRegState)) {
-                Phone secondaryDataPhone = null;
-                debugMessage.append(", found phone ").append(phoneId).append(" in HOME reg");
 
-                if (isInService(mPhonesSignalStatus[defaultPhoneId].mDataRegState)) {
+        PhoneSignalStatus defaultPhoneStatus = mPhonesSignalStatus[defaultPhoneId];
+        for (int phoneId = 0; phoneId < mPhonesSignalStatus.length; phoneId++) {
+            if (phoneId == defaultPhoneId) continue;
+
+            Phone secondaryDataPhone = null;
+            PhoneSignalStatus candidatePhoneStatus = mPhonesSignalStatus[phoneId];
+            if (mFlags.autoSwitchAllowRoaming()) {
+                PhoneSignalStatus.UsableState currentUsableState =
+                        mPhonesSignalStatus[defaultPhoneId].getUsableState();
+                PhoneSignalStatus.UsableState candidatePhoneUsableRank =
+                        mPhonesSignalStatus[phoneId].getUsableState();
+                debugMessage.append(", found phone ").append(phoneId).append(" is ").append(
+                        candidatePhoneUsableRank)
+                        .append(", current is ").append(currentUsableState);
+                if (candidatePhoneUsableRank.mScore > currentUsableState.mScore) {
+                    secondaryDataPhone = PhoneFactory.getPhone(phoneId);
+                } else if (isRatSignalStrengthBasedSwitchEnabled()
+                        && currentUsableState.mScore == candidatePhoneUsableRank.mScore) {
+                    // Both phones are home or both roaming enabled, so compare RAT/signal score.
+
+                    int defaultScore = defaultPhoneStatus.getRatSignalScore();
+                    int candidateScore = candidatePhoneStatus.getRatSignalScore();
+                    if ((candidateScore - defaultScore) > mScoreTolerance) {
+                        debugMessage.append(" with higher score ").append(
+                                        candidateScore)
+                                .append(" versus current ").append(defaultScore);
+                        secondaryDataPhone = PhoneFactory.getPhone(phoneId);
+                    } else {
+                        debugMessage.append(", but its score ").append(candidateScore)
+                                .append(" doesn't meet the bar to switch given the current ")
+                                .append(defaultScore);
+                    }
+                }
+            } else if (isHomeService(candidatePhoneStatus.mDataRegState)) {
+                // the alternative phone must have HOME availability
+                debugMessage.append(", found phone ").append(phoneId).append(" in HOME service");
+
+                if (isInService(defaultPhoneStatus.mDataRegState)) {
                     // Use score if RAT/signal strength based switch is enabled and both phone are
                     // in service.
                     if (isRatSignalStrengthBasedSwitchEnabled()) {
@@ -658,13 +792,14 @@
                     // Only OOS/in service switch is enabled.
                     secondaryDataPhone = PhoneFactory.getPhone(phoneId);
                 }
-                if (secondaryDataPhone != null) {
-                    // check auto switch feature enabled
-                    if (secondaryDataPhone.isDataAllowed()) {
-                        return phoneId;
-                    } else {
-                        debugMessage.append(", but its data is not allowed");
-                    }
+            }
+
+            if (secondaryDataPhone != null) {
+                // check auto switch feature enabled
+                if (secondaryDataPhone.isDataAllowed()) {
+                    return phoneId;
+                } else {
+                    debugMessage.append(", but its data is not allowed");
                 }
             }
         }
@@ -676,7 +811,7 @@
      * @return {@code true} If the feature of switching base on RAT and signal strength is enabled.
      */
     private boolean isRatSignalStrengthBasedSwitchEnabled() {
-        return mScoreTolerance >= 0;
+        return mFlags.autoDataSwitchRatSs() && mScoreTolerance >= 0;
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java
index 36e6587..2c84f5e 100644
--- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java
+++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java
@@ -28,6 +28,7 @@
 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM;
 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN;
 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE;
+
 import static java.util.Arrays.copyOf;
 
 import android.annotation.NonNull;
@@ -83,6 +84,7 @@
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.data.DataNetworkController.NetworkRequestList;
 import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwitch;
@@ -184,6 +186,7 @@
     private final @NonNull NetworkRequestList mNetworkRequestList = new NetworkRequestList();
     protected final RegistrantList mActivePhoneRegistrants;
     private final SubscriptionManagerService mSubscriptionManagerService;
+    private final @NonNull FeatureFlags mFlags;
     protected final Context mContext;
     private final LocalLog mLocalLog;
     protected PhoneState[] mPhoneStates;
@@ -397,9 +400,10 @@
     /**
      * Method to create singleton instance.
      */
-    public static PhoneSwitcher make(int maxDataAttachModemCount, Context context, Looper looper) {
+    public static PhoneSwitcher make(int maxDataAttachModemCount, Context context, Looper looper,
+            @NonNull FeatureFlags flags) {
         if (sPhoneSwitcher == null) {
-            sPhoneSwitcher = new PhoneSwitcher(maxDataAttachModemCount, context, looper);
+            sPhoneSwitcher = new PhoneSwitcher(maxDataAttachModemCount, context, looper, flags);
         }
 
         return sPhoneSwitcher;
@@ -457,9 +461,11 @@
     }
 
     @VisibleForTesting
-    public PhoneSwitcher(int maxActivePhones, Context context, Looper looper) {
+    public PhoneSwitcher(int maxActivePhones, Context context, Looper looper,
+            @NonNull FeatureFlags featureFlags) {
         super(looper);
         mContext = context;
+        mFlags = featureFlags;
         mActiveModemCount = getTm().getActiveModemCount();
         mPhoneSubscriptions = new int[mActiveModemCount];
         mPhoneStates = new PhoneState[mActiveModemCount];
@@ -497,6 +503,12 @@
                                     @TelephonyManager.DataEnabledChangedReason int reason,
                                     @NonNull String callingPackage) {
                                 PhoneSwitcher.this.onDataEnabledChanged();
+                            }
+                            @Override
+                            public void onDataRoamingEnabledChanged(boolean enabled) {
+                                PhoneSwitcher.this.mAutoDataSwitchController.evaluateAutoDataSwitch(
+                                        AutoDataSwitchController
+                                                .EVALUATION_REASON_DATA_SETTINGS_CHANGED);
                             }});
                 phone.getDataSettingsManager().registerCallback(
                         mDataSettingsManagerCallbacks.get(phoneId));
@@ -546,7 +558,7 @@
             }
         };
         mAutoDataSwitchController = new AutoDataSwitchController(context, looper, this,
-                mAutoDataSwitchCallback);
+                mFlags, mAutoDataSwitchCallback);
 
         mContext.registerReceiver(mDefaultDataChangedReceiver,
                 new IntentFilter(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED));
@@ -647,7 +659,6 @@
     public void handleMessage(Message msg) {
         switch (msg.what) {
             case EVENT_SUBSCRIPTION_CHANGED: {
-                mAutoDataSwitchController.notifySubscriptionsChanged();
                 onEvaluate(REQUESTS_UNCHANGED, "subscription changed");
                 break;
             }
@@ -902,6 +913,12 @@
                                 @NonNull String callingPackage) {
                             PhoneSwitcher.this.onDataEnabledChanged();
                         }
+                        @Override
+                        public void onDataRoamingEnabledChanged(boolean enabled) {
+                            PhoneSwitcher.this.mAutoDataSwitchController.evaluateAutoDataSwitch(
+                                    AutoDataSwitchController
+                                            .EVALUATION_REASON_DATA_SETTINGS_CHANGED);
+                        }
                     });
             phone.getDataSettingsManager().registerCallback(
                     mDataSettingsManagerCallbacks.get(phone.getPhoneId()));
@@ -1080,6 +1097,7 @@
                     registerForImsRadioTechChange(mContext, i);
                 }
                 diffDetected = true;
+                mAutoDataSwitchController.notifySubscriptionsMappingChanged();
             }
         }
 
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
index 4943ba3..b21d45d 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
@@ -23,6 +23,8 @@
 import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_NONE;
 import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK;
 import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT;
+import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_RAT_BLOCK;
+import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCK;
 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE;
 
 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAIC;
@@ -2527,6 +2529,11 @@
                 if ((suggestedAction == SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK)
                         || (suggestedAction == SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT)) {
                     suggestedModemAction = suggestedAction;
+                } else if (mFeatureFlags.addRatRelatedSuggestedActionToImsRegistration()) {
+                    if ((suggestedAction == SUGGESTED_ACTION_TRIGGER_RAT_BLOCK)
+                            || (suggestedAction == SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCK)) {
+                        suggestedModemAction = suggestedAction;
+                    }
                 }
             }
             updateImsRegistrationInfo(REGISTRATION_STATE_NOT_REGISTERED,
diff --git a/src/java/com/android/internal/telephony/security/CellularIdentifierDisclosureNotifier.java b/src/java/com/android/internal/telephony/security/CellularIdentifierDisclosureNotifier.java
new file mode 100644
index 0000000..46e6a28
--- /dev/null
+++ b/src/java/com/android/internal/telephony/security/CellularIdentifierDisclosureNotifier.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.security;
+
+import android.telephony.CellularIdentifierDisclosure;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.telephony.Rlog;
+
+/**
+ * Encapsulates logic to emit notifications to the user that their cellular identifiers were
+ * disclosed in the clear.
+ *
+ * <p>This class will either emit notifications through SafetyCenterManager if SafetyCenter exists
+ * on a device, or it will emit system notifications otherwise.
+ *
+ * @hide
+ */
+public class CellularIdentifierDisclosureNotifier {
+
+    private static final String TAG = "CellularIdentifierDisclosureNotifier";
+    private static CellularIdentifierDisclosureNotifier sInstance = null;
+
+    @VisibleForTesting
+    public CellularIdentifierDisclosureNotifier() {}
+
+    /**
+     * Add a CellularIdentifierDisclosure to be tracked by this instance.
+     * If appropriate, this will trigger a user notification.
+     */
+    public void addDisclosure(CellularIdentifierDisclosure disclosure) {
+        // TODO (b/308985417) this is a stub method for now. Logic
+        // for tracking disclosures and emitting notifications will flow
+        // from here.
+        Rlog.d(TAG, "Identifier disclosure reported: " + disclosure);
+    }
+
+    /**
+     * Get a singleton CellularIdentifierDisclosureNotifier.
+     */
+    public static synchronized CellularIdentifierDisclosureNotifier getInstance() {
+        if (sInstance == null) {
+            sInstance = new CellularIdentifierDisclosureNotifier();
+        }
+
+        return sInstance;
+    }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
index 2dac867..da3920e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
@@ -779,7 +779,7 @@
         doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyString());
         doAnswer(invocation -> mNetworkId++).when(mNetwork).getNetId();
         doReturn(mNetwork).when(mConnectivityManager).registerNetworkAgent(
-                any(), any(), any(), any(), any(), any(), any(), anyInt());
+                any(), any(), any(), any(), any(), any(), anyInt());
 
         doReturn(true).when(mEuiccManager).isEnabled();
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
index 2563fdf..34087b6 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
@@ -72,6 +72,7 @@
 import android.telephony.CellIdentity;
 import android.telephony.CellIdentityCdma;
 import android.telephony.CellIdentityGsm;
+import android.telephony.CellularIdentifierDisclosure;
 import android.telephony.LinkCapacityEstimate;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.RadioAccessFamily;
@@ -2761,4 +2762,105 @@
         assertEquals(Phone.IMEI_TYPE_SECONDARY, mPhoneUT.getImeiType());
         assertEquals(FAKE_IMEI, mPhoneUT.getImei());
     }
+
+    @Test
+    public void testCellularIdentifierDisclosureFlagOff() {
+        when(mFeatureFlags.enableIdentifierDisclosureTransparency()).thenReturn(false);
+
+        GsmCdmaPhone phoneUT =
+                new GsmCdmaPhone(
+                        mContext,
+                        mSimulatedCommands,
+                        mNotifier,
+                        true,
+                        0,
+                        PhoneConstants.PHONE_TYPE_GSM,
+                        mTelephonyComponentFactory,
+                        (c, p) -> mImsManager,
+                        mFeatureFlags);
+        phoneUT.mCi = mMockCi;
+
+        verify(mMockCi, never())
+                .registerForCellularIdentifierDisclosures(
+                        any(Handler.class), anyInt(), any(Object.class));
+    }
+
+    @Test
+    public void testCellularIdentifierDisclosureFlagOn() {
+        when(mFeatureFlags.enableIdentifierDisclosureTransparency()).thenReturn(true);
+
+        Phone phoneUT =
+                new GsmCdmaPhone(
+                        mContext,
+                        mMockCi,
+                        mNotifier,
+                        true,
+                        0,
+                        PhoneConstants.PHONE_TYPE_GSM,
+                        mTelephonyComponentFactory,
+                        (c, p) -> mImsManager,
+                        mFeatureFlags);
+
+        verify(mMockCi, times(1))
+                .registerForCellularIdentifierDisclosures(
+                        eq(phoneUT),
+                        eq(Phone.EVENT_CELL_IDENTIFIER_DISCLOSURE),
+                        nullable(Object.class));
+    }
+
+    @Test
+    public void testCellularIdentifierDisclosure_disclosureEventAddedToNotifier() {
+        when(mFeatureFlags.enableIdentifierDisclosureTransparency()).thenReturn(true);
+
+        Phone phoneUT =
+                new GsmCdmaPhone(
+                        mContext,
+                        mMockCi,
+                        mNotifier,
+                        true,
+                        0,
+                        PhoneConstants.PHONE_TYPE_GSM,
+                        mTelephonyComponentFactory,
+                        (c, p) -> mImsManager,
+                        mFeatureFlags);
+
+        CellularIdentifierDisclosure disclosure =
+                new CellularIdentifierDisclosure(
+                        CellularIdentifierDisclosure.NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST,
+                        CellularIdentifierDisclosure.CELLULAR_IDENTIFIER_IMSI,
+                        "001001",
+                        false);
+        phoneUT.sendMessage(
+                mPhoneUT.obtainMessage(
+                        Phone.EVENT_CELL_IDENTIFIER_DISCLOSURE,
+                        new AsyncResult(null, disclosure, null)));
+        processAllMessages();
+
+        verify(mIdentifierDisclosureNotifier, times(1)).addDisclosure(eq(disclosure));
+    }
+
+    @Test
+    public void testCellularIdentifierDisclosure_disclosureEventNull() {
+        when(mFeatureFlags.enableIdentifierDisclosureTransparency()).thenReturn(true);
+
+        Phone phoneUT =
+                new GsmCdmaPhone(
+                        mContext,
+                        mMockCi,
+                        mNotifier,
+                        true,
+                        0,
+                        PhoneConstants.PHONE_TYPE_GSM,
+                        mTelephonyComponentFactory,
+                        (c, p) -> mImsManager,
+                        mFeatureFlags);
+
+        phoneUT.sendMessage(
+                mPhoneUT.obtainMessage(
+                        Phone.EVENT_CELL_IDENTIFIER_DISCLOSURE, new AsyncResult(null, null, null)));
+        processAllMessages();
+
+        verify(mIdentifierDisclosureNotifier, never())
+                .addDisclosure(any(CellularIdentifierDisclosure.class));
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index b8d875c..1ebe96d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -122,6 +122,7 @@
 import com.android.internal.telephony.metrics.SmsStats;
 import com.android.internal.telephony.metrics.VoiceCallSessionStats;
 import com.android.internal.telephony.satellite.SatelliteController;
+import com.android.internal.telephony.security.CellularIdentifierDisclosureNotifier;
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
 import com.android.internal.telephony.test.SimulatedCommands;
 import com.android.internal.telephony.test.SimulatedCommandsVerifier;
@@ -279,6 +280,7 @@
     protected ServiceStateStats mServiceStateStats;
     protected SatelliteController mSatelliteController;
     protected DeviceStateHelper mDeviceStateHelper;
+    protected CellularIdentifierDisclosureNotifier mIdentifierDisclosureNotifier;
 
     // Initialized classes
     protected ActivityManager mActivityManager;
@@ -549,6 +551,7 @@
         mServiceStateStats = Mockito.mock(ServiceStateStats.class);
         mSatelliteController = Mockito.mock(SatelliteController.class);
         mDeviceStateHelper = Mockito.mock(DeviceStateHelper.class);
+        mIdentifierDisclosureNotifier = Mockito.mock(CellularIdentifierDisclosureNotifier.class);
 
         TelephonyManager.disableServiceHandleCaching();
         PropertyInvalidatedCache.disableForTestMode();
@@ -662,6 +665,9 @@
                         any(DataServiceManager.class), any(Looper.class),
                         any(FeatureFlags.class),
                         any(DataProfileManager.DataProfileManagerCallback.class));
+        doReturn(mIdentifierDisclosureNotifier)
+                .when(mTelephonyComponentFactory)
+                .makeIdentifierDisclosureNotifier();
 
         //mPhone
         doReturn(mContext).when(mPhone).getContext();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/AutoDataSwitchControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/AutoDataSwitchControllerTest.java
index 4b88f0a..6462d73 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/AutoDataSwitchControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/AutoDataSwitchControllerTest.java
@@ -152,12 +152,16 @@
         doReturn(PHONE_1).when(mPhoneSwitcher).getPreferredDataPhoneId();
 
         mAutoDataSwitchControllerUT = new AutoDataSwitchController(mContext, Looper.myLooper(),
-                mPhoneSwitcher, mMockedPhoneSwitcherCallback);
+                mPhoneSwitcher, mFeatureFlags, mMockedPhoneSwitcherCallback);
+
+        doReturn(true).when(mFeatureFlags).autoSwitchAllowRoaming();
     }
 
     @After
     public void tearDown() throws Exception {
         mAutoDataSwitchControllerUT = null;
+        mGoodTelephonyDisplayInfo = null;
+        mBadTelephonyDisplayInfo = null;
         super.tearDown();
     }
 
@@ -222,6 +226,97 @@
     }
 
     @Test
+    public void testRoaming_prefer_home_over_roam() {
+        // DDS -> nDDS: Prefer Home over Roaming
+        prepareIdealUsesNonDdsCondition();
+        serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING);
+        serviceStateChanged(PHONE_2, NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+        processAllFutureMessages();
+
+        verify(mMockedPhoneSwitcherCallback).onRequireValidation(PHONE_2, true/*needValidation*/);
+
+        // nDDS -> DDS: Prefer Home over Roaming
+        doReturn(PHONE_2).when(mPhoneSwitcher).getPreferredDataPhoneId();
+        serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+        serviceStateChanged(PHONE_2, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING);
+        processAllFutureMessages();
+
+        verify(mMockedPhoneSwitcherCallback).onRequireValidation(DEFAULT_PHONE_INDEX,
+                true/*needValidation*/);
+    }
+
+    @Test
+    public void testRoaming_roaming_but_roam_disabled() {
+        // Disable RAT + signalStrength base switching.
+        doReturn(-1).when(mDataConfigManager).getAutoDataSwitchScoreTolerance();
+        mAutoDataSwitchControllerUT = new AutoDataSwitchController(mContext, Looper.myLooper(),
+                mPhoneSwitcher, mFeatureFlags, mMockedPhoneSwitcherCallback);
+
+        // On primary phone
+        // 1.1 Both roaming, user allow roaming on both phone, no need to switch.
+        prepareIdealUsesNonDdsCondition();
+        serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING);
+        serviceStateChanged(PHONE_2, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING);
+        processAllFutureMessages();
+        clearInvocations(mMockedPhoneSwitcherCallback);
+
+        mAutoDataSwitchControllerUT.evaluateAutoDataSwitch(EVALUATION_REASON_DATA_SETTINGS_CHANGED);
+        processAllFutureMessages();
+        verify(mMockedPhoneSwitcherCallback, never()).onRequireValidation(anyInt(),
+                anyBoolean()/*needValidation*/);
+
+        // 1.2 Both roaming, but roaming is only allowed on the backup phone.
+        doReturn(false).when(mPhone).getDataRoamingEnabled();
+        mAutoDataSwitchControllerUT.evaluateAutoDataSwitch(EVALUATION_REASON_DATA_SETTINGS_CHANGED);
+        processAllFutureMessages();
+
+        verify(mMockedPhoneSwitcherCallback).onRequireValidation(PHONE_2, true/*needValidation*/);
+
+        // On backup phone
+        doReturn(PHONE_2).when(mPhoneSwitcher).getPreferredDataPhoneId();
+        // 2.1 Both roaming, user allow roaming on both phone, prefer default.
+        doReturn(true).when(mPhone).getDataRoamingEnabled();
+        mAutoDataSwitchControllerUT.evaluateAutoDataSwitch(EVALUATION_REASON_DATA_SETTINGS_CHANGED);
+        processAllFutureMessages();
+
+        verify(mMockedPhoneSwitcherCallback).onRequireValidation(DEFAULT_PHONE_INDEX,
+                true/*needValidation*/);
+
+        // 2.1 Both roaming, but roaming is only allowed on the default phone.
+        doReturn(false).when(mPhone2).getDataRoamingEnabled();
+        mAutoDataSwitchControllerUT.evaluateAutoDataSwitch(EVALUATION_REASON_DATA_SETTINGS_CHANGED);
+        processAllFutureMessages();
+
+        verify(mMockedPhoneSwitcherCallback).onRequireValidation(DEFAULT_PHONE_INDEX,
+                false/*needValidation*/);
+    }
+
+    @Test
+    public void testRoaming_same_roaming_condition_uses_rat_signalStrength() {
+        doReturn(true).when(mFeatureFlags).autoDataSwitchRatSs();
+        // On primary phone
+        // 1. Both roaming, user allow roaming on both phone, uses RAT score to decide switch.
+        prepareIdealUsesNonDdsCondition();
+        serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING);
+        serviceStateChanged(PHONE_2, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING);
+        processAllFutureMessages();
+
+        verify(mMockedPhoneSwitcherCallback).onRequireValidation(PHONE_2, true/*needValidation*/);
+
+        // On backup phone
+        doReturn(PHONE_2).when(mPhoneSwitcher).getPreferredDataPhoneId();
+        // 2. Both roaming, user allow roaming on both phone, uses RAT score to decide switch.
+        signalStrengthChanged(PHONE_1, SignalStrength.SIGNAL_STRENGTH_GREAT);
+        signalStrengthChanged(PHONE_2, SignalStrength.SIGNAL_STRENGTH_POOR);
+        displayInfoChanged(PHONE_1, mGoodTelephonyDisplayInfo);
+        displayInfoChanged(PHONE_2, mBadTelephonyDisplayInfo);
+        processAllFutureMessages();
+
+        verify(mMockedPhoneSwitcherCallback).onRequireValidation(DEFAULT_PHONE_INDEX,
+                true/*needValidation*/);
+    }
+
+    @Test
     public void testCancelSwitch_onPrimary_rat_signalStrength() {
         // 4.1.1 Display info and signal strength on secondary phone became bad,
         // but primary is still OOS, so still switch to the secondary.
@@ -269,13 +364,13 @@
         // Disable Rat/SignalStrength based switch to test primary OOS based switch
         doReturn(-1).when(mDataConfigManager).getAutoDataSwitchScoreTolerance();
         mAutoDataSwitchControllerUT = new AutoDataSwitchController(mContext, Looper.myLooper(),
-                mPhoneSwitcher, mMockedPhoneSwitcherCallback);
+                mPhoneSwitcher, mFeatureFlags, mMockedPhoneSwitcherCallback);
         doReturn(PHONE_2).when(mPhoneSwitcher).getPreferredDataPhoneId();
 
         prepareIdealUsesNonDdsCondition();
         // 1.1 service state changes - primary becomes available again, require validation
         serviceStateChanged(PHONE_1,
-                NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING/*need validate*/);
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME/*need validate*/);
         processAllFutureMessages();
         verify(mMockedPhoneSwitcherCallback).onRequireValidation(DEFAULT_PHONE_INDEX,
                 true/*needValidation*/);
@@ -285,7 +380,7 @@
         // 1.2 service state changes - secondary becomes unavailable, NO need validation
         serviceStateChanged(PHONE_1,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME/*need validate*/);
-        serviceStateChanged(PHONE_2, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING/*no need*/);
+        serviceStateChanged(PHONE_2, NetworkRegistrationInfo.REGISTRATION_STATE_DENIED/*no need*/);
         processAllFutureMessages();
         // The later validation requirement overrides the previous
         verify(mMockedPhoneSwitcherCallback).onRequireValidation(DEFAULT_PHONE_INDEX,
@@ -325,6 +420,7 @@
 
     @Test
     public void testOnNonDdsSwitchBackToPrimary_rat_signalStrength() {
+        doReturn(true).when(mFeatureFlags).autoDataSwitchRatSs();
         doReturn(PHONE_2).when(mPhoneSwitcher).getPreferredDataPhoneId();
 
         prepareIdealUsesNonDdsCondition();
@@ -354,8 +450,8 @@
         doReturn(PHONE_2).when(mPhoneSwitcher).getPreferredDataPhoneId();
         prepareIdealUsesNonDdsCondition();
 
-        // attempts the switch back due to secondary becomes ROAMING
-        serviceStateChanged(PHONE_2, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING);
+        // attempts the switch back due to secondary not usable
+        serviceStateChanged(PHONE_2, NetworkRegistrationInfo.REGISTRATION_STATE_DENIED);
         processAllFutureMessages();
 
         verify(mMockedPhoneSwitcherCallback).onRequireValidation(DEFAULT_PHONE_INDEX,
@@ -413,7 +509,7 @@
         doReturn(-1 /*Disable signal based switch for easy mock*/).when(mDataConfigManager)
                 .getAutoDataSwitchScoreTolerance();
         mAutoDataSwitchControllerUT = new AutoDataSwitchController(mContext, Looper.myLooper(),
-                mPhoneSwitcher, mMockedPhoneSwitcherCallback);
+                mPhoneSwitcher, mFeatureFlags, mMockedPhoneSwitcherCallback);
 
         //1. DDS -> nDDS, verify callback doesn't require validation
         prepareIdealUsesNonDdsCondition();
@@ -423,7 +519,7 @@
 
         //2. nDDS -> DDS, verify callback doesn't require validation
         doReturn(PHONE_2).when(mPhoneSwitcher).getPreferredDataPhoneId();
-        serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING);
+        serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
         processAllFutureMessages();
         verify(mMockedPhoneSwitcherCallback).onRequireValidation(DEFAULT_PHONE_INDEX,
                 false/*needValidation*/);
@@ -478,7 +574,7 @@
         int modemCount = 2;
         doReturn(new int[]{SUB_2}).when(mSubscriptionManagerService)
                 .getActiveSubIdList(true);
-        mAutoDataSwitchControllerUT.notifySubscriptionsChanged();
+        mAutoDataSwitchControllerUT.notifySubscriptionsMappingChanged();
         processAllMessages();
 
         // Verify unregister from both slots since only 1 visible SIM is insufficient for switching
@@ -492,7 +588,7 @@
         clearInvocations(mDisplayInfoController, mSignalStrengthController, mSST);
         doReturn(new int[]{SUB_1, SUB_2}).when(mSubscriptionManagerService)
                 .getActiveSubIdList(true);
-        mAutoDataSwitchControllerUT.notifySubscriptionsChanged();
+        mAutoDataSwitchControllerUT.notifySubscriptionsMappingChanged();
         processAllMessages();
 
         // Verify register on both slots
@@ -544,8 +640,10 @@
 
         // 4.1 User data enabled on primary SIM
         doReturn(true).when(mPhone).isUserDataEnabled();
+        doReturn(true).when(mPhone).getDataRoamingEnabled();
 
         // 4.2 Auto switch feature is enabled
+        doReturn(true).when(mPhone2).getDataRoamingEnabled();
         doReturn(true).when(mPhone2).isDataAllowed();
 
         // 5. No default network
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
index ffaf8fc..5dd83bf 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
@@ -445,7 +445,7 @@
 
         verify(mConnectivityManager).registerNetworkAgent(any(), any(NetworkInfo.class),
                 linkPropertiesCaptor.capture(), networkCapabilitiesCaptor.capture(), any(), any(),
-                any(), anyInt());
+                anyInt());
         // The very first link properties from telephony is an empty link properties. It will be
         // updated later.
         assertThat(linkPropertiesCaptor.getValue()).isEqualTo(new LinkProperties());
@@ -552,7 +552,7 @@
 
         verify(mConnectivityManager).registerNetworkAgent(any(), any(NetworkInfo.class),
                 any(LinkProperties.class), networkCapabilitiesCaptor.capture(), any(), any(),
-                any(), anyInt());
+                anyInt());
 
         // Make sure the initial network capability has NOT_SUSPENDED
         assertThat(networkCapabilitiesCaptor.getValue().hasCapability(
@@ -616,7 +616,7 @@
         // Agent re-created, so register should be called twice.
         verify(mConnectivityManager, times(2)).registerNetworkAgent(any(), any(NetworkInfo.class),
                 any(LinkProperties.class), networkCapabilitiesCaptor.capture(), any(), any(),
-                any(), anyInt());
+                anyInt());
 
         // Make sure the 2nd network agent was created with NOT_SUSPENDED.
         assertThat(networkCapabilitiesCaptor.getValue().hasCapability(
@@ -663,7 +663,7 @@
 
         verify(mConnectivityManager).registerNetworkAgent(any(), any(NetworkInfo.class),
                 linkPropertiesCaptor.capture(), networkCapabilitiesCaptor.capture(), any(), any(),
-                any(), anyInt());
+                anyInt());
         // The very first link properties from telephony is an empty link properties. It will be
         // updated later.
         assertThat(linkPropertiesCaptor.getValue()).isEqualTo(new LinkProperties());
@@ -1424,8 +1424,8 @@
                 .forClass(NetworkAgentConfig.class);
 
         verify(mConnectivityManager).registerNetworkAgent(any(), any(NetworkInfo.class),
-                any(LinkProperties.class), any(NetworkCapabilities.class), any(), any(),
-                captor.capture(), anyInt());
+                any(LinkProperties.class), any(NetworkCapabilities.class), any(), captor.capture(),
+                anyInt());
 
         NetworkAgentConfig networkAgentConfig = captor.getValue();
 
@@ -1508,7 +1508,7 @@
         // Agent re-created, so register should be called twice.
         verify(mConnectivityManager, times(2)).registerNetworkAgent(any(), any(NetworkInfo.class),
                 any(LinkProperties.class), any(NetworkCapabilities.class), any(), any(),
-                any(), anyInt());
+                anyInt());
 
         assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)).isTrue();
@@ -1530,7 +1530,7 @@
         // Agent not re-created, so register should be called once.
         verify(mConnectivityManager, times(1)).registerNetworkAgent(any(), any(NetworkInfo.class),
                 any(LinkProperties.class), any(NetworkCapabilities.class), any(), any(),
-                any(), anyInt());
+                anyInt());
 
         assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)).isTrue();
@@ -1730,7 +1730,7 @@
         // Agent re-created, so register should be called twice.
         verify(mConnectivityManager, times(2)).registerNetworkAgent(any(), any(NetworkInfo.class),
                 linkPropertiesCaptor.capture(), any(NetworkCapabilities.class), any(), any(),
-                any(), anyInt());
+                anyInt());
         // The new agent should have the new IP address.
         assertThat(linkPropertiesCaptor.getValue().getAllAddresses()).containsExactly(
                 InetAddresses.parseNumericAddress(IPV4_ADDRESS1),
@@ -1779,7 +1779,7 @@
         // Agent re-created, so register should be called twice.
         verify(mConnectivityManager, times(2)).registerNetworkAgent(any(), any(NetworkInfo.class),
                 linkPropertiesCaptor.capture(), any(NetworkCapabilities.class), any(), any(),
-                any(), anyInt());
+                anyInt());
         // The new agent should have the new IP address.
         assertThat(linkPropertiesCaptor.getValue().getAllAddresses()).containsExactly(
                 InetAddresses.parseNumericAddress(IPV6_ADDRESS1));
@@ -1870,7 +1870,7 @@
         // Agent should not be re-created, so register should be called ony once.
         verify(mConnectivityManager, times(1)).registerNetworkAgent(any(), any(NetworkInfo.class),
                 any(LinkProperties.class), any(NetworkCapabilities.class), any(), any(),
-                any(), anyInt());
+                anyInt());
 
         // The network should have IPv6 address now
         assertThat(mDataNetworkUT.getLinkProperties().getAllAddresses()).containsExactly(
@@ -1914,7 +1914,7 @@
         // Agent should not be re-created, so register should be called ony once.
         verify(mConnectivityManager, times(1)).registerNetworkAgent(any(), any(NetworkInfo.class),
                 any(LinkProperties.class), any(NetworkCapabilities.class), any(), any(),
-                any(), anyInt());
+                anyInt());
 
         // The network should have IPv6 address now
         assertThat(mDataNetworkUT.getLinkProperties().getAllAddresses()).containsExactly(
@@ -1959,7 +1959,7 @@
         // Agent should not be re-created, so register should be called ony once.
         verify(mConnectivityManager, times(1)).registerNetworkAgent(any(), any(NetworkInfo.class),
                 any(LinkProperties.class), any(NetworkCapabilities.class), any(), any(),
-                any(), anyInt());
+                anyInt());
 
         // The network should have IPv6 address now
         assertThat(mDataNetworkUT.getLinkProperties().getAllAddresses()).containsExactly(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java
index 94fd934..13ab611 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java
@@ -26,8 +26,10 @@
 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM;
 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN;
 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
+
 import static com.android.internal.telephony.data.AutoDataSwitchController.EVALUATION_REASON_VOICE_CALL_END;
 import static com.android.internal.telephony.data.PhoneSwitcher.ECBM_DEFAULT_DATA_SWITCH_BASE_TIME_MS;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -267,12 +269,14 @@
         assertFalse("data allowed", mDataAllowed[0]);
 
         setSlotIndexToSubId(1, 1);
+        clearInvocations(mAutoDataSwitchController);
         mSubChangedListener.onSubscriptionsChanged();
         processAllMessages();
 
         Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget();
         processAllMessages();
         verify(mActivePhoneSwitchHandler, times(1)).sendMessageAtTime(any(), anyLong());
+        verify(mAutoDataSwitchController).notifySubscriptionsMappingChanged();
         clearInvocations(mActivePhoneSwitchHandler);
         assertFalse("data allowed", mDataAllowed[0]);
         assertTrue("data not allowed", mDataAllowed[1]);
@@ -289,8 +293,10 @@
 
         // 3 lose default via sub->phone change
         setSlotIndexToSubId(0, 2);
+        clearInvocations(mAutoDataSwitchController);
         mSubChangedListener.onSubscriptionsChanged();
         processAllMessages();
+        verify(mAutoDataSwitchController).notifySubscriptionsMappingChanged();
         Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget();
         processAllMessages();
 
@@ -1097,7 +1103,6 @@
     }
 
     @Test
-    @SmallTest
     public void testDataEnabledChangedDuringVoiceCall() throws Exception {
         doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
         initialize();
@@ -1135,6 +1140,18 @@
     }
 
     @Test
+    public void testRoamingToggle() throws Exception {
+        initialize();
+        setSlotIndexToSubId(0, 1);
+
+        mDataSettingsManagerCallbacks.get(0).onDataRoamingEnabledChanged(true);
+        processAllMessages();
+
+        verify(mAutoDataSwitchController).evaluateAutoDataSwitch(AutoDataSwitchController
+                .EVALUATION_REASON_DATA_SETTINGS_CHANGED);
+    }
+
+    @Test
     @SmallTest
     public void testNetworkRequestOnNonDefaultData() throws Exception {
         doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
@@ -1858,7 +1875,8 @@
         initializeConnManagerMock();
         initializeConfigMock();
 
-        mPhoneSwitcherUT = new PhoneSwitcher(mMaxDataAttachModemCount, mContext, Looper.myLooper());
+        mPhoneSwitcherUT = new PhoneSwitcher(mMaxDataAttachModemCount, mContext, Looper.myLooper(),
+                mFeatureFlags);
 
         Field field = PhoneSwitcher.class.getDeclaredField("mDataSettingsManagerCallbacks");
         field.setAccessible(true);
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 4e61c67..fbb30ff 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
@@ -24,6 +24,8 @@
 import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_NONE;
 import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK;
 import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT;
+import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_RAT_BLOCK;
+import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCK;
 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_3G;
 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN;
 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
@@ -1484,6 +1486,81 @@
         assertTrue(regInfo[0] == 1 && regInfo[1] == 1 && regInfo[2] == 1);
     }
 
+    /**
+     * Verifies that valid state and reason is passed to RIL with RAT suggested actions
+     * when IMS registration state changes to unregistered.
+     */
+    @Test
+    @SmallTest
+    public void testUpdateImsRegistrationInfoWithRatSuggestedAction() {
+        doReturn(true).when(mFeatureFlags)
+                .addRatRelatedSuggestedActionToImsRegistration();
+
+        mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null);
+
+        int[] regInfo = mSimulatedCommands.getImsRegistrationInfo();
+        assertNotNull(regInfo);
+        assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0);
+
+        RegistrationManager.RegistrationCallback registrationCallback =
+                mImsPhoneUT.getImsMmTelRegistrationCallback();
+
+        ImsReasonInfo reasonInfo = new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR,
+                ImsReasonInfo.CODE_UNSPECIFIED, "");
+
+        // unregistered with rat block
+        registrationCallback.onUnregistered(reasonInfo,
+                SUGGESTED_ACTION_TRIGGER_RAT_BLOCK,
+                REGISTRATION_TECH_LTE);
+        regInfo = mSimulatedCommands.getImsRegistrationInfo();
+
+        assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED
+                && regInfo[1] == REGISTRATION_TECH_LTE
+                && regInfo[2] == SUGGESTED_ACTION_TRIGGER_RAT_BLOCK);
+
+        // reset the registration info saved in the SimulatedCommands
+        mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null);
+        regInfo = mSimulatedCommands.getImsRegistrationInfo();
+
+        assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0);
+
+        // verfies that duplicated notification with the same suggested action is invoked
+        registrationCallback.onUnregistered(reasonInfo,
+                SUGGESTED_ACTION_TRIGGER_RAT_BLOCK,
+                REGISTRATION_TECH_LTE);
+        regInfo = mSimulatedCommands.getImsRegistrationInfo();
+
+        assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED
+                && regInfo[1] == REGISTRATION_TECH_LTE
+                && regInfo[2] == SUGGESTED_ACTION_TRIGGER_RAT_BLOCK);
+
+        // unregistered with rat block clear
+        registrationCallback.onUnregistered(reasonInfo,
+                SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCK,
+                REGISTRATION_TECH_LTE);
+        regInfo = mSimulatedCommands.getImsRegistrationInfo();
+
+        assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED
+                && regInfo[1] == REGISTRATION_TECH_LTE
+                && regInfo[2] == SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCK);
+
+        // reset the registration info saved in the SimulatedCommands
+        mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null);
+        regInfo = mSimulatedCommands.getImsRegistrationInfo();
+
+        assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0);
+
+        // verfies that duplicated notification with the same suggested action is invoked
+        registrationCallback.onUnregistered(reasonInfo,
+                SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCK,
+                REGISTRATION_TECH_LTE);
+        regInfo = mSimulatedCommands.getImsRegistrationInfo();
+
+        assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED
+                && regInfo[1] == REGISTRATION_TECH_LTE
+                && regInfo[2] == SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCK);
+    }
+
     @Test
     @SmallTest
     public void testImsDialArgsBuilderFromForAlternateService() {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/security/CellularIdentifierDisclosureTest.java b/tests/telephonytests/src/com/android/internal/telephony/security/CellularIdentifierDisclosureTest.java
index 7d2a6a6..327a1cb 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/security/CellularIdentifierDisclosureTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/security/CellularIdentifierDisclosureTest.java
@@ -19,12 +19,16 @@
 import static android.telephony.CellularIdentifierDisclosure.CELLULAR_IDENTIFIER_IMEI;
 import static android.telephony.CellularIdentifierDisclosure.CELLULAR_IDENTIFIER_IMSI;
 import static android.telephony.CellularIdentifierDisclosure.NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST;
+import static android.telephony.CellularIdentifierDisclosure.NAS_PROTOCOL_MESSAGE_IDENTITY_RESPONSE;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 
+import android.hardware.radio.network.CellularIdentifier;
+import android.hardware.radio.network.NasProtocolMessage;
 import android.os.Parcel;
-import android.telephony.CellularIdentifierDisclosure;
+
+import com.android.internal.telephony.RILUtils;
 
 import org.junit.Test;
 
@@ -32,22 +36,38 @@
 
     @Test
     public void testEqualsAndHash() {
-        CellularIdentifierDisclosure disclosure = new CellularIdentifierDisclosure(
-                NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, CELLULAR_IDENTIFIER_IMSI, "001001", false);
+        android.telephony.CellularIdentifierDisclosure disclosure =
+                new android.telephony.CellularIdentifierDisclosure(
+                        NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST,
+                        CELLULAR_IDENTIFIER_IMSI,
+                        "001001",
+                        false);
 
-        CellularIdentifierDisclosure anotherDislcosure = new CellularIdentifierDisclosure(
-                NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, CELLULAR_IDENTIFIER_IMSI, "001001", false);
+        android.telephony.CellularIdentifierDisclosure anotherDislcosure =
+                new android.telephony.CellularIdentifierDisclosure(
+                        NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST,
+                        CELLULAR_IDENTIFIER_IMSI,
+                        "001001",
+                        false);
         assertEquals(disclosure, anotherDislcosure);
         assertEquals(disclosure.hashCode(), anotherDislcosure.hashCode());
     }
 
     @Test
     public void testNotEqualsAndHash() {
-        CellularIdentifierDisclosure imsiDisclosure = new CellularIdentifierDisclosure(
-                NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, CELLULAR_IDENTIFIER_IMSI, "001001", false);
+        android.telephony.CellularIdentifierDisclosure imsiDisclosure =
+                new android.telephony.CellularIdentifierDisclosure(
+                        NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST,
+                        CELLULAR_IDENTIFIER_IMSI,
+                        "001001",
+                        false);
 
-        CellularIdentifierDisclosure imeiDisclosure = new CellularIdentifierDisclosure(
-                NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, CELLULAR_IDENTIFIER_IMEI, "001001", false);
+        android.telephony.CellularIdentifierDisclosure imeiDisclosure =
+                new android.telephony.CellularIdentifierDisclosure(
+                        NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST,
+                        CELLULAR_IDENTIFIER_IMEI,
+                        "001001",
+                        false);
 
         assertNotEquals(imsiDisclosure, imeiDisclosure);
         assertNotEquals(imsiDisclosure.hashCode(), imeiDisclosure.hashCode());
@@ -55,8 +75,12 @@
 
     @Test
     public void testGetters() {
-        CellularIdentifierDisclosure disclosure = new CellularIdentifierDisclosure(
-                NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, CELLULAR_IDENTIFIER_IMSI, "001001", false);
+        android.telephony.CellularIdentifierDisclosure disclosure =
+                new android.telephony.CellularIdentifierDisclosure(
+                        NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST,
+                        CELLULAR_IDENTIFIER_IMSI,
+                        "001001",
+                        false);
 
         assertEquals(NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, disclosure.getNasProtocolMessage());
         assertEquals(CELLULAR_IDENTIFIER_IMSI, disclosure.getCellularIdentifier());
@@ -66,15 +90,39 @@
 
     @Test
     public void testParcel() {
-        CellularIdentifierDisclosure disclosure = new CellularIdentifierDisclosure(
-                NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, CELLULAR_IDENTIFIER_IMSI, "001001", false);
+        android.telephony.CellularIdentifierDisclosure disclosure =
+                new android.telephony.CellularIdentifierDisclosure(
+                        NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST,
+                        CELLULAR_IDENTIFIER_IMSI,
+                        "001001",
+                        false);
 
         Parcel p = Parcel.obtain();
         disclosure.writeToParcel(p, 0);
         p.setDataPosition(0);
 
-        CellularIdentifierDisclosure fromParcel =
-                CellularIdentifierDisclosure.CREATOR.createFromParcel(p);
+        android.telephony.CellularIdentifierDisclosure fromParcel =
+                android.telephony.CellularIdentifierDisclosure.CREATOR.createFromParcel(p);
         assertEquals(disclosure, fromParcel);
     }
+
+    @Test
+    public void testConvertCellularIdentifierDisclosure() {
+        android.hardware.radio.network.CellularIdentifierDisclosure aidlDisclsoure =
+                new android.hardware.radio.network.CellularIdentifierDisclosure();
+        aidlDisclsoure.plmn = "001001";
+        aidlDisclsoure.identifier = NasProtocolMessage.IDENTITY_RESPONSE;
+        aidlDisclsoure.protocolMessage = CellularIdentifier.IMEI;
+        aidlDisclsoure.isEmergency = true;
+
+        android.telephony.CellularIdentifierDisclosure expectedDisclosure =
+                new android.telephony.CellularIdentifierDisclosure(
+                        NAS_PROTOCOL_MESSAGE_IDENTITY_RESPONSE,
+                        CELLULAR_IDENTIFIER_IMEI,
+                        "001001",
+                        true);
+
+        assertEquals(
+                expectedDisclosure, RILUtils.convertCellularIdentifierDisclosure(aidlDisclsoure));
+    }
 }