Merge "Scan limited service only if VoLTE fails" into main
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 04e3706..9f4922a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -169,9 +169,11 @@
     <!-- Needed to register for UWB state changes for satellite communication -->
     <uses-permission android:name="android.permission.UWB_PRIVILEGED"/>
 
-    <permission android:name="com.android.phone.permission.ACCESS_LAST_KNOWN_CELL_ID"
-                android:label="Access last known cell identity."
-                android:protectionLevel="signature"/>
+    <!-- Needed to bind the domain selection service. -->
+    <uses-permission android:name="android.permission.BIND_DOMAIN_SELECTION_SERVICE" />
+
+    <!-- Needed to send safety center updates for cellular transparency features   -->
+    <uses-permission android:name="android.permission.SEND_SAFETY_CENTER_UPDATE"/>
 
     <application android:name="PhoneApp"
             android:persistent="true"
@@ -576,6 +578,14 @@
             android:name="com.android.internal.telephony.uicc.ShowInstallAppNotificationReceiver"
             android:exported="false"/>
 
+        <receiver
+            android:name=".security.SafetySourceReceiver"
+            android:exported="false">
+            <intent-filter>
+                <action android:name="android.safetycenter.action.REFRESH_SAFETY_SOURCES"/>
+            </intent-filter>
+        </receiver>
+
         <activity
             android:name="com.android.phone.settings.PickSmsSubscriptionActivity"
             android:exported="false"
@@ -628,5 +638,13 @@
             android:multiprocess="false"
             android:singleUser="true"
             android:writePermission="android.permission.MODIFY_PHONE_STATE"/>
+
+        <service android:name="com.android.services.telephony.domainselection.TelephonyDomainSelectionService"
+            android:exported="true"
+            android:permission="android.permission.BIND_DOMAIN_SELECTION_SERVICE">
+            <intent-filter>
+                <action android:name="android.telephony.DomainSelectionService"/>
+            </intent-filter>
+        </service>
     </application>
 </manifest>
diff --git a/OWNERS b/OWNERS
index 53b9401..96033ab 100644
--- a/OWNERS
+++ b/OWNERS
@@ -2,4 +2,4 @@
 
 per-file *SimPhonebookProvider* = file:platform/packages/apps/Contacts:/OWNERS
 
-per-file config.xml=hwangoo@google.com,forestchoi@google.com,avinashmp@google.com,mkoon@google.com,seheele@google.com,radhikaagrawal@google.com
+per-file config.xml=hwangoo@google.com,forestchoi@google.com,avinashmp@google.com,mkoon@google.com,seheele@google.com,radhikaagrawal@google.com,jdyou@google.com
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index c52cb86..76ae668 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -661,7 +661,7 @@
     <string name="description_dial_button" msgid="8614631902795087259">"شماره گیری"</string>
     <string name="description_dialpad_button" msgid="7395114120463883623">"نمایش صفحه شماره گیری"</string>
     <string name="pane_title_emergency_dialpad" msgid="3627372514638694401">"صفحه شماره‌گیری اضطراری"</string>
-    <string name="voicemail_visual_voicemail_switch_title" msgid="6610414098912832120">"پست صوتی دیداری"</string>
+    <string name="voicemail_visual_voicemail_switch_title" msgid="6610414098912832120">"پست صوتی تصویری"</string>
     <string name="voicemail_set_pin_dialog_title" msgid="7005128605986960003">"تنظیم پین"</string>
     <string name="voicemail_change_pin_dialog_title" msgid="4633077715231764435">"تغییر پین"</string>
     <string name="preference_category_ringtone" msgid="8787281191375434976">"آهنگ‌ زنگ و لرزش"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 85a5a93..8b3f378 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -595,7 +595,7 @@
     <string name="singleContactImportedMsg" msgid="3619804066300998934">"Contact importé"</string>
     <string name="failedToImportSingleContactMsg" msgid="228095510489830266">"Échec de l\'importation du contact."</string>
     <string name="hac_mode_title" msgid="4127986689621125468">"Assistance auditive"</string>
-    <string name="hac_mode_summary" msgid="7774989500136009881">"Activer la compatibilité avec les prothèses auditives"</string>
+    <string name="hac_mode_summary" msgid="7774989500136009881">"Activer la compatibilité avec les appareils auditifs"</string>
     <string name="rtt_mode_title" msgid="3075948111362818043">"Appel texte en temps réel"</string>
     <string name="rtt_mode_summary" msgid="8631541375609989562">"Autoriser l\'échange de messages pendant les appels vocaux"</string>
     <string name="rtt_mode_more_information" msgid="587500128658756318">"La fonctionnalité de texte en temps réel vient en aide aux personnes sourdes, malentendantes, qui ont un trouble de la parole, ou qui ont besoin d\'une transcription en plus de la voix.&lt;br&gt; &lt;a href=<xliff:g id="URL">http://support.google.com/mobile?p=telephony_rtt</xliff:g>&gt;En savoir plus&lt;/a&gt;\n       &lt;br&gt;&lt;br&gt; - Les appels texte en temps réel sont enregistrés sous forme transcrite\n       &lt;br&gt; - Le mode texte en temps réel n\'est pas disponible pour les appels vidéo"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index fe39ede..011b30b 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -466,7 +466,7 @@
     <string name="get_pin2" msgid="4221654606863196332">"PIN2 ಅನ್ನು ಟೈಪ್‌ ಮಾಡಿ"</string>
     <string name="name" msgid="1347432469852527784">"ಹೆಸರು"</string>
     <string name="number" msgid="1564053487748491000">"ಸಂಖ್ಯೆ"</string>
-    <string name="save" msgid="983805790346099749">"ಉಳಿಸು"</string>
+    <string name="save" msgid="983805790346099749">"ಸೇವ್ ಮಾಡಿ"</string>
     <string name="add_fdn_contact" msgid="1169713422306640887">"ಸ್ಥಿರ ಡಯಲಿಂಗ್ ಸಂಖ್ಯೆಯನ್ನು ಸೇರಿಸಿ"</string>
     <string name="adding_fdn_contact" msgid="3112531600824361259">"ಸ್ಥಿರ ಡಯಲಿಂಗ್‌‌ ಸಂಖ್ಯೆಯನ್ನು ಸೇರಿಸಲಾಗುತ್ತಿದೆ…"</string>
     <string name="fdn_contact_added" msgid="2840016151693394596">"ಸ್ಥಿರ ಡಯಲಿಂಗ್ ಸಂಖ್ಯೆಯನ್ನು ಸೇರಿಸಲಾಗಿದೆ."</string>
@@ -598,7 +598,7 @@
     <string name="hac_mode_summary" msgid="7774989500136009881">"ಶ್ರವಣ ಸಾಧನ ಹೊಂದಾಣಿಕೆಯನ್ನು ಆನ್‌ ಮಾಡಿ"</string>
     <string name="rtt_mode_title" msgid="3075948111362818043">"ನೈಜ-ಸಮಯ ಪಠ್ಯ (RTT) ಕರೆ"</string>
     <string name="rtt_mode_summary" msgid="8631541375609989562">"ಧ್ವನಿ ಕರೆಯ ಒಳಗೆ ಸಂದೇಶ ಕಳುಹಿಸುವಿಕೆಗೆ ಅನುಮತಿಸಿ"</string>
-    <string name="rtt_mode_more_information" msgid="587500128658756318">"ಕಿವುಡರು, ಆಲಿಸುವಿಕೆಯ ದೋಷಗಳನ್ನು ಹೊಂದಿದವರು, ಮಾತನಾಡುವಿಕೆಯಲ್ಲಿ ದೋಷಗಳನ್ನು ಹೊಂದಿದವರು ಅಥವಾ ಧ್ವನಿ ಮೀರಿ ಬೇರೆ ರೀತಿಯಲ್ಲಿ ಕರೆ ಮಾಡಲು ಕಠಿಣರಾಗಿರುವವರಿಗೆ RTT ಮೋಡ್ ಸಹಾಯ ಮಾಡುತ್ತದೆ.&lt;br&gt; &lt;a href=<xliff:g id="URL">http://support.google.com/mobile?p=telephony_rtt</xliff:g>&gt;ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ&lt;/a&gt;\n   &lt;br&gt;&lt;br&gt; - RTT ಕರೆಗಳನ್ನು ಸಂದೇಶ ಪ್ರತಿಲಿಪಿಗಳಂತೆ ಉಳಿಸಲಾಗಿದೆ \n    &lt;br&gt; - ವೀಡಿಯೊ ಕರೆಗಳಿಗೆ RTT ಲಭ್ಯವಿಲ್ಲ"</string>
+    <string name="rtt_mode_more_information" msgid="587500128658756318">"ಕಿವುಡರು, ಆಲಿಸುವಿಕೆಯ ದೋಷಗಳನ್ನು ಹೊಂದಿದವರು, ಮಾತನಾಡುವಿಕೆಯಲ್ಲಿ ದೋಷಗಳನ್ನು ಹೊಂದಿದವರು ಅಥವಾ ಧ್ವನಿ ಮೀರಿ ಬೇರೆ ರೀತಿಯಲ್ಲಿ ಕರೆ ಮಾಡಲು ಕಠಿಣರಾಗಿರುವವರಿಗೆ RTT ಮೋಡ್ ಸಹಾಯ ಮಾಡುತ್ತದೆ.&lt;br&gt; &lt;a href=<xliff:g id="URL">http://support.google.com/mobile?p=telephony_rtt</xliff:g>&gt;ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ&lt;/a&gt;\n   &lt;br&gt;&lt;br&gt; - RTT ಕರೆಗಳನ್ನು ಸಂದೇಶ ಪ್ರತಿಲಿಪಿಗಳಂತೆ ಸೇವ್ ಮಾಡಲಾಗಿದೆ \n    &lt;br&gt; - ವೀಡಿಯೊ ಕರೆಗಳಿಗೆ RTT ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="no_rtt_when_roaming" msgid="5268008247378355389">"ಗಮನಿಸಿ: ರೋಮಿಂಗ್‌ನಲ್ಲಿ RTT ಲಭ್ಯವಿಲ್ಲ"</string>
   <string-array name="tty_mode_entries">
     <item msgid="3238070884803849303">"TTY ಆಫ್"</item>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 0ab1b47..2c68ef1 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -318,7 +318,7 @@
     <string name="throttle_current_usage" msgid="7483859109708658613">"Податоци кои се користат во тековниот период"</string>
     <string name="throttle_time_frame" msgid="1813452485948918791">"Период на потрошен интернет"</string>
     <string name="throttle_rate" msgid="7641913901133634905">"Политика на стапка на податоци"</string>
-    <string name="throttle_help" msgid="2624535757028809735">"Дознај повеќе"</string>
+    <string name="throttle_help" msgid="2624535757028809735">"Дознајте повеќе"</string>
     <string name="throttle_status_subtext" msgid="1110276415078236687">"<xliff:g id="USED_0">%1$s</xliff:g> (<xliff:g id="USED_1">%2$d</xliff:g> ٪) од максимум <xliff:g id="USED_2">%3$s</xliff:g> за периодот\nСледниот период започнува за <xliff:g id="USED_3">%4$d</xliff:g> дена (<xliff:g id="USED_4">%5$s</xliff:g>)"</string>
     <string name="throttle_data_usage_subtext" msgid="3185429653996709840">"<xliff:g id="USED_0">%1$s</xliff:g> (<xliff:g id="USED_1">%2$d</xliff:g>٪) од <xliff:g id="USED_2">%3$s</xliff:g> максимален период"</string>
     <string name="throttle_data_rate_reduced_subtext" msgid="8369839346277847725">"<xliff:g id="USED_0">%1$s</xliff:g> максимум е надминат\nСтапката на податоци е намалена на <xliff:g id="USED_1">%2$d</xliff:g> Kb/s"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 8576e1f..b4c7573 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -675,7 +675,7 @@
     <string name="sim_description_default" msgid="7474671114363724971">"SIM ကတ်၊ အပေါက်: <xliff:g id="SLOT_ID">%s</xliff:g>"</string>
     <string name="accessibility_settings_activity_title" msgid="7883415189273700298">"အများသုံးနိုင်မှု"</string>
     <string name="status_hint_label_incoming_wifi_call" msgid="2606052595898044071">"အောက်ပါမှ Wi-Fi ခေါ်ခြင်း"</string>
-    <string name="status_hint_label_wifi_call" msgid="942993035689809853">"ဝိုင်ဖိုင်ခေါ်ဆိုမှု"</string>
+    <string name="status_hint_label_wifi_call" msgid="942993035689809853">"Wi-Fi ခေါ်ဆိုမှု"</string>
     <string name="message_decode_error" msgid="1061856591500290887">"စာကို ကုဒ်ဖွင့်နေစဉ် အမှားရှိခဲ့သည်။"</string>
     <string name="callFailed_cdma_activation" msgid="5392057031552253550">"SIM ကဒ်သည် သင့် ဖုန်းဝန်ဆောင်မှုအား အသက်သွင်းခဲ့ပြီး သင့်ဖုန်း၏ ကွန်ယက်ပြင်ပဒေတာသုံးနိုင်စွမ်းအား ပြင်ဆင်မွမ်းမံပြီးဖြစ်၏။"</string>
     <string name="callFailed_cdma_call_limit" msgid="1074219746093031412">"လက်ရှိခေါ်ဆိုမှုများ အလွန်များနေပါသည်။ ခေါ်ဆိုမှုအသစ်တစ်ခု မပြုလုပ်ခင် လက်ရှိဖုန်းခေါ်ဆိုမှုများကို အဆုံးသတ် (သို့) ပေါင်း လိုက်ပါ။"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 10c516c..fd8e728 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -674,8 +674,8 @@
     <string name="sim_description_emergency_calls" msgid="5146872803938897296">"କେବଳ ଜରୁରିକାଳୀନ କଲ୍ ପାଇଁ"</string>
     <string name="sim_description_default" msgid="7474671114363724971">"SIM କାର୍ଡ, ସ୍ଲଟ୍: <xliff:g id="SLOT_ID">%s</xliff:g>"</string>
     <string name="accessibility_settings_activity_title" msgid="7883415189273700298">"ଆକ୍ସେସିବିଲିଟୀ"</string>
-    <string name="status_hint_label_incoming_wifi_call" msgid="2606052595898044071">"ଠାରୁ ୱାଇ-ଫାଇ କଲ୍ କରନ୍ତୁ"</string>
-    <string name="status_hint_label_wifi_call" msgid="942993035689809853">"ୱାଇ-ଫାଇ କଲ୍"</string>
+    <string name="status_hint_label_incoming_wifi_call" msgid="2606052595898044071">"ୱାଇ-ଫାଇ କଲ କରିଛନ୍ତି"</string>
+    <string name="status_hint_label_wifi_call" msgid="942993035689809853">"ୱାଇ-ଫାଇ କଲ"</string>
     <string name="message_decode_error" msgid="1061856591500290887">"ମେସେଜ୍‌କୁ ଡିକୋଡ୍ କରିବା ବେଳେ ଗୋଟିଏ ତ୍ରୁଟି ଦେଖାଦେଲା।"</string>
     <string name="callFailed_cdma_activation" msgid="5392057031552253550">"ଗୋଟିଏ SIM କାର୍ଡ ଆପଣଙ୍କର ସେବାକୁ କାର୍ଯ୍ୟକ୍ଷମ କରିଛି ଏବଂ ଆପଣଙ୍କ ଫୋନ୍‌ର ରୋମିଙ୍ଗ କ୍ଷମତାକୁ ଅପଡେଟ୍ କରିଛି।"</string>
     <string name="callFailed_cdma_call_limit" msgid="1074219746093031412">"ଏଠାରେ ଅନେକ ସକ୍ରିୟ କଲ୍ ଅଛି। ଗୋଟିଏ ନୂଆ କଲ୍‌କୁ ସ୍ଥାପନ କରିବା ପୂର୍ବରୁ ଦୟାକରି ବିଦ୍ୟମାନ ଥିବା କଲ୍‌କୁ ସମାପ୍ତ କିମ୍ବା ମର୍ଜ କରନ୍ତୁ।"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 1f86b13..975cdc7 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -168,7 +168,7 @@
     <string name="vm_change_pin_progress_message" msgid="626015184502739044">"Počakajte."</string>
     <string name="vm_change_pin_error_too_short" msgid="1789139338449945483">"Nova koda PIN je prekratka."</string>
     <string name="vm_change_pin_error_too_long" msgid="3634907034310018954">"Nova koda PIN je predolga."</string>
-    <string name="vm_change_pin_error_too_weak" msgid="8581892952627885719">"Nova koda PIN je prešibka. Zapleteno geslo ne sme vsebovati zaporednih ali ponavljajočih se števk."</string>
+    <string name="vm_change_pin_error_too_weak" msgid="8581892952627885719">"Nova koda PIN je prešibka. Močno geslo ne sme vsebovati zaporednih ali ponavljajočih se števk."</string>
     <string name="vm_change_pin_error_mismatch" msgid="5364847280026257331">"Stara koda PIN se ne ujema."</string>
     <string name="vm_change_pin_error_invalid" msgid="5230002671175580674">"Nova koda PIN vsebuje neveljavne znake."</string>
     <string name="vm_change_pin_error_system_error" msgid="9116483527909681791">"Ni mogoče spremeniti kode PIN"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index dcfa364..7cd4e18 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -337,7 +337,8 @@
         <item>de</item>
     </string-array>
 
-    <!-- Flag specifying whether the AOSP domain selection is enabled or
-         the device should fallback to the modem based domain selection architecture. -->
-    <bool name="config_enable_aosp_domain_selection">false</bool>
+    <!-- The component name(a flattened ComponentName string) for the telephony domain selection
+         service. The device should fallback to the modem based domain selection architecture
+         if this is not configured. -->
+    <string name="config_domain_selection_service_component_name" translatable="false"></string>
 </resources>
diff --git a/src/com/android/phone/DiagnosticDataCollector.java b/src/com/android/phone/DiagnosticDataCollector.java
index e997270..e0b1dac 100644
--- a/src/com/android/phone/DiagnosticDataCollector.java
+++ b/src/com/android/phone/DiagnosticDataCollector.java
@@ -16,7 +16,6 @@
 
 package com.android.phone;
 
-import android.annotation.AnyThread;
 import android.annotation.NonNull;
 import android.annotation.WorkerThread;
 import android.os.DropBoxManager;
@@ -25,7 +24,6 @@
 import android.telephony.AnomalyReporter;
 import android.telephony.TelephonyManager;
 import android.util.Log;
-import java.util.UUID;
 
 import java.io.BufferedReader;
 import java.io.IOException;
@@ -34,6 +32,7 @@
 import java.util.Arrays;
 import java.util.Date;
 import java.util.Locale;
+import java.util.UUID;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 
@@ -75,16 +74,16 @@
     }
 
     public void persistEmergencyDianosticData(@NonNull DataCollectorConfig.Adapter dc,
-            @NonNull TelephonyManager.EmergencyCallDiagnosticParams edp, @NonNull String tag) {
+            @NonNull TelephonyManager.EmergencyCallDiagnosticData ecdData, @NonNull String tag) {
 
-        if (edp.isTelephonyDumpSysCollectionEnabled()) {
+        if (ecdData.isTelephonyDumpsysCollectionEnabled()) {
             persistTelephonyState(dc, tag);
         }
-        if (edp.isTelecomDumpSysCollectionEnabled()) {
+        if (ecdData.isTelecomDumpsysCollectionEnabled()) {
             persistTelecomState(dc, tag);
         }
-        if (edp.isLogcatCollectionEnabled()) {
-            persistLogcat(dc, tag, edp.getLogcatStartTime());
+        if (ecdData.isLogcatCollectionEnabled()) {
+            persistLogcat(dc, tag, ecdData.getLogcatCollectionStartTimeMillis());
         }
     }
 
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 76cf979..7fba651 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -83,7 +83,6 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.phone.settings.SettingsConstants;
 import com.android.phone.vvm.CarrierVvmPackageInstalledReceiver;
-import com.android.services.telephony.domainselection.TelephonyDomainSelectionService;
 import com.android.services.telephony.rcs.TelephonyRcsService;
 
 import java.io.FileDescriptor;
@@ -166,7 +165,6 @@
     public ImsStateCallbackController mImsStateCallbackController;
     public ImsProvisioningController mImsProvisioningController;
     CarrierConfigLoader configLoader;
-    TelephonyDomainSelectionService mDomainSelectionService;
 
     private Phone phoneInEcm;
 
@@ -496,8 +494,9 @@
             // Create DomainSelectionResolver always, but it MUST be initialized only when
             // the device supports AOSP domain selection architecture and
             // has new IRadio that supports its related HAL APIs.
-            DomainSelectionResolver.make(this,
-                    getResources().getBoolean(R.bool.config_enable_aosp_domain_selection));
+            String dssComponentName = getResources().getString(
+                    R.string.config_domain_selection_service_component_name);
+            DomainSelectionResolver.make(this, dssComponentName);
 
             // Initialize the telephony framework
             mFeatureFlags = new FeatureFlagsImpl();
@@ -506,8 +505,7 @@
             // Initialize the DomainSelectionResolver after creating the Phone instance
             // to check the Radio HAL version.
             if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) {
-                mDomainSelectionService = new TelephonyDomainSelectionService(this);
-                DomainSelectionResolver.getInstance().initialize(mDomainSelectionService);
+                DomainSelectionResolver.getInstance().initialize();
                 // Initialize EmergencyStateTracker if domain selection is supported
                 boolean isSuplDdsSwitchRequiredForEmergencyCall = getResources()
                         .getBoolean(R.bool.config_gnss_supl_requires_default_data_for_emergency);
@@ -1390,9 +1388,6 @@
             e.printStackTrace();
         }
         pw.decreaseIndent();
-        if (mDomainSelectionService != null) {
-            mDomainSelectionService.dump(fd, pw, args);
-        }
         pw.decreaseIndent();
         if (mFeatureFlags.reorganizeRoamingNotification()) {
             pw.println("mShownNotificationReasons=" + mShownNotificationReasons);
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index d8d8450..e53a674 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -156,8 +156,8 @@
 import android.telephony.satellite.INtnSignalStrengthCallback;
 import android.telephony.satellite.ISatelliteCapabilitiesCallback;
 import android.telephony.satellite.ISatelliteDatagramCallback;
+import android.telephony.satellite.ISatelliteModemStateCallback;
 import android.telephony.satellite.ISatelliteProvisionStateCallback;
-import android.telephony.satellite.ISatelliteStateCallback;
 import android.telephony.satellite.ISatelliteTransmissionUpdateCallback;
 import android.telephony.satellite.NtnSignalStrength;
 import android.telephony.satellite.NtnSignalStrengthCallback;
@@ -248,6 +248,7 @@
 import com.android.phone.callcomposer.CallComposerPictureTransfer;
 import com.android.phone.callcomposer.ImageData;
 import com.android.phone.satellite.accesscontrol.SatelliteAccessController;
+import com.android.phone.satellite.entitlement.SatelliteEntitlementController;
 import com.android.phone.settings.PickSmsSubscriptionActivity;
 import com.android.phone.slice.SlicePurchaseController;
 import com.android.phone.utils.CarrierAllowListInfo;
@@ -411,6 +412,8 @@
     private static final int MIN_NULL_CIPHER_AND_INTEGRITY_VERSION = 201;
     // Cellular identifier disclosure transparency was added in IRadioNetwork 2.2
     private static final int MIN_IDENTIFIER_DISCLOSURE_VERSION = 202;
+    // Null cipher notification support was added in IRadioNetwork 2.2
+    private static final int MIN_NULL_CIPHER_NOTIFICATION_VERSION = 202;
 
     /** The singleton instance. */
     private static PhoneInterfaceManager sInstance;
@@ -2475,6 +2478,10 @@
         PropertyInvalidatedCache.invalidateCache(TelephonyManager.CACHE_KEY_PHONE_ACCOUNT_TO_SUBID);
         publish();
         CarrierAllowListInfo.loadInstance(mApp);
+
+        // Create the SatelliteEntitlementController singleton, for using the get the
+        // entitlementStatus for satellite service.
+        SatelliteEntitlementController.make(mApp, mFeatureFlags);
     }
 
     @VisibleForTesting
@@ -12566,8 +12573,9 @@
      * @return {@CellIdentity} last known cell identity {@CellIdentity}.
      *
      * Require {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and
-     * com.android.phone.permission.ACCESS_LAST_KNOWN_CELL_ID, otherwise throws
+     * {@link android.Manifest.permission#ACCESS_LAST_KNOWN_CELL_ID}, otherwise throws
      * SecurityException.
+     *
      * If there is current registered network this value will be same as the registered cell
      * identity. If the device goes out of service the previous cell identity is cached and
      * will be returned. If the cache age of the Cell identity is more than 24 hours
@@ -12643,6 +12651,27 @@
         return result;
     }
 
+    /**
+     * Get the aggregated satellite plmn list. This API collects plmn data from multiple sources,
+     * including carrier config, entitlement server, and config update.
+     *
+     * @param subId subId The subscription ID of the carrier.
+     *
+     * @return List of plmns for carrier satellite service. If no plmn is available, empty list will
+     * be returned.
+     *
+     * @throws SecurityException if the caller doesn't have the required permission.
+     */
+    @NonNull public List<String> getSatellitePlmnsForCarrier(int subId) {
+        enforceSatelliteCommunicationPermission("getSatellitePlmnsForCarrier");
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return mSatelliteController.getSatellitePlmnsForCarrier(subId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     @Override
     public void setVoiceServiceStateOverride(int subId, boolean hasService, String callingPackage) {
         // Only telecom (and shell, for CTS purposes) is allowed to call this method.
@@ -12795,6 +12824,17 @@
         }
     }
 
+    private void checkForNullCipherNotificationSupport() {
+        if (getHalVersion(HAL_SERVICE_NETWORK) < MIN_NULL_CIPHER_NOTIFICATION_VERSION) {
+            throw new UnsupportedOperationException(
+                    "Null cipher notification operations require HAL 2.2 or above");
+        }
+        if (!getDefaultPhone().isNullCipherNotificationSupported()) {
+            throw new UnsupportedOperationException(
+                    "Null cipher notification operations unsupported by modem");
+        }
+    }
+
     /**
      * Get the SIM state for the slot index.
      * For Remote-SIMs, this method returns {@link IccCardConstants.State#UNKNOWN}
@@ -12836,22 +12876,26 @@
             long logcatStartTimestampMillis, boolean enableTelecomDump,
             boolean enableTelephonyDump) {
         DropBoxManager db = mApp.getSystemService(DropBoxManager.class);
-        TelephonyManager.EmergencyCallDiagnosticParams edp =
-                new TelephonyManager.EmergencyCallDiagnosticParams();
-        edp.setLogcatCollection(enableLogcat, logcatStartTimestampMillis);
-        edp.setTelephonyDumpSysCollection(enableTelephonyDump);
-        edp.setTelecomDumpSysCollection(enableTelecomDump);
-        Log.d(LOG_TAG, "persisting with Params " + edp.toString());
+        TelephonyManager.EmergencyCallDiagnosticData.Builder ecdDataBuilder =
+                new TelephonyManager.EmergencyCallDiagnosticData.Builder();
+        ecdDataBuilder
+                .setTelecomDumpsysCollectionEnabled(enableTelecomDump)
+                .setTelephonyDumpsysCollectionEnabled(enableTelephonyDump);
+        if (enableLogcat) {
+            ecdDataBuilder.setLogcatCollectionStartTimeMillis(logcatStartTimestampMillis);
+        }
+        TelephonyManager.EmergencyCallDiagnosticData ecdData = ecdDataBuilder.build();
+        Log.d(LOG_TAG, "persisting with Params " + ecdData.toString());
         DiagnosticDataCollector ddc = new DiagnosticDataCollector(Runtime.getRuntime(),
                 Executors.newCachedThreadPool(), db,
                 mApp.getSystemService(ActivityManager.class).isLowRamDevice());
-        ddc.persistEmergencyDianosticData(new DataCollectorConfig.Adapter(), edp, dropboxTag);
+        ddc.persistEmergencyDianosticData(new DataCollectorConfig.Adapter(), ecdData, dropboxTag);
     }
 
     /**
      * Request telephony to persist state for debugging emergency call failures.
      *
-     * @param dropBoxTag                 Tag to use when persisting data to dropbox service.
+     * @param dropboxTag                 Tag to use when persisting data to dropbox service.
      * @param enableLogcat               whether to collect logcat output
      * @param logcatStartTimestampMillis timestamp from when logcat buffers would be persisted
      * @param enableTelecomDump          whether to collect telecom dumpsys
@@ -12964,34 +13008,41 @@
     public void requestSatelliteEnabled(int subId, boolean enableSatellite, boolean enableDemoMode,
             @NonNull IIntegerConsumer callback) {
         enforceSatelliteCommunicationPermission("requestSatelliteEnabled");
-        ResultReceiver resultReceiver = new ResultReceiver(mMainThreadHandler) {
-            @Override
-            protected void onReceiveResult(int resultCode, Bundle resultData) {
-                Log.d(LOG_TAG, "Satellite access restriction resultCode=" + resultCode
-                        + ", resultData=" + resultData);
-                boolean isAllowed = false;
-                Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
-                if (resultCode == SATELLITE_RESULT_SUCCESS) {
-                    if (resultData != null
-                            && resultData.containsKey(KEY_SATELLITE_COMMUNICATION_ALLOWED)) {
-                        isAllowed = resultData.getBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED);
+        if (enableSatellite) {
+            ResultReceiver resultReceiver = new ResultReceiver(mMainThreadHandler) {
+                @Override
+                protected void onReceiveResult(int resultCode, Bundle resultData) {
+                    Log.d(LOG_TAG, "Satellite access restriction resultCode=" + resultCode
+                            + ", resultData=" + resultData);
+                    boolean isAllowed = false;
+                    Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(
+                            callback::accept);
+                    if (resultCode == SATELLITE_RESULT_SUCCESS) {
+                        if (resultData != null
+                                && resultData.containsKey(KEY_SATELLITE_COMMUNICATION_ALLOWED)) {
+                            isAllowed = resultData.getBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED);
+                        } else {
+                            loge("KEY_SATELLITE_COMMUNICATION_ALLOWED does not exist.");
+                        }
                     } else {
-                        loge("KEY_SATELLITE_COMMUNICATION_ALLOWED does not exist.");
+                        result.accept(resultCode);
+                        return;
                     }
-                } else {
-                    result.accept(resultCode);
-                    return;
+                    if (isAllowed) {
+                        mSatelliteController.requestSatelliteEnabled(
+                                subId, enableSatellite, enableDemoMode, callback);
+                    } else {
+                        result.accept(SATELLITE_RESULT_ACCESS_BARRED);
+                    }
                 }
-                if (isAllowed) {
-                    mSatelliteController.requestSatelliteEnabled(
-                            subId, enableSatellite, enableDemoMode, callback);
-                } else {
-                    result.accept(SATELLITE_RESULT_ACCESS_BARRED);
-                }
-            }
-        };
-        mSatelliteAccessController.requestIsSatelliteCommunicationAllowedForCurrentLocation(
-                subId, resultReceiver);
+            };
+            mSatelliteAccessController.requestIsCommunicationAllowedForCurrentLocation(
+                    subId, resultReceiver);
+        } else {
+            // No need to check if satellite is allowed at current location when disabling satellite
+            mSatelliteController.requestSatelliteEnabled(
+                    subId, enableSatellite, enableDemoMode, callback);
+        }
     }
 
     /**
@@ -13195,7 +13246,7 @@
      */
     @Override
     @SatelliteManager.SatelliteResult public int registerForSatelliteModemStateChanged(int subId,
-            @NonNull ISatelliteStateCallback callback) {
+            @NonNull ISatelliteModemStateCallback callback) {
         enforceSatelliteCommunicationPermission("registerForSatelliteModemStateChanged");
         return mSatelliteController.registerForSatelliteModemStateChanged(subId, callback);
     }
@@ -13206,15 +13257,15 @@
      *
      * @param subId The subId of the subscription to unregister for satellite modem state changed.
      * @param callback The callback that was passed to
-     *                 {@link #registerForSatelliteModemStateChanged(int, ISatelliteStateCallback)}.
+     * {@link #registerForModemStateChanged(int, ISatelliteModemStateCallback)}.
      *
      * @throws SecurityException if the caller doesn't have the required permission.
      */
     @Override
-    public void unregisterForSatelliteModemStateChanged(int subId,
-            @NonNull ISatelliteStateCallback callback) {
-        enforceSatelliteCommunicationPermission("unregisterForSatelliteModemStateChanged");
-        mSatelliteController.unregisterForSatelliteModemStateChanged(subId, callback);
+    public void unregisterForModemStateChanged(int subId,
+            @NonNull ISatelliteModemStateCallback callback) {
+        enforceSatelliteCommunicationPermission("unregisterForModemStateChanged");
+        mSatelliteController.unregisterForModemStateChanged(subId, callback);
     }
 
     /**
@@ -13228,10 +13279,10 @@
      * @throws SecurityException if the caller doesn't have the required permission.
      */
     @Override
-    @SatelliteManager.SatelliteResult public int registerForSatelliteDatagram(int subId,
+    @SatelliteManager.SatelliteResult public int registerForIncomingDatagram(int subId,
             @NonNull ISatelliteDatagramCallback callback) {
-        enforceSatelliteCommunicationPermission("registerForSatelliteDatagram");
-        return mSatelliteController.registerForSatelliteDatagram(subId, callback);
+        enforceSatelliteCommunicationPermission("registerForIncomingDatagram");
+        return mSatelliteController.registerForIncomingDatagram(subId, callback);
     }
 
     /**
@@ -13240,15 +13291,15 @@
      *
      * @param subId The subId of the subscription to unregister for incoming satellite datagrams.
      * @param callback The callback that was passed to
-     *                 {@link #registerForSatelliteDatagram(int, ISatelliteDatagramCallback)}.
+     *                 {@link #registerForIncomingDatagram(int, ISatelliteDatagramCallback)}.
      *
      * @throws SecurityException if the caller doesn't have the required permission.
      */
     @Override
-    public void unregisterForSatelliteDatagram(int subId,
+    public void unregisterForIncomingDatagram(int subId,
             @NonNull ISatelliteDatagramCallback callback) {
-        enforceSatelliteCommunicationPermission("unregisterForSatelliteDatagram");
-        mSatelliteController.unregisterForSatelliteDatagram(subId, callback);
+        enforceSatelliteCommunicationPermission("unregisterForIncomingDatagram");
+        mSatelliteController.unregisterForIncomingDatagram(subId, callback);
     }
 
     /**
@@ -13263,10 +13314,9 @@
      *
      * @throws SecurityException if the caller doesn't have required permission.
      */
-    @Override
-    public void pollPendingSatelliteDatagrams(int subId, IIntegerConsumer callback) {
-        enforceSatelliteCommunicationPermission("pollPendingSatelliteDatagrams");
-        mSatelliteController.pollPendingSatelliteDatagrams(subId, callback);
+    public void pollPendingDatagrams(int subId, IIntegerConsumer callback) {
+        enforceSatelliteCommunicationPermission("pollPendingDatagrams");
+        mSatelliteController.pollPendingDatagrams(subId, callback);
     }
 
     /**
@@ -13288,12 +13338,12 @@
      * @throws SecurityException if the caller doesn't have required permission.
      */
     @Override
-    public void sendSatelliteDatagram(int subId, @SatelliteManager.DatagramType int datagramType,
+    public void sendDatagram(int subId, @SatelliteManager.DatagramType int datagramType,
             @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI,
             @NonNull IIntegerConsumer callback) {
-        enforceSatelliteCommunicationPermission("sendSatelliteDatagram");
-        mSatelliteController.sendSatelliteDatagram(subId, datagramType, datagram,
-                needFullScreenPointingUI, callback);
+        enforceSatelliteCommunicationPermission("sendDatagram");
+        mSatelliteController.sendDatagram(subId, datagramType, datagram, needFullScreenPointingUI,
+                callback);
     }
 
     /**
@@ -13308,12 +13358,11 @@
      * @throws SecurityException if the caller doesn't have the required permission.
      */
     @Override
-    public void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId,
+    public void requestIsCommunicationAllowedForCurrentLocation(int subId,
             @NonNull ResultReceiver result) {
-        enforceSatelliteCommunicationPermission(
-                "requestIsSatelliteCommunicationAllowedForCurrentLocation");
-        mSatelliteAccessController.requestIsSatelliteCommunicationAllowedForCurrentLocation(
-                subId, result);
+        enforceSatelliteCommunicationPermission("requestIsCommunicationAllowedForCurrentLocation");
+        mSatelliteAccessController.requestIsCommunicationAllowedForCurrentLocation(subId,
+                result);
     }
 
     /**
@@ -13358,13 +13407,13 @@
      *
      * @throws SecurityException if the caller doesn't have required permission.
      */
-    public void addSatelliteAttachRestrictionForCarrier(int subId,
+    public void addAttachRestrictionForCarrier(int subId,
             @SatelliteManager.SatelliteCommunicationRestrictionReason int reason,
             @NonNull IIntegerConsumer callback) {
-        enforceSatelliteCommunicationPermission("addSatelliteAttachRestrictionForCarrier");
+        enforceSatelliteCommunicationPermission("addAttachRestrictionForCarrier");
         final long identity = Binder.clearCallingIdentity();
         try {
-            mSatelliteController.addSatelliteAttachRestrictionForCarrier(subId, reason, callback);
+            mSatelliteController.addAttachRestrictionForCarrier(subId, reason, callback);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -13381,14 +13430,13 @@
      *
      * @throws SecurityException if the caller doesn't have required permission.
      */
-    public void removeSatelliteAttachRestrictionForCarrier(int subId,
+    public void removeAttachRestrictionForCarrier(int subId,
             @SatelliteManager.SatelliteCommunicationRestrictionReason int reason,
             @NonNull IIntegerConsumer callback) {
-        enforceSatelliteCommunicationPermission("removeSatelliteAttachRestrictionForCarrier");
+        enforceSatelliteCommunicationPermission("removeAttachRestrictionForCarrier");
         final long identity = Binder.clearCallingIdentity();
         try {
-            mSatelliteController.removeSatelliteAttachRestrictionForCarrier(subId, reason,
-                    callback);
+            mSatelliteController.removeAttachRestrictionForCarrier(subId, reason, callback);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -13404,13 +13452,13 @@
      *
      * @throws SecurityException if the caller doesn't have the required permission.
      */
-    public @NonNull int[] getSatelliteAttachRestrictionReasonsForCarrier(
+    public @NonNull int[] getAttachRestrictionReasonsForCarrier(
             int subId) {
-        enforceSatelliteCommunicationPermission("getSatelliteAttachRestrictionReasonsForCarrier");
+        enforceSatelliteCommunicationPermission("getAttachRestrictionReasonsForCarrier");
         final long identity = Binder.clearCallingIdentity();
         try {
             Set<Integer> reasonSet =
-                    mSatelliteController.getSatelliteAttachRestrictionReasonsForCarrier(subId);
+                    mSatelliteController.getAttachRestrictionReasonsForCarrier(subId);
             return reasonSet.stream().mapToInt(i->i).toArray();
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -13498,12 +13546,12 @@
      * @throws SecurityException if the caller doesn't have required permission.
      */
     @Override
-    @SatelliteManager.SatelliteResult public int registerForSatelliteCapabilitiesChanged(
+    @SatelliteManager.SatelliteResult public int registerForCapabilitiesChanged(
             int subId, @NonNull ISatelliteCapabilitiesCallback callback) {
-        enforceSatelliteCommunicationPermission("registerForSatelliteCapabilitiesChanged");
+        enforceSatelliteCommunicationPermission("registerForCapabilitiesChanged");
         final long identity = Binder.clearCallingIdentity();
         try {
-            return mSatelliteController.registerForSatelliteCapabilitiesChanged(subId, callback);
+            return mSatelliteController.registerForCapabilitiesChanged(subId, callback);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -13515,17 +13563,17 @@
      *
      * @param subId The subId of the subscription to unregister for satellite capabilities change.
      * @param callback The callback that was passed to.
-     * {@link #registerForSatelliteCapabilitiesChanged(int, ISatelliteCapabilitiesCallback)}.
+     * {@link #registerForCapabilitiesChanged(int, ISatelliteCapabilitiesCallback)}.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      */
     @Override
-    public void unregisterForSatelliteCapabilitiesChanged(
-            int subId, @NonNull ISatelliteCapabilitiesCallback callback) {
-        enforceSatelliteCommunicationPermission("unregisterForSatelliteCapabilitiesChanged");
+    public void unregisterForCapabilitiesChanged(int subId,
+            @NonNull ISatelliteCapabilitiesCallback callback) {
+        enforceSatelliteCommunicationPermission("unregisterForCapabilitiesChanged");
         final long identity = Binder.clearCallingIdentity();
         try {
-            mSatelliteController.unregisterForSatelliteCapabilitiesChanged(subId, callback);
+            mSatelliteController.unregisterForCapabilitiesChanged(subId, callback);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -13645,6 +13693,25 @@
     }
 
     /**
+     * This API can be used in only testing to override oem-enabled satellite provision status.
+     *
+     * @param reset {@code true} mean the overriding status should not be used, {@code false}
+     *              otherwise.
+     * @param isProvisioned The overriding provision status.
+     * @return {@code true} if the provision status is set successfully, {@code false} otherwise.
+     */
+    public boolean setOemEnabledSatelliteProvisionStatus(boolean reset, boolean isProvisioned) {
+        Log.d(LOG_TAG, "setOemEnabledSatelliteProvisionStatus - reset=" + reset
+                + ", isProvisioned=" + isProvisioned);
+        TelephonyPermissions.enforceShellOnly(
+                Binder.getCallingUid(), "setOemEnabledSatelliteProvisionStatus");
+        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp,
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+                "setOemEnabledSatelliteProvisionStatus");
+        return mSatelliteController.setOemEnabledSatelliteProvisionStatus(reset, isProvisioned);
+    }
+
+    /**
      * This API should be used by only CTS tests to forcefully set telephony country codes.
      *
      * @return {@code true} if the country code is set successfully, {@code false} otherwise.
@@ -13720,6 +13787,62 @@
     }
 
     /**
+     * Sets the service defined in ComponentName to be bound.
+     *
+     * This should only be used for testing.
+     * @return {@code true} if the DomainSelectionService to bind to was set,
+     *         {@code false} otherwise.
+     */
+    @Override
+    public boolean setDomainSelectionServiceOverride(ComponentName componentName) {
+        Log.i(LOG_TAG, "setDomainSelectionServiceOverride component=" + componentName);
+
+        TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(),
+                "setDomainSelectionServiceOverride");
+        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp,
+                getDefaultSubscription(), "setDomainSelectionServiceOverride");
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) {
+                return DomainSelectionResolver.getInstance()
+                        .setDomainSelectionServiceOverride(componentName);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+        return false;
+    }
+
+    /**
+     * Clears the DomainSelectionService override.
+     *
+     * This should only be used for testing.
+     * @return {@code true} if the DomainSelectionService override was cleared,
+     *         {@code false} otherwise.
+     */
+    @Override
+    public boolean clearDomainSelectionServiceOverride() {
+        Log.i(LOG_TAG, "clearDomainSelectionServiceOverride");
+
+        TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(),
+                "clearDomainSelectionServiceOverride");
+        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp,
+                getDefaultSubscription(), "clearDomainSelectionServiceOverride");
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) {
+                return DomainSelectionResolver.getInstance()
+                        .clearDomainSelectionServiceOverride();
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+        return false;
+    }
+
+    /**
      * Enable or disable notifications sent for cellular identifier disclosure events.
      *
      * Disclosure events are defined as instances where a device has sent a cellular identifier
@@ -13760,6 +13883,49 @@
     }
 
     /**
+     * Enables or disables notifications sent when cellular null cipher or integrity algorithms
+     * are in use by the cellular modem.
+     *
+     * @throws IllegalStateException if the Telephony process is not currently available
+     * @throws SecurityException if the caller does not have the required privileges
+     * @throws UnsupportedOperationException if the modem does not support reporting on ciphering
+     * and integrity algorithms in use
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    public void setNullCipherNotificationsEnabled(boolean enable) {
+        enforceModifyPermission();
+        checkForNullCipherNotificationSupport();
+
+        SharedPreferences.Editor editor = mTelephonySharedPreferences.edit();
+        editor.putBoolean(Phone.PREF_NULL_CIPHER_NOTIFICATIONS_ENABLED, enable);
+        editor.apply();
+
+        // Each phone instance is responsible for updating its respective modem immediately
+        // after a preference change.
+        for (Phone phone : PhoneFactory.getPhones()) {
+            phone.handleNullCipherNotificationPreferenceChanged();
+        }
+    }
+
+    /**
+     * Get whether notifications are enabled for null cipher or integrity algorithms in use by the
+     * cellular modem.
+     *
+     * @throws IllegalStateException if the Telephony process is not currently available
+     * @throws SecurityException if the caller does not have the required privileges
+     * @throws UnsupportedOperationException if the modem does not support reporting on ciphering
+     * and integrity algorithms in use
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public boolean isNullCipherNotificationsEnabled() {
+        enforceReadPrivilegedPermission("isNullCipherNotificationsEnabled");
+        checkForNullCipherNotificationSupport();
+        return getDefaultPhone().getNullCipherNotificationsPreferenceEnabled();
+    }
+
+    /**
      * Check whether the caller (or self, if not processing an IPC) can read device identifiers.
      *
      * <p>This method behaves in one of the following ways:
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index 80b7cf6..3e3d31d 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -26,6 +26,7 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.ComponentName;
 import android.content.Context;
 import android.net.Uri;
 import android.os.Binder;
@@ -197,9 +198,15 @@
     private static final String SET_COUNTRY_CODES = "set-country-codes";
     private static final String SET_SATELLITE_ACCESS_CONTROL_OVERLAY_CONFIGS =
             "set-satellite-access-control-overlay-configs";
+    private static final String SET_OEM_ENABLED_SATELLITE_PROVISION_STATUS =
+            "set-oem-enabled-satellite-provision-status";
     private static final String SET_SHOULD_SEND_DATAGRAM_TO_MODEM_IN_DEMO_MODE =
             "set-should-send-datagram-to-modem-in-demo-mode";
 
+    private static final String DOMAIN_SELECTION_SUBCOMMAND = "domainselection";
+    private static final String DOMAIN_SELECTION_SET_SERVICE_OVERRIDE = "set-dss-override";
+    private static final String DOMAIN_SELECTION_CLEAR_SERVICE_OVERRIDE = "clear-dss-override";
+
     private static final String INVALID_ENTRY_ERROR = "An emergency number (only allow '0'-'9', "
             + "'*', '#' or '+') needs to be specified after -a in the command ";
 
@@ -380,6 +387,8 @@
                 return setCarrierServicePackageOverride();
             case CLEAR_CARRIER_SERVICE_PACKAGE_OVERRIDE:
                 return clearCarrierServicePackageOverride();
+            case DOMAIN_SELECTION_SUBCOMMAND:
+                return handleDomainSelectionCommand();
             case SET_SATELLITE_SERVICE_PACKAGE_NAME:
                 return handleSetSatelliteServicePackageNameCommand();
             case SET_SATELLITE_GATEWAY_SERVICE_PACKAGE_NAME:
@@ -398,6 +407,8 @@
                 return handleSetSatelliteAccessControlOverlayConfigs();
             case SET_COUNTRY_CODES:
                 return handleSetCountryCodes();
+            case SET_OEM_ENABLED_SATELLITE_PROVISION_STATUS:
+                return handleSetOemEnabledSatelliteProvisionStatus();
             default: {
                 return handleDefaultCommands(cmd);
             }
@@ -452,6 +463,7 @@
         onHelpRadio();
         onHelpImei();
         onHelpSatellite();
+        onHelpDomainSelection();
     }
 
     private void onHelpD2D() {
@@ -824,6 +836,10 @@
         pw.println("      -c: the cached network country code ISOs.");
         pw.println("      -l: the location country code ISO.");
         pw.println("      -t: the update timestamp nanos of the location country code.");
+        pw.println("  set-oem-enabled-satellite-provision-status [-p true/false]");
+        pw.println("    Sets the OEM-enabled satellite provision status. Options are:");
+        pw.println("      -p: the overriding satellite provision status. If no option is ");
+        pw.println("          specified, reset the overridden provision status.");
     }
 
     private void onHelpImei() {
@@ -835,6 +851,15 @@
         pw.println("          is specified, it will choose the default voice SIM slot.");
     }
 
+    private void onHelpDomainSelection() {
+        PrintWriter pw = getOutPrintWriter();
+        pw.println("Domain Selection Commands:");
+        pw.println("  domainselection set-dss-override COMPONENT_NAME");
+        pw.println("    Sets the service defined in COMPONENT_NAME to be bound");
+        pw.println("  domainselection clear-dss-override");
+        pw.println("    Clears DomainSelectionService override.");
+    }
+
     private int handleImsCommand() {
         String arg = getNextArg();
         if (arg == null) {
@@ -3533,6 +3558,43 @@
         return 0;
     }
 
+    private int handleSetOemEnabledSatelliteProvisionStatus() {
+        PrintWriter errPw = getErrPrintWriter();
+        boolean isProvisioned = false;
+        boolean reset = true;
+
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            switch (opt) {
+                case "-p": {
+                    try {
+                        isProvisioned = Boolean.parseBoolean(getNextArgRequired());
+                        reset = false;
+                    } catch (Exception e) {
+                        errPw.println("setOemEnabledSatelliteProvisionStatus requires a boolean "
+                                + "after -p indicating provision status");
+                        return -1;
+                    }
+                }
+            }
+        }
+        Log.d(LOG_TAG, "setOemEnabledSatelliteProvisionStatus: reset=" + reset
+                + ", isProvisioned=" + isProvisioned);
+
+        try {
+            boolean result = mInterface.setOemEnabledSatelliteProvisionStatus(reset, isProvisioned);
+            if (VDBG) {
+                Log.v(LOG_TAG, "setOemEnabledSatelliteProvisionStatus result = " + result);
+            }
+            getOutPrintWriter().println(result);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "setOemEnabledSatelliteProvisionStatus: error = " + e.getMessage());
+            errPw.println("Exception: " + e.getMessage());
+            return -1;
+        }
+        return 0;
+    }
+
     /**
      * Sample inputStr = "US,UK,CA;2,1,3"
      * Sample output: {[US,2], [UK,1], [CA,3]}
@@ -3699,6 +3761,66 @@
         return 0;
     }
 
+    private int handleDomainSelectionCommand() {
+        String arg = getNextArg();
+        if (arg == null) {
+            onHelpDomainSelection();
+            return 0;
+        }
+
+        switch (arg) {
+            case DOMAIN_SELECTION_SET_SERVICE_OVERRIDE: {
+                return handleDomainSelectionSetServiceOverrideCommand();
+            }
+            case DOMAIN_SELECTION_CLEAR_SERVICE_OVERRIDE: {
+                return handleDomainSelectionClearServiceOverrideCommand();
+            }
+        }
+
+        return -1;
+    }
+
+    // domainselection set-dss-override
+    private int handleDomainSelectionSetServiceOverrideCommand() {
+        PrintWriter errPw = getErrPrintWriter();
+
+        String componentName = getNextArg();
+
+        try {
+            boolean result = mInterface.setDomainSelectionServiceOverride(
+                    ComponentName.unflattenFromString(componentName));
+            if (VDBG) {
+                Log.v(LOG_TAG, "domainselection set-dss-override "
+                        + componentName + ", result=" + result);
+            }
+            getOutPrintWriter().println(result);
+        } catch (Exception e) {
+            Log.w(LOG_TAG, "domainselection set-dss-override "
+                    + componentName + ", error=" + e.getMessage());
+            errPw.println("Exception: " + e.getMessage());
+            return -1;
+        }
+        return 0;
+    }
+
+    // domainselection clear-dss-override
+    private int handleDomainSelectionClearServiceOverrideCommand() {
+        PrintWriter errPw = getErrPrintWriter();
+
+        try {
+            boolean result = mInterface.clearDomainSelectionServiceOverride();
+            if (VDBG) {
+                Log.v(LOG_TAG, "domainselection clear-dss-override result=" + result);
+            }
+            getOutPrintWriter().println(result);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "domainselection clear-dss-override error=" + e.getMessage());
+            errPw.println("Exception: " + e.getMessage());
+            return -1;
+        }
+        return 0;
+    }
+
     /**
      * Building the string that can be used to build the JsonObject which supports to stub the data
      * in CarrierAllowListInfo for CTS testing. sample format is like
diff --git a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
index 047c0a3..76032f8 100644
--- a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
+++ b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
@@ -230,7 +230,7 @@
      *               for the current location if the request is successful or an error code
      *               if the request failed.
      */
-    public void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId,
+    public void requestIsCommunicationAllowedForCurrentLocation(int subId,
             @NonNull ResultReceiver result) {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
             logd("oemEnabledSatelliteFlag is disabled");
@@ -392,7 +392,7 @@
         synchronized (mLock) {
             mSatelliteAllowResultReceivers.add(requestArguments.second);
             if (mSatelliteAllowResultReceivers.size() > 1) {
-                logd("requestIsSatelliteCommunicationAllowedForCurrentLocation is already being "
+                logd("requestIsCommunicationAllowedForCurrentLocation is already being "
                         + "processed");
                 return;
             }
diff --git a/src/com/android/phone/satellite/entitlement/SatelliteEntitlementApi.java b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementApi.java
new file mode 100644
index 0000000..c856eb5
--- /dev/null
+++ b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementApi.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2024 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.phone.satellite.entitlement;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+
+import com.android.libraries.entitlement.CarrierConfig;
+import com.android.libraries.entitlement.ServiceEntitlement;
+import com.android.libraries.entitlement.ServiceEntitlementException;
+import com.android.libraries.entitlement.ServiceEntitlementRequest;
+
+/**
+ * Class that sends an HTTP request to the entitlement server and processes the response to check
+ * whether satellite service can be activated.
+ * @hide
+ */
+public class SatelliteEntitlementApi {
+    @NonNull
+    private final ServiceEntitlement mServiceEntitlement;
+    private final Context mContext;
+
+    public SatelliteEntitlementApi(@NonNull Context context,
+            @NonNull PersistableBundle carrierConfig, @NonNull int subId) {
+        mContext = context;
+        mServiceEntitlement = new ServiceEntitlement(mContext,
+                getCarrierConfigFromEntitlementServerUrl(carrierConfig), subId);
+    }
+
+    /**
+     * Returns satellite entitlement result from the entitlement server.
+     * @return The SatelliteEntitlementResult
+     */
+    public SatelliteEntitlementResult checkEntitlementStatus() throws ServiceEntitlementException {
+        ServiceEntitlementRequest.Builder requestBuilder = ServiceEntitlementRequest.builder();
+        requestBuilder.setAcceptContentType(ServiceEntitlementRequest.ACCEPT_CONTENT_TYPE_JSON);
+        ServiceEntitlementRequest request = requestBuilder.build();
+
+        String response = mServiceEntitlement.queryEntitlementStatus(
+                ServiceEntitlement.APP_SATELLITE_ENTITLEMENT, request);
+        SatelliteEntitlementResponse satelliteEntitlementResponse =
+                new SatelliteEntitlementResponse(response);
+        return new SatelliteEntitlementResult(satelliteEntitlementResponse.getEntitlementStatus(),
+                satelliteEntitlementResponse.getPlmnAllowed());
+    }
+
+    @NonNull
+    private CarrierConfig getCarrierConfigFromEntitlementServerUrl(
+            @NonNull PersistableBundle carrierConfig) {
+        String entitlementServiceUrl = carrierConfig.getString(
+                CarrierConfigManager.ImsServiceEntitlement.KEY_ENTITLEMENT_SERVER_URL_STRING,
+                "");
+        return CarrierConfig.builder().setServerUrl(entitlementServiceUrl).build();
+    }
+}
diff --git a/src/com/android/phone/satellite/entitlement/SatelliteEntitlementController.java b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementController.java
new file mode 100644
index 0000000..94362a0
--- /dev/null
+++ b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementController.java
@@ -0,0 +1,542 @@
+/*
+ * Copyright (C) 2024 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.phone.satellite.entitlement;
+
+import static com.android.phone.satellite.entitlement.SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_ENABLED;
+
+import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME;
+import static java.time.temporal.ChronoUnit.SECONDS;
+
+import android.annotation.NonNull;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.Rlog;
+import android.telephony.SubscriptionManager;
+
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.ExponentialBackoff;
+import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.satellite.SatelliteController;
+import com.android.internal.telephony.subscription.SubscriptionManagerService;
+import com.android.libraries.entitlement.ServiceEntitlementException;
+
+import java.time.Instant;
+import java.time.format.DateTimeParseException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * This class query the entitlement server to receive values for satellite services and passes the
+ * response to the {@link com.android.internal.telephony.satellite.SatelliteController}.
+ * @hide
+ */
+public class SatelliteEntitlementController extends Handler {
+    private static final String TAG = "SatelliteEntitlementController";
+    @NonNull private static SatelliteEntitlementController sInstance;
+    /** Message code used in handleMessage() */
+    private static final int CMD_START_QUERY_ENTITLEMENT = 1;
+    private static final int CMD_RETRY_QUERY_ENTITLEMENT = 2;
+    private static final int CMD_STOP_RETRY_QUERY_ENTITLEMENT = 3;
+
+    /** Retry on next trigger event. */
+    private static final int HTTP_RESPONSE_500 = 500;
+    /** Retry after the time specified in the “Retry-After” header. After retry count doesn't exceed
+     * MAX_RETRY_COUNT. */
+    private static final int HTTP_RESPONSE_503 = 503;
+    /** Default query refresh time is 1 month. */
+
+    private static final int DEFAULT_QUERY_REFRESH_DAYS = 30;
+    private static final long INITIAL_DELAY_MILLIS = TimeUnit.MINUTES.toMillis(10); // 10 min
+    private static final long MAX_DELAY_MILLIS = TimeUnit.DAYS.toMillis(5); // 5 days
+    private static final int MULTIPLIER = 2;
+    private static final int MAX_RETRY_COUNT = 5;
+    @NonNull private final SubscriptionManagerService mSubscriptionManagerService;
+    @NonNull private final CarrierConfigManager mCarrierConfigManager;
+    @NonNull private final CarrierConfigManager.CarrierConfigChangeListener
+            mCarrierConfigChangeListener;
+    @NonNull private final ConnectivityManager mConnectivityManager;
+    @NonNull private final ConnectivityManager.NetworkCallback mNetworkCallback;
+    @NonNull private final BroadcastReceiver mReceiver;
+    @NonNull private final Context mContext;
+    private final Object mLock = new Object();
+    /** Map key : subId, value : ExponentialBackoff. */
+    private Map<Integer, ExponentialBackoff> mExponentialBackoffPerSub = new HashMap<>();
+    /** Map key : subId, value : SatelliteEntitlementResult. */
+    private Map<Integer, SatelliteEntitlementResult> mSatelliteEntitlementResultPerSub =
+            new HashMap<>();
+    /** Map key : subId, value : the last query time to millis. */
+    private Map<Integer, Long> mLastQueryTimePerSub = new HashMap<>();
+    /** Map key : subId, value : Count the number of retries caused by the 'ExponentialBackoff' and
+     * '503 error case with the Retry-After header'. */
+    private Map<Integer, Integer> mRetryCountPerSub = new HashMap<>();
+
+    /**
+     * Create the SatelliteEntitlementController singleton instance.
+     * @param context      The Context to use to create the SatelliteEntitlementController.
+     * @param featureFlags The feature flag.
+     */
+    public static void make(@NonNull Context context, @NonNull FeatureFlags featureFlags) {
+        if (!featureFlags.carrierEnabledSatelliteFlag()) {
+            logd("carrierEnabledSatelliteFlag is disabled. don't created this.");
+            return;
+        }
+        if (sInstance == null) {
+            HandlerThread handlerThread = new HandlerThread(TAG);
+            handlerThread.start();
+            sInstance =
+                    new SatelliteEntitlementController(context, handlerThread.getLooper());
+        }
+    }
+
+    /**
+     * Create a SatelliteEntitlementController to request query to the entitlement server for
+     * satellite services and receive responses.
+     *
+     * @param context      The Context for the SatelliteEntitlementController.
+     * @param looper       The looper for the handler. It does not run on main thread.
+     */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    public SatelliteEntitlementController(@NonNull Context context, @NonNull Looper looper) {
+        super(looper);
+        mContext = context;
+        mSubscriptionManagerService = SubscriptionManagerService.getInstance();
+        mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
+        mCarrierConfigChangeListener = (slotIndex, subId, carrierId, specificCarrierId) ->
+                handleCarrierConfigChanged(slotIndex, subId, carrierId, specificCarrierId);
+        mCarrierConfigManager.registerCarrierConfigChangeListener(this::post,
+                mCarrierConfigChangeListener);
+        mConnectivityManager = context.getSystemService(ConnectivityManager.class);
+        mNetworkCallback = new ConnectivityManager.NetworkCallback() {
+            @Override
+            public void onAvailable(Network network) {
+                handleInternetConnected();
+            }
+
+            @Override
+            public void onLost(Network network) {
+                handleInternetDisconnected();
+            }
+        };
+        NetworkRequest networkrequest = new NetworkRequest.Builder()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).build();
+        mConnectivityManager.registerNetworkCallback(networkrequest, mNetworkCallback, this);
+        mReceiver = new SatelliteEntitlementControllerReceiver();
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        context.registerReceiver(mReceiver, intentFilter);
+    }
+
+    @Override
+    public void handleMessage(@NonNull Message msg) {
+        switch (msg.what) {
+            case CMD_START_QUERY_ENTITLEMENT:
+                handleCmdStartQueryEntitlement();
+                break;
+            case CMD_RETRY_QUERY_ENTITLEMENT:
+                handleCmdRetryQueryEntitlement(msg.arg1);
+                break;
+            case CMD_STOP_RETRY_QUERY_ENTITLEMENT:
+                stopExponentialBackoff(msg.arg1);
+                break;
+            default:
+                logd("do not used this message");
+        }
+    }
+
+    private void handleCarrierConfigChanged(int slotIndex, int subId, int carrierId,
+            int specificCarrierId) {
+        if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            return;
+        }
+        logd("handleCarrierConfigChanged(): slotIndex(" + slotIndex + "), subId("
+                + subId + "), carrierId(" + carrierId + "), specificCarrierId("
+                + specificCarrierId + ")");
+
+        sendEmptyMessage(CMD_START_QUERY_ENTITLEMENT);
+    }
+
+    private class SatelliteEntitlementControllerReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
+                boolean airplaneMode = intent.getBooleanExtra("state", false);
+                handleAirplaneModeChange(airplaneMode);
+            }
+        }
+    }
+
+    private void handleAirplaneModeChange(boolean airplaneMode) {
+        if (!airplaneMode) {
+            resetEntitlementQueryCounts(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        }
+    }
+
+    private boolean isInternetConnected() {
+        Network activeNetwork = mConnectivityManager.getActiveNetwork();
+        NetworkCapabilities networkCapabilities =
+                mConnectivityManager.getNetworkCapabilities(activeNetwork);
+        // TODO b/319780796 Add checking if it is not a satellite.
+        return networkCapabilities != null
+                && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+    }
+
+    private void handleInternetConnected() {
+        sendEmptyMessage(CMD_START_QUERY_ENTITLEMENT);
+    }
+
+    private void handleInternetDisconnected() {
+        mExponentialBackoffPerSub.forEach((key, value) -> {
+            Message message = obtainMessage();
+            message.what = CMD_STOP_RETRY_QUERY_ENTITLEMENT;
+            message.arg1 = key;
+            sendMessage(message);
+        });
+    }
+
+    /**
+     * Check if the device can request to entitlement server (if there is an internet connection and
+     * if the throttle time has passed since the last request), and then pass the response to
+     * SatelliteController if the response is received.
+     */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    public void handleCmdStartQueryEntitlement() {
+        if (!isInternetConnected()) {
+            logd("Internet disconnected");
+            return;
+        }
+
+        for (int subId : mSubscriptionManagerService.getActiveSubIdList(true)) {
+            if (!shouldQueryEntitlement(subId)) {
+                return;
+            }
+
+            // Check the satellite service query result from the entitlement server for the
+            // satellite service.
+            try {
+                mSatelliteEntitlementResultPerSub.remove(subId);
+                mSatelliteEntitlementResultPerSub.put(subId, getSatelliteEntitlementApi(
+                        subId).checkEntitlementStatus());
+            } catch (ServiceEntitlementException e) {
+                loge(e.toString());
+                if (!isInternetConnected()) {
+                    logd("handleCmdStartQueryEntitlement: disconnected. " + e);
+                    return;
+                }
+                if (shouldHandleErrorResponse(e, subId)) {
+                    logd("handleCmdStartQueryEntitlement: handle response.");
+                    return;
+                }
+                startExponentialBackoff(subId);
+                return;
+            }
+            queryCompleted(subId);
+        }
+    }
+
+    /** When airplane mode changes from on to off, reset the values required to start the first
+     * query. */
+    private void resetEntitlementQueryCounts(String event) {
+        logd("resetEntitlementQueryCounts: " + event);
+        mLastQueryTimePerSub = new HashMap<>();
+        mExponentialBackoffPerSub = new HashMap<>();
+        mRetryCountPerSub = new HashMap<>();
+    }
+
+    /**
+     * If the HTTP response does not receive a body containing the 200 ok with sat mode
+     * configuration,
+     *
+     * 1. If the 500 response received, then no more retry until next event occurred.
+     * 2. If the 503 response with Retry-After header received, then the query is retried until
+     * MAX_RETRY_COUNT.
+     * 3. If other response or exception is occurred, then the query is retried until
+     * MAX_RETRY_COUNT is reached using the ExponentialBackoff.
+     */
+    private void handleCmdRetryQueryEntitlement(int subId) {
+        logd("handleCmdRetryQueryEntitlement: " + subId);
+        try {
+            synchronized (mLock) {
+                mSatelliteEntitlementResultPerSub.put(subId, getSatelliteEntitlementApi(
+                        subId).checkEntitlementStatus());
+            }
+        } catch (ServiceEntitlementException e) {
+            if (!isInternetConnected()) {
+                logd("retryQuery: Internet disconnected. reset the retry and after the "
+                        + "internet is connected then the first query is triggered." + e);
+                stopExponentialBackoff(subId);
+                return;
+            }
+            if (shouldHandleErrorResponse(e, subId)) {
+                logd("retryQuery: handle response.");
+                stopExponentialBackoff(subId);
+                return;
+            }
+            mExponentialBackoffPerSub.get(subId).notifyFailed();
+            mRetryCountPerSub.put(subId,
+                    mRetryCountPerSub.getOrDefault(subId, 0) + 1);
+            logd("handleCmdRetryQueryEntitlement:" + e + "[" + subId + "] cnt="
+                    + mRetryCountPerSub.getOrDefault(subId, 0) + "] Retrying in "
+                    + mExponentialBackoffPerSub.get(subId).getCurrentDelay() + " ms.");
+        }
+    }
+
+    /** Only handle '500' and '503 with retry-after header' error responses received.
+     * If the 500 response is received, no retry until the next trigger event occurs.
+     * If the 503 response with Retry-After header, retry is attempted according to the value in the
+     * Retry-After header up to MAX_RETRY_COUNT.
+     * In other cases, it performs an exponential backoff process. */
+    private boolean shouldHandleErrorResponse(ServiceEntitlementException e, int subId) {
+        int responseCode = e.getHttpStatus();
+        logd("shouldHandleErrorResponse: received the " + responseCode);
+        if (responseCode == HTTP_RESPONSE_503 && e.getRetryAfter() != null
+                && !e.getRetryAfter().isEmpty()) {
+            if (mRetryCountPerSub.getOrDefault(subId, 0) >= MAX_RETRY_COUNT) {
+                logd("The 503 retry after reaching the " + MAX_RETRY_COUNT
+                        + "The retry will not be attempted until the next trigger event.");
+                queryCompleted(subId);
+                return true;
+            }
+            long retryAfterSeconds = parseSecondsFromRetryAfter(e.getRetryAfter());
+            if (retryAfterSeconds == -1) {
+                logd("Unable parsing the retry-after. try to exponential backoff.");
+                return false;
+            }
+            mRetryCountPerSub.put(subId, mRetryCountPerSub.getOrDefault(subId, 0) + 1);
+            logd("[" + subId + "] cnt=" + mRetryCountPerSub.getOrDefault(subId, 0)
+                    + " Retrying in " + TimeUnit.SECONDS.toMillis(retryAfterSeconds) + " sec");
+            Message message = obtainMessage();
+            message.what = CMD_RETRY_QUERY_ENTITLEMENT;
+            message.arg1 = subId;
+            sendMessageDelayed(message, TimeUnit.SECONDS.toMillis(retryAfterSeconds));
+            return true;
+        } else if (responseCode == HTTP_RESPONSE_500) {
+            logd("The retry on the next trigger event.");
+            queryCompleted(subId);
+            return true;
+        }
+        return false;
+    }
+
+    /** Parse the HTTP-date or a number of seconds in the retry-after value. */
+    private long parseSecondsFromRetryAfter(String retryAfter) {
+        try {
+            return Long.parseLong(retryAfter);
+        } catch (NumberFormatException numberFormatException) {
+        }
+
+        try {
+            return SECONDS.between(
+                    Instant.now(), RFC_1123_DATE_TIME.parse(retryAfter, Instant::from));
+        } catch (DateTimeParseException dateTimeParseException) {
+        }
+
+        return -1;
+    }
+
+    private void startExponentialBackoff(int subId) {
+        stopExponentialBackoff(subId);
+        mExponentialBackoffPerSub.put(subId,
+                new ExponentialBackoff(INITIAL_DELAY_MILLIS, MAX_DELAY_MILLIS,
+                        MULTIPLIER, this.getLooper(), () -> {
+                    synchronized (mLock) {
+                        if (mSatelliteEntitlementResultPerSub.containsKey(subId)) {
+                            logd("handleCmdStartQueryEntitlement: get the response "
+                                    + "successfully.");
+                            mExponentialBackoffPerSub.get(subId).stop();
+                            queryCompleted(subId);
+                            return;
+                        }
+
+                        if (mRetryCountPerSub.getOrDefault(subId, 0) >= MAX_RETRY_COUNT) {
+                            logd("The ExponentialBackoff is  stopped after reaching the "
+                                    + MAX_RETRY_COUNT + ". The retry don't attempted until the"
+                                    + " refresh time expires.");
+                            mExponentialBackoffPerSub.get(subId).stop();
+                            queryCompleted(subId);
+                            return;
+                        }
+                        if (!mSatelliteEntitlementResultPerSub.containsKey(subId)) {
+                            handleCmdRetryQueryEntitlement(subId);
+                        }
+                    }
+                }));
+        mExponentialBackoffPerSub.get(subId).start();
+        mRetryCountPerSub.put(subId, mRetryCountPerSub.getOrDefault(subId, 0) + 1);
+        logd("start ExponentialBackoff [" + mRetryCountPerSub.getOrDefault(subId, 0)
+                + "] Retrying in " + mExponentialBackoffPerSub.get(subId).getCurrentDelay()
+                + " ms.");
+    }
+
+    /** If the Internet connection is lost during the ExponentialBackoff, stop the
+     * ExponentialBackoff and reset it. */
+    private void stopExponentialBackoff(int subId) {
+        if (isExponentialBackoffInProgress(subId)) {
+            logd("stopExponentialBackoff: reset ExponentialBackoff");
+            mExponentialBackoffPerSub.get(subId).stop();
+            mExponentialBackoffPerSub.remove(subId);
+        }
+    }
+
+    /**
+     * No more query retry, update the result. If there is no response from the server, then used
+     * the default value - 'satellite disabled' and empty 'PLMN allowed list'.
+     * And then it send a delayed message to trigger the query again after A refresh day has passed.
+     */
+    private void queryCompleted(int subId) {
+        if (!mSatelliteEntitlementResultPerSub.containsKey(subId)) {
+            logd("queryCompleted: create default SatelliteEntitlementResult");
+            mSatelliteEntitlementResultPerSub.put(subId,
+                    SatelliteEntitlementResult.getDefaultResult());
+        }
+
+        saveLastQueryTime(subId);
+        Message message = obtainMessage();
+        message.what = CMD_START_QUERY_ENTITLEMENT;
+        message.arg1 = subId;
+        sendMessageDelayed(message, TimeUnit.DAYS.toMillis(
+                getSatelliteEntitlementStatusRefreshDays(subId)));
+        logd("queryCompleted: updateSatelliteEntitlementStatus");
+        updateSatelliteEntitlementStatus(subId,
+                mSatelliteEntitlementResultPerSub.get(subId).getEntitlementStatus()
+                        == SATELLITE_ENTITLEMENT_STATUS_ENABLED,
+                mSatelliteEntitlementResultPerSub.get(subId).getAllowedPLMNList());
+        stopExponentialBackoff(subId);
+        mRetryCountPerSub.remove(subId);
+    }
+
+    /** Check whether there is a saved subId. Returns true if there is a saved subId,
+     * otherwise return false.*/
+    private boolean isExponentialBackoffInProgress(int subId) {
+        return mExponentialBackoffPerSub.containsKey(subId);
+    }
+
+    /**
+     * Check if the subId can query the entitlement server to get the satellite configuration.
+     */
+    private boolean shouldQueryEntitlement(int subId) {
+        if (!isSatelliteEntitlementSupported(subId)) {
+            logd("Doesn't support entitlement query for satellite.");
+            return false;
+        }
+
+        if (isExponentialBackoffInProgress(subId)) {
+            logd("In progress ExponentialBackoff.");
+            return false;
+        }
+
+        return shouldRefreshEntitlementStatus(subId);
+    }
+
+    /**
+     * Compare the last query time to the refresh time from the CarrierConfig to see if the device
+     * can query the entitlement server.
+     */
+    private boolean shouldRefreshEntitlementStatus(int subId) {
+        long lastQueryTimeMillis = getLastQueryTime(subId);
+        long refreshTimeMillis = TimeUnit.DAYS.toMillis(
+                getSatelliteEntitlementStatusRefreshDays(subId));
+        boolean isAvailable =
+                (System.currentTimeMillis() - lastQueryTimeMillis) > refreshTimeMillis;
+        if (!isAvailable) {
+            logd("query is already done. can query after " + Instant.ofEpochMilli(
+                    refreshTimeMillis + lastQueryTimeMillis));
+        }
+        return isAvailable;
+    }
+
+    /**
+     * Get the SatelliteEntitlementApi.
+     *
+     * @param subId The subId of the subscription for creating SatelliteEntitlementApi
+     * @return A new SatelliteEntitlementApi object.
+     */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    public SatelliteEntitlementApi getSatelliteEntitlementApi(int subId) {
+        return new SatelliteEntitlementApi(mContext, getConfigForSubId(subId), subId);
+    }
+
+    /** If there is a value stored in the cache, it is used. If there is no value stored in the
+     * cache, it is considered the first query. */
+    private long getLastQueryTime(int subId) {
+        return mLastQueryTimePerSub.getOrDefault(subId, 0L);
+    }
+
+    /** Return the satellite entitlement status refresh days from carrier config. */
+    private int getSatelliteEntitlementStatusRefreshDays(int subId) {
+        return getConfigForSubId(subId).getInt(
+                CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_STATUS_REFRESH_DAYS_INT,
+                DEFAULT_QUERY_REFRESH_DAYS);
+    }
+
+    /** Return the satellite entitlement supported bool from carrier config. */
+    private boolean isSatelliteEntitlementSupported(int subId) {
+        return getConfigForSubId(subId).getBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL);
+    }
+
+    @NonNull
+    private PersistableBundle getConfigForSubId(int subId) {
+        PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId,
+                CarrierConfigManager.ImsServiceEntitlement.KEY_ENTITLEMENT_SERVER_URL_STRING,
+                CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_STATUS_REFRESH_DAYS_INT,
+                CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL);
+        if (config == null || config.isEmpty()) {
+            config = CarrierConfigManager.getDefaultConfig();
+        }
+        return config;
+    }
+
+    private void saveLastQueryTime(int subId) {
+        long lastQueryTimeMillis = System.currentTimeMillis();
+        mLastQueryTimePerSub.put(subId, lastQueryTimeMillis);
+    }
+
+    /**
+     * Send to satelliteController for update the satellite service enabled or not and plmn Allowed
+     * list.
+     */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    public void updateSatelliteEntitlementStatus(int subId, boolean enabled,
+            List<String> plmnAllowedList) {
+        SatelliteController.getInstance().onSatelliteEntitlementStatusUpdated(subId, enabled,
+                plmnAllowedList, null);
+    }
+
+    private static void logd(String log) {
+        Rlog.d(TAG, log);
+    }
+
+    private static void loge(String log) {
+        Rlog.e(TAG, log);
+    }
+}
diff --git a/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResponse.java b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResponse.java
new file mode 100644
index 0000000..1fe0ecf
--- /dev/null
+++ b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResponse.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2024 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.phone.satellite.entitlement;
+
+import static com.android.phone.satellite.entitlement.SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_DISABLED;
+
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.satellite.SatelliteNetworkInfo;
+import com.android.libraries.entitlement.ServiceEntitlement;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * This class parses whether the satellite service configuration.
+ * @hide
+ */
+public class SatelliteEntitlementResponse {
+    private static final String TAG = "SatelliteEntitlementResponse";
+
+    /** Overall status of the SatMode entitlement, stating if the satellite service can be offered
+     * on the device, and if it can be activated or not by the user. */
+    private static final String ENTITLEMENT_STATUS_KEY = "EntitlementStatus";
+    /** List of allowed PLMNs where the service can be used. */
+    private static final String PLMN_ALLOWED_KEY = "PLMNAllowed";
+    /** List of barred PLMNs where the service can’t be used. */
+    private static final String PLMN_BARRED_KEY = "PLMNBarred";
+    /** allowed PLMN-ID where the service can be used or is barred. */
+    private static final String PLMN_KEY = "PLMN";
+    /** The data plan is of the metered or un-metered type. This value is optional. */
+    private static final String DATA_PLAN_TYPE_KEY = "DataPlanType";
+
+    @SatelliteEntitlementResult.SatelliteEntitlementStatus private int mEntitlementStatus;
+
+    /**
+     * <p> Available options are :
+     * "PLMNAllowed":[{ "PLMN": "XXXXXX", “DataPlanType”: "unmetered"},
+     * {"PLMN": "XXXXXX", “DataPlanType”: "metered"},
+     * {"PLMN": "XXXXXX"}]
+     */
+    private List<SatelliteNetworkInfo> mPlmnAllowedList;
+    /**
+     * <p> Available option is :
+     * "PLMNBarred":[{"PLMN": "XXXXXX"}, {"PLMN”:"XXXXXX"}]
+     */
+    private List<String> mPlmnBarredList;
+
+    public SatelliteEntitlementResponse(String response) {
+        mEntitlementStatus = SATELLITE_ENTITLEMENT_STATUS_DISABLED;
+        mPlmnAllowedList = new ArrayList<>();
+        mPlmnBarredList = new ArrayList<>();
+        parsingResponse(response);
+    }
+
+    /**
+     * Get the entitlement status for the satellite service
+     * @return The satellite entitlement status
+     */
+    public int getEntitlementStatus() {
+        return mEntitlementStatus;
+    }
+
+    /**
+     * Get the PLMNAllowed from the response
+     * @return The PLMNs Allowed list. PLMN and Data Plan Type(optional).
+     */
+    public List<SatelliteNetworkInfo> getPlmnAllowed() {
+        return mPlmnAllowedList.stream().map((info) -> new SatelliteNetworkInfo(info.mPlmn,
+                info.mDataPlanType)).collect(Collectors.toList());
+    }
+
+    /**
+     * Get the PLMNBarredList from the response
+     * @return The PLMNs Barred List
+     */
+    @VisibleForTesting
+    public List<String> getPlmnBarredList() {
+        return mPlmnBarredList.stream().map(String::new).collect(Collectors.toList());
+    }
+
+    private void parsingResponse(String response) {
+        JSONObject jsonAuthResponse = null;
+        try {
+            jsonAuthResponse = new JSONObject(response);
+            if (!jsonAuthResponse.has(ServiceEntitlement.APP_SATELLITE_ENTITLEMENT)) {
+                loge("parsingResponse failed with no app");
+                return;
+            }
+            JSONObject jsonToken = jsonAuthResponse.getJSONObject(
+                    ServiceEntitlement.APP_SATELLITE_ENTITLEMENT);
+            if (jsonToken.has(ENTITLEMENT_STATUS_KEY)) {
+                String entitlementStatus = jsonToken.getString(ENTITLEMENT_STATUS_KEY);
+                if (entitlementStatus == null) {
+                    loge("parsingResponse EntitlementStatus is null");
+                    return;
+                }
+                mEntitlementStatus = Integer.valueOf(entitlementStatus);
+            }
+            if (jsonToken.has(PLMN_ALLOWED_KEY)) {
+                JSONArray jsonArray = jsonToken.getJSONArray(PLMN_ALLOWED_KEY);
+                mPlmnAllowedList = new ArrayList<>();
+                for (int i = 0; i < jsonArray.length(); i++) {
+                    String dataPlanType = jsonArray.getJSONObject(i).has(DATA_PLAN_TYPE_KEY)
+                            ? jsonArray.getJSONObject(i).getString(DATA_PLAN_TYPE_KEY) : "";
+                    mPlmnAllowedList.add(new SatelliteNetworkInfo(
+                            jsonArray.getJSONObject(i).getString(PLMN_KEY), dataPlanType));
+                }
+            }
+            if (jsonToken.has(PLMN_BARRED_KEY)) {
+                mPlmnBarredList = new ArrayList<>();
+                JSONArray jsonArray = jsonToken.getJSONArray(PLMN_BARRED_KEY);
+                for (int i = 0; i < jsonArray.length(); i++) {
+                    mPlmnBarredList.add(jsonArray.getJSONObject(i).getString(PLMN_KEY));
+                }
+            }
+        } catch (JSONException e) {
+            loge("parsingResponse: failed JSONException", e);
+        } catch (NumberFormatException e) {
+            loge("parsingResponse: failed NumberFormatException", e);
+        }
+    }
+
+    private static void loge(String log) {
+        Log.e(TAG, log);
+    }
+
+    private static void loge(String log, Exception e) {
+        Log.e(TAG, log, e);
+    }
+}
diff --git a/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResult.java b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResult.java
new file mode 100644
index 0000000..3289232
--- /dev/null
+++ b/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResult.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2024 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.phone.satellite.entitlement;
+
+import android.annotation.IntDef;
+
+import com.android.internal.telephony.satellite.SatelliteNetworkInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * This class stores the result of the satellite entitlement query and passes them to
+ * SatelliteEntitlementController.
+ */
+public class SatelliteEntitlementResult {
+    /** SatMode allowed, but not yet provisioned and activated on the network. */
+    public static final int SATELLITE_ENTITLEMENT_STATUS_DISABLED = 0;
+    /** SatMode service allowed, provisioned and activated on the network. User can access the
+     * satellite service. */
+    public static final int SATELLITE_ENTITLEMENT_STATUS_ENABLED = 1;
+    /** SatMode cannot be offered for network or device. */
+    public static final int SATELLITE_ENTITLEMENT_STATUS_INCOMPATIBLE = 2;
+    /** SatMode is being provisioned on the network. Not yet activated. */
+    public static final int SATELLITE_ENTITLEMENT_STATUS_PROVISIONING = 3;
+
+    @IntDef(prefix = {"SATELLITE_ENTITLEMENT_STATUS_"}, value = {
+            SATELLITE_ENTITLEMENT_STATUS_DISABLED,
+            SATELLITE_ENTITLEMENT_STATUS_ENABLED,
+            SATELLITE_ENTITLEMENT_STATUS_INCOMPATIBLE,
+            SATELLITE_ENTITLEMENT_STATUS_PROVISIONING
+    })
+    public @interface SatelliteEntitlementStatus {}
+
+    private @SatelliteEntitlementStatus int mEntitlementStatus;
+    /**
+     * An SatelliteNetworkInfo list consisting of the PLMN and the DataPlanType in the PLMNAlowed
+     * item of the satellite configuration received from the entitlement server.
+     */
+    private List<SatelliteNetworkInfo> mAllowedSatelliteNetworkInfoList;
+
+    /**
+     * Store the result of the satellite entitlement response.
+     *
+     * @param entitlementStatus The entitlement status.
+     * @param allowedSatelliteNetworkInfoList The allowedSatelliteNetworkInfoList
+     */
+    public SatelliteEntitlementResult(@SatelliteEntitlementStatus int entitlementStatus,
+            List<SatelliteNetworkInfo> allowedSatelliteNetworkInfoList) {
+        mEntitlementStatus = entitlementStatus;
+        mAllowedSatelliteNetworkInfoList = allowedSatelliteNetworkInfoList;
+    }
+
+    /**
+     * Get the entitlement status.
+     *
+     * @return The entitlement status.
+     */
+    public @SatelliteEntitlementStatus int getEntitlementStatus() {
+        return mEntitlementStatus;
+    }
+
+    /**
+     * Get the plmn allowed list
+     *
+     * @return The plmn allowed list.
+     */
+    public List<String> getAllowedPLMNList() {
+        return mAllowedSatelliteNetworkInfoList.stream().map(info -> info.mPlmn).collect(
+                Collectors.toList());
+    }
+
+    /**
+     * Get the default SatelliteEntitlementResult. EntitlementStatus set to
+     * `SATELLITE_ENTITLEMENT_STATUS_DISABLED` and SatelliteNetworkInfo list set to empty.
+     *
+     * @return If there is no response, return default SatelliteEntitlementResult
+     */
+    public static SatelliteEntitlementResult getDefaultResult() {
+        return new SatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_DISABLED,
+                new ArrayList<>());
+    }
+}
diff --git a/src/com/android/phone/security/SafetySourceReceiver.java b/src/com/android/phone/security/SafetySourceReceiver.java
new file mode 100644
index 0000000..c846c43
--- /dev/null
+++ b/src/com/android/phone/security/SafetySourceReceiver.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2024 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.phone.security;
+
+import static android.safetycenter.SafetyCenterManager.ACTION_REFRESH_SAFETY_SOURCES;
+import static android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import com.android.phone.PhoneGlobals;
+
+public final class SafetySourceReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        if (!ACTION_REFRESH_SAFETY_SOURCES.equals(action)) {
+            return;
+        }
+
+        String refreshBroadcastId =
+                intent.getStringExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID);
+        if (refreshBroadcastId == null) {
+            return;
+        }
+
+        PhoneGlobals.getPhone().refreshSafetySources(refreshBroadcastId);
+    }
+}
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index adb07f9..91ecb93 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -31,7 +31,7 @@
 import com.android.internal.telephony.PhoneFactory;
 import com.android.phone.ImsUtil;
 import com.android.phone.PhoneGlobals;
-import com.android.phone.common.R;
+import com.android.phone.R;
 
 public class DisconnectCauseUtil {
 
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index ea29b77..efa5278 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -64,6 +64,7 @@
 import com.android.internal.telephony.ExponentialBackoff;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.flags.Flags;
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
 import com.android.phone.PhoneGlobals;
 import com.android.phone.PhoneUtils;
@@ -465,6 +466,15 @@
             mIsUsingSimCallManager = isCarrierUsingSimCallManager();
             mIsShowPreciseFailedCause = isCarrierShowPreciseFailedCause();
 
+            // Set CAPABILITY_EMERGENCY_CALLS_ONLY flag if either
+            // - Carrier config overrides subscription is not voice capable, or
+            // - Resource config overrides it be emergency_calls_only
+            // TODO(b/316183370:): merge the two cases when clearing up flag
+            if (Flags.dataOnlyServiceAllowEmergencyCallOnly()) {
+                if (!isSubscriptionVoiceCapableByCarrierConfig()) {
+                    capabilities |= PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY;
+                }
+            }
             if (isEmergency && mContext.getResources().getBoolean(
                     R.bool.config_emergency_account_emergency_calls_only)) {
                 capabilities |= PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY;
@@ -804,6 +814,21 @@
         }
 
         /**
+         * @return true if the subscription is voice capable by the carrier config.
+         */
+        private boolean isSubscriptionVoiceCapableByCarrierConfig() {
+            PersistableBundle b =
+                    PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
+            if (b == null) {
+                return true; // For any abnormal case, we assume subscription is voice capable
+            }
+            final int[] serviceCapabilities = b.getIntArray(
+                    CarrierConfigManager.KEY_CELLULAR_SERVICE_CAPABILITIES_INT_ARRAY);
+            return Arrays.stream(serviceCapabilities).anyMatch(
+                    i -> i == SubscriptionManager.SERVICE_CAPABILITY_VOICE);
+        }
+
+        /**
          * Receives callback from {@link PstnPhoneCapabilitiesNotifier} when the video capabilities
          * have changed.
          *
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 9fe73e2..7749a2c 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -964,7 +964,7 @@
     private Integer mEmergencyServiceCategory = null;
 
     protected TelephonyConnection(com.android.internal.telephony.Connection originalConnection,
-            String callId, @android.telecom.Call.Details.CallDirection int callDirection) {
+            String callId, int callDirection) {
         setCallDirection(callDirection);
         setTelecomCallId(callId);
         if (originalConnection != null) {
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 62c573d..acd83c3 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -642,6 +642,13 @@
                 }
             };
 
+    private void clearNormalCallDomainSelectionConnection() {
+        if (mDomainSelectionConnection != null) {
+            mDomainSelectionConnection.finishSelection();
+            mDomainSelectionConnection = null;
+        }
+    }
+
     /**
      * A listener for calls.
      */
@@ -654,17 +661,15 @@
                     if (c != null) {
                         switch(c.getState()) {
                             case Connection.STATE_ACTIVE: {
-                                Log.d(LOG_TAG, "Call State->ACTIVE."
-                                        + "Clearing DomainSelectionConnection");
-                                if (mDomainSelectionConnection != null) {
-                                    mDomainSelectionConnection.finishSelection();
-                                    mDomainSelectionConnection = null;
-                                }
+                                clearNormalCallDomainSelectionConnection();
                                 mNormalCallConnection = null;
                             }
                             break;
 
                             case Connection.STATE_DISCONNECTED: {
+                                // Clear connection if the call state changes from
+                                // DIALING -> DISCONNECTED without ACTIVE State.
+                                clearNormalCallDomainSelectionConnection();
                                 c.removeTelephonyConnectionListener(mNormalCallConnectionListener);
                             }
                             break;
@@ -1103,6 +1108,7 @@
         final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber,
                 /* Note: when not an emergency, handle can be null for unknown callers */
                 handle == null ? null : handle.getSchemeSpecificPart());
+        ImsPhone imsPhone = phone != null ? (ImsPhone) phone.getImsPhone() : null;
 
         boolean isPhoneWifiCallingEnabled = phone != null && phone.isWifiCallingEnabled();
         boolean needToTurnOnRadio = (isEmergencyNumber && (!isRadioOn() || isAirplaneModeOn))
@@ -1133,6 +1139,7 @@
             }
             int timeoutToOnTimeoutCallback = mDomainSelectionResolver.isDomainSelectionSupported()
                     ? TIMEOUT_TO_DYNAMIC_ROUTING_MS : 0;
+            final Phone phoneForEmergency = phone;
             mRadioOnHelper.triggerRadioOnAndListen(new RadioOnStateListener.Callback() {
                 @Override
                 public void onComplete(RadioOnStateListener listener, boolean isRadioReady) {
@@ -1157,7 +1164,7 @@
                             && phone.getHalVersion(HAL_SERVICE_VOICE)
                             .less(RIL.RADIO_HAL_VERSION_1_4);
                     if (mDomainSelectionResolver.isDomainSelectionSupported()) {
-                        if (isEmergencyNumber) {
+                        if (isEmergencyNumber && phone == phoneForEmergency) {
                             // Since the domain selection service is enabled,
                             // dilaing normal routing emergency number only reaches here.
                             if (!isVoiceInService(phone, imsVoiceCapable)) {
@@ -1209,8 +1216,9 @@
             }
 
             if (!isEmergencyNumber) {
-                if (mSatelliteController.isSatelliteEnabled()
-                        || isCallDisallowedDueToSatellite(phone)) {
+                if ((mSatelliteController.isSatelliteEnabled()
+                        || isCallDisallowedDueToSatellite(phone))
+                        && (imsPhone == null || !imsPhone.canMakeWifiCall())) {
                     Log.d(this, "onCreateOutgoingConnection, cannot make call in satellite mode.");
                     return Connection.createFailedConnection(
                             mDisconnectCauseFactory.toTelecomDisconnectCause(
@@ -2308,6 +2316,7 @@
                     mNormalCallConnection.setTelephonyConnectionDisconnected(mDisconnectCauseFactory
                             .toTelecomDisconnectCause(telephonyDisconnectCause,
                                     "Connection is null", phone.getPhoneId()));
+                    clearNormalCallDomainSelectionConnection();
                     mNormalCallConnection.close();
                     return;
                 }
@@ -2335,10 +2344,7 @@
                             e.getMessage(), phone.getPhoneId()));
             mNormalCallConnection.close();
         }
-        if (mDomainSelectionConnection != null) {
-            mDomainSelectionConnection.finishSelection();
-            mDomainSelectionConnection = null;
-        }
+        clearNormalCallDomainSelectionConnection();
         mNormalCallConnection = null;
     }
 
@@ -2386,7 +2392,7 @@
         SelectionAttributes selectionAttributes =
                 new SelectionAttributes.Builder(phone.getPhoneId(), phone.getSubId(),
                         SELECTOR_TYPE_CALLING)
-                        .setNumber(number)
+                        .setAddress(Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null))
                         .setEmergency(false)
                         .setVideoCall(VideoProfile.isVideo(videoState))
                         .build();
@@ -2435,7 +2441,7 @@
                 }
                 if (result == android.telephony.DisconnectCause.NOT_DISCONNECTED) {
                     createEmergencyConnection(phone, (TelephonyConnection) resultConnection,
-                            numberToDial, request, needToTurnOnRadio,
+                            numberToDial, isTestEmergencyNumber, request, needToTurnOnRadio,
                             mEmergencyStateTracker.getEmergencyRegResult());
                 } else {
                     mEmergencyConnection = null;
@@ -2459,6 +2465,7 @@
     @SuppressWarnings("FutureReturnValueIgnored")
     private void createEmergencyConnection(final Phone phone,
             final TelephonyConnection resultConnection, final String number,
+            final boolean isTestEmergencyNumber,
             final ConnectionRequest request, boolean needToTurnOnRadio,
             final EmergencyRegResult regResult) {
         Log.i(this, "createEmergencyConnection");
@@ -2500,7 +2507,8 @@
         DomainSelectionService.SelectionAttributes attr =
                 EmergencyCallDomainSelectionConnection.getSelectionAttributes(
                         phone.getPhoneId(), phone.getSubId(), needToTurnOnRadio,
-                        request.getTelecomCallId(), number, 0, null, regResult);
+                        request.getTelecomCallId(), number, isTestEmergencyNumber,
+                        0, null, regResult);
 
         CompletableFuture<Integer> future =
                 mEmergencyCallDomainSelectionConnection.createEmergencyConnection(
@@ -2579,10 +2587,7 @@
                             && extraCode == ImsReasonInfo.EXTRA_CODE_CALL_RETRY_EMERGENCY)) {
                 // clear normal call domain selector
                 c.removeTelephonyConnectionListener(mNormalCallConnectionListener);
-                if (mDomainSelectionConnection != null) {
-                    mDomainSelectionConnection.finishSelection();
-                    mDomainSelectionConnection = null;
-                }
+                clearNormalCallDomainSelectionConnection();
                 mNormalCallConnection = null;
 
                 onEmergencyRedial(c, c.getPhone().getDefaultPhone());
@@ -2608,7 +2613,7 @@
                     EmergencyCallDomainSelectionConnection.getSelectionAttributes(
                             c.getPhone().getPhoneId(), c.getPhone().getSubId(), false,
                             c.getTelecomCallId(), c.getAddress().getSchemeSpecificPart(),
-                            callFailCause, reasonInfo, null);
+                            false, callFailCause, reasonInfo, null);
 
             CompletableFuture<Integer> future =
                     mEmergencyCallDomainSelectionConnection.reselectDomain(attr);
@@ -2778,10 +2783,7 @@
         }
 
         c.removeTelephonyConnectionListener(mTelephonyConnectionListener);
-        if (mDomainSelectionConnection != null) {
-            mDomainSelectionConnection.finishSelection();
-            mDomainSelectionConnection = null;
-        }
+        clearNormalCallDomainSelectionConnection();
         mNormalCallConnection = null;
         Log.d(LOG_TAG, "Reselect call domain not triggered.");
         return false;
@@ -2881,7 +2883,7 @@
                                 phone.getPhoneId(),
                                 phone.getSubId(), false,
                                 c.getTelecomCallId(),
-                                c.getAddress().getSchemeSpecificPart(),
+                                c.getAddress().getSchemeSpecificPart(), isTestEmergencyNumber,
                                 0, null, mEmergencyStateTracker.getEmergencyRegResult());
 
                 CompletableFuture<Integer> domainFuture =
@@ -3620,6 +3622,11 @@
     @VisibleForTesting
     public boolean isAvailableForEmergencyCalls(Phone phone,
             @EmergencyNumber.EmergencyCallRouting int routing) {
+        if (isCallDisallowedDueToSatellite(phone)) {
+            // Phone is connected to satellite due to which it is not preferred for emergency call.
+            return false;
+        }
+
         if (phone.getImsRegistrationTech() == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM) {
             // When a Phone is registered to Cross-SIM calling, there must always be a Phone on the
             // other sub which is registered to cellular, so that must be selected.
@@ -4294,6 +4301,10 @@
         }
 
         ServiceState serviceState = phone.getServiceState();
+        if (serviceState == null) {
+            return false;
+        }
+
         if (!serviceState.isUsingNonTerrestrialNetwork()) {
             // Device is not connected to satellite
             return false;
diff --git a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
index ce2dacc..bfa7026 100644
--- a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
@@ -55,6 +55,7 @@
 import static android.telephony.PreciseDisconnectCause.EMERGENCY_PERM_FAILURE;
 import static android.telephony.PreciseDisconnectCause.EMERGENCY_TEMP_FAILURE;
 import static android.telephony.PreciseDisconnectCause.SERVICE_OPTION_NOT_AVAILABLE;
+import static android.telephony.TelephonyManager.DATA_CONNECTED;
 
 import android.annotation.NonNull;
 import android.content.Context;
@@ -79,11 +80,9 @@
 import android.telephony.DomainSelectionService.SelectionAttributes;
 import android.telephony.EmergencyRegResult;
 import android.telephony.NetworkRegistrationInfo;
-import android.telephony.PhoneNumberUtils;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.TransportSelectorCallback;
-import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.ImsManager;
 import android.telephony.ims.ImsMmTelManager;
 import android.telephony.ims.ProvisioningManager;
@@ -95,9 +94,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.function.IntFunction;
 
 /**
@@ -213,13 +210,15 @@
     private final PowerManager.WakeLock mPartialWakeLock;
     private final CrossSimRedialingController mCrossSimRedialingController;
     private final CarrierConfigHelper mCarrierConfigHelper;
+    private final EmergencyCallbackModeHelper mEcbmHelper;
 
     /** Constructor. */
     public EmergencyCallDomainSelector(Context context, int slotId, int subId,
             @NonNull Looper looper, @NonNull ImsStateTracker imsStateTracker,
             @NonNull DestroyListener destroyListener,
             @NonNull CrossSimRedialingController csrController,
-            @NonNull CarrierConfigHelper carrierConfigHelper) {
+            @NonNull CarrierConfigHelper carrierConfigHelper,
+            @NonNull EmergencyCallbackModeHelper ecbmHelper) {
         super(context, slotId, subId, looper, imsStateTracker, destroyListener, TAG);
 
         mImsStateTracker.addBarringInfoListener(this);
@@ -230,6 +229,7 @@
 
         mCrossSimRedialingController = csrController;
         mCarrierConfigHelper = carrierConfigHelper;
+        mEcbmHelper = ecbmHelper;
         acquireWakeLock();
     }
 
@@ -284,7 +284,7 @@
                       && (mScanType == DomainSelectionService.SCAN_TYPE_FULL_SERVICE)) {
                 mScanType = DomainSelectionService.SCAN_TYPE_LIMITED_SERVICE;
                 mWwanSelectorCallback.onRequestEmergencyNetworkScan(
-                        mLastPreferredNetworks, mScanType, mCancelSignal,
+                        mLastPreferredNetworks, mScanType, false, mCancelSignal,
                         (regResult) -> {
                             logi("requestScan-onComplete");
                             sendMessage(obtainMessage(MSG_NETWORK_SCAN_RESULT, regResult));
@@ -326,12 +326,6 @@
     }
 
     @Override
-    public void cancelSelection() {
-        logi("cancelSelection");
-        finishSelection();
-    }
-
-    @Override
     public void reselectDomain(SelectionAttributes attr) {
         logi("reselectDomain attr=" + attr);
         mSelectionAttributes = attr;
@@ -344,7 +338,6 @@
         int cause = mSelectionAttributes.getCsDisconnectCause();
         mCrossSimRedialingController.notifyCallFailure(cause);
 
-        // TODO(b/258112541) make EMERGENCY_PERM_FAILURE and EMERGENCY_TEMP_FAILURE public api
         if (cause == EMERGENCY_PERM_FAILURE
                 || cause == EMERGENCY_TEMP_FAILURE) {
             logi("reselectDomain should redial on the other subscription");
@@ -358,11 +351,6 @@
             return;
         }
 
-        if (mIsTestEmergencyNumber) {
-            selectDomainForTestEmergencyNumber();
-            return;
-        }
-
         if (mTryCsWhenPsFails) {
             mTryCsWhenPsFails = false;
             // Initial state was CSFB available and dial PS failed.
@@ -437,7 +425,7 @@
         logi("selectDomain attr=" + attr);
         mTransportSelectorCallback = cb;
         mSelectionAttributes = attr;
-        mIsTestEmergencyNumber = isTestEmergencyNumber(attr.getNumber());
+        mIsTestEmergencyNumber = attr.isTestEmergencyNumber();
 
         TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
         mModemCount = tm.getActiveModemCount();
@@ -636,7 +624,8 @@
             return;
         }
 
-        if (isWifiPreferred()) {
+        if (isWifiPreferred()
+                || isInEmergencyCallbackModeOnWlan()) {
             onWlanSelected();
             return;
         }
@@ -649,11 +638,6 @@
     }
 
     private void selectDomainFromInitialState() {
-        if (mIsTestEmergencyNumber) {
-            selectDomainForTestEmergencyNumber();
-            return;
-        }
-
         boolean csInService = isCsInService();
         boolean psInService = isPsInService();
 
@@ -687,7 +671,8 @@
         logi("selectDomain CS={" + csInService + ", " + accessNetworkTypeToString(mCsNetworkType)
                 + "}, PS={" + psInService + ", " + accessNetworkTypeToString(mPsNetworkType) + "}");
         if (csAvailable && psAvailable) {
-            if (mPreferImsWhenCallsOnCs || isImsRegisteredWithVoiceCapability()) {
+            if (mSelectionAttributes.isExitedFromAirplaneMode()
+                    || mPreferImsWhenCallsOnCs || isImsRegisteredWithVoiceCapability()) {
                 mTryCsWhenPsFails = true;
                 onWwanNetworkTypeSelected(mPsNetworkType);
             } else if (isDeactivatedSim()) {
@@ -698,7 +683,8 @@
             }
         } else if (psAvailable) {
             mTryEpsFallback = (mPsNetworkType == NGRAN) && isEpsFallbackAvailable();
-            if (!mRequiresImsRegistration || isImsRegisteredWithVoiceCapability()) {
+            if (mSelectionAttributes.isExitedFromAirplaneMode()
+                    || !mRequiresImsRegistration || isImsRegisteredWithVoiceCapability()) {
                 onWwanNetworkTypeSelected(mPsNetworkType);
             } else if (isDeactivatedSim()) {
                 // Deactivated SIM but PS is in service and supports emergency calls.
@@ -713,7 +699,8 @@
             onWwanNetworkTypeSelected(mCsNetworkType);
         } else {
             // PS is in service but not supports emergency calls.
-            if (mRequiresImsRegistration && !isImsRegisteredWithVoiceCapability()) {
+            if (!mSelectionAttributes.isExitedFromAirplaneMode()
+                    && mRequiresImsRegistration && !isImsRegisteredWithVoiceCapability()) {
                 // Carrier configuration requires IMS registration for emergency services over PS,
                 // but not registered. Try CS emergency call.
                 requestScan(true, true);
@@ -763,14 +750,15 @@
         mTryEpsFallback = false;
 
         if (isInRoaming()
-                && (mPreferredNetworkScanType == DomainSelectionService.SCAN_TYPE_FULL_SERVICE)) {
+                && (mPreferredNetworkScanType
+                        == CarrierConfigManager.ImsEmergency.SCAN_TYPE_FULL_SERVICE)) {
             // FULL_SERVICE only preference is available only when not in roaming.
             mScanType = DomainSelectionService.SCAN_TYPE_NO_PREFERENCE;
         }
 
         mIsScanRequested = true;
         mWwanSelectorCallback.onRequestEmergencyNetworkScan(
-                mLastPreferredNetworks, mScanType, mCancelSignal,
+                mLastPreferredNetworks, mScanType, false, mCancelSignal,
                 (result) -> {
                     logi("requestScan-onComplete");
                     sendMessage(obtainMessage(MSG_NETWORK_SCAN_RESULT, result));
@@ -1188,7 +1176,8 @@
         }
 
         if (!mCdmaPreferredNumbers.isEmpty()) {
-            if (mCdmaPreferredNumbers.contains(mSelectionAttributes.getNumber())) {
+            String number = mSelectionAttributes.getAddress().getSchemeSpecificPart();
+            if (mCdmaPreferredNumbers.contains(number)) {
                 // The number will be dialed over CDMA.
                 ratList.clear();
                 ratList.add(new Integer(CDMA2000));
@@ -1224,7 +1213,7 @@
             if (regResult.getRegState() == REGISTRATION_STATE_HOME) return false;
             if (regResult.getRegState() == REGISTRATION_STATE_ROAMING) return true;
 
-            String iso = regResult.getIso();
+            String iso = regResult.getCountryIso();
             if (!TextUtils.isEmpty(iso)) netIso = iso;
         }
 
@@ -1380,7 +1369,7 @@
             return true;
         }
 
-        String iso = regResult.getIso();
+        String iso = regResult.getCountryIso();
         if (sSimReadyAllowList.contains(iso)) {
             TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
             int simState = tm.getSimState(getSlotId());
@@ -1436,8 +1425,9 @@
             inRoaming = (regState == REGISTRATION_STATE_ROAMING) || isInRoaming();
         }
 
+        String number = mSelectionAttributes.getAddress().getSchemeSpecificPart();
         mCrossSimRedialingController.startTimer(mContext, this, mSelectionAttributes.getCallId(),
-                mSelectionAttributes.getNumber(), inService, inRoaming, mModemCount);
+                number, inService, inRoaming, mModemCount);
     }
 
     /** Notifies that the cross stack redilaing timer has been expired. */
@@ -1562,6 +1552,12 @@
         }
     }
 
+    private boolean isInEmergencyCallbackModeOnWlan() {
+        return mEcbmHelper.isInEmergencyCallbackMode(getSlotId())
+                && mEcbmHelper.getTransportType(getSlotId()) == TRANSPORT_TYPE_WLAN
+                && mEcbmHelper.getDataConnectionState(getSlotId()) == DATA_CONNECTED;
+    }
+
     private void selectDomainForTestEmergencyNumber() {
         logi("selectDomainForTestEmergencyNumber");
         if (isImsRegisteredWithVoiceCapability()) {
@@ -1576,28 +1572,6 @@
         }
     }
 
-    private boolean isTestEmergencyNumber(String number) {
-        number = PhoneNumberUtils.stripSeparators(number);
-        Map<Integer, List<EmergencyNumber>> list = new HashMap<>();
-        try {
-            TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
-            list = tm.getEmergencyNumberList();
-        } catch (IllegalStateException ise) {
-            loge("isTestEmergencyNumber ise=" + ise);
-        }
-
-        for (Integer sub : list.keySet()) {
-            for (EmergencyNumber eNumber : list.get(sub)) {
-                if (number.equals(eNumber.getNumber())
-                        && eNumber.isFromSources(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST)) {
-                    logd("isTestEmergencyNumber: " + number + " is a test emergency number.");
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
     @Override
     protected void logi(String msg) {
         super.logi(msg);
diff --git a/src/com/android/services/telephony/domainselection/EmergencyCallbackModeHelper.java b/src/com/android/services/telephony/domainselection/EmergencyCallbackModeHelper.java
new file mode 100644
index 0000000..e42dfe7
--- /dev/null
+++ b/src/com/android/services/telephony/domainselection/EmergencyCallbackModeHelper.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2024 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.services.telephony.domainselection;
+
+import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL;
+import static android.telephony.SubscriptionManager.EXTRA_SLOT_INDEX;
+import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+import static android.telephony.TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED;
+import static android.telephony.TelephonyManager.EXTRA_PHONE_IN_ECM_STATE;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PersistableBundle;
+import android.os.SystemProperties;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.CarrierConfigManager;
+import android.telephony.PreciseDataConnectionState;
+import android.telephony.TelephonyCallback;
+import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
+import android.util.ArrayMap;
+import android.util.Log;
+
+/** Helper class to cache emergency data connection state. */
+public class EmergencyCallbackModeHelper extends Handler {
+    private static final String TAG = "EmergencyCallbackModeHelper";
+    private static final boolean DBG = (SystemProperties.getInt("ro.debuggable", 0) == 1);
+
+    /**
+     * TelephonyCallback used to monitor ePDN state.
+     */
+    private static final class DataConnectionStateListener extends TelephonyCallback
+            implements TelephonyCallback.PreciseDataConnectionStateListener {
+
+        private final Handler mHandler;
+        private final TelephonyManager mTelephonyManager;
+        private final int mSubId;
+        private int mTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
+        private int mState = TelephonyManager.DATA_UNKNOWN;
+
+        DataConnectionStateListener(Handler handler, TelephonyManager tm, int subId) {
+            mHandler = handler;
+            mTelephonyManager = tm;
+            mSubId = subId;
+        }
+
+        @Override
+        public void onPreciseDataConnectionStateChanged(
+                @NonNull PreciseDataConnectionState dataConnectionState) {
+            ApnSetting apnSetting = dataConnectionState.getApnSetting();
+            if ((apnSetting == null)
+                    || ((apnSetting.getApnTypeBitmask() | ApnSetting.TYPE_EMERGENCY) == 0)) {
+                return;
+            }
+            mTransportType = dataConnectionState.getTransportType();
+            mState = dataConnectionState.getState();
+            Log.i(TAG, "onPreciseDataConnectionStateChanged ePDN state=" + mState
+                    + ", transport=" + mTransportType);
+        }
+
+        public void registerTelephonyCallback() {
+            TelephonyManager tm = mTelephonyManager.createForSubscriptionId(mSubId);
+            tm.registerTelephonyCallback(mHandler::post, this);
+        }
+
+        public void unregisterTelephonyCallback() {
+            mTelephonyManager.unregisterTelephonyCallback(this);
+        }
+
+        public int getSubId() {
+            return mSubId;
+        }
+
+        public int getTransportType() {
+            return mTransportType;
+        }
+
+        public int getState() {
+            return mState;
+        }
+    }
+
+    private final Context mContext;
+    private final TelephonyManager mTelephonyManager;
+    private final CarrierConfigManager mConfigManager;
+
+    private final ArrayMap<Integer, DataConnectionStateListener>
+            mDataConnectionStateListeners = new ArrayMap<>();
+
+    private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener =
+            (slotIndex, subId, carrierId, specificCarrierId) -> onCarrierConfigChanged(
+                    slotIndex, subId, carrierId);
+
+    /**
+     * Creates an instance.
+     *
+     * @param context The Context this is associated with.
+     * @param looper The Looper to run the EmergencyCallbackModeHelper.
+     */
+    public EmergencyCallbackModeHelper(@NonNull Context context, @NonNull Looper looper) {
+        super(looper);
+
+        mContext = context;
+        mTelephonyManager = context.getSystemService(TelephonyManager.class);
+        mConfigManager = context.getSystemService(CarrierConfigManager.class);
+        mConfigManager.registerCarrierConfigChangeListener(this::post,
+                mCarrierConfigChangeListener);
+    }
+
+    /**
+     * Returns whether it is in emergency callback mode.
+     *
+     * @param slotIndex The logical SIM slot index.
+     * @return true if it is in emergency callback mode.
+     */
+    public boolean isInEmergencyCallbackMode(int slotIndex) {
+        DataConnectionStateListener listener =
+                mDataConnectionStateListeners.get(Integer.valueOf(slotIndex));
+        if (listener == null) return false;
+
+        Intent intent = mContext.registerReceiver(null,
+                new IntentFilter(ACTION_EMERGENCY_CALLBACK_MODE_CHANGED));
+        if (intent != null
+                && ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(intent.getAction())) {
+            boolean inEcm = intent.getBooleanExtra(EXTRA_PHONE_IN_ECM_STATE, false);
+            int index = intent.getIntExtra(EXTRA_SLOT_INDEX, INVALID_SIM_SLOT_INDEX);
+            Log.i(TAG, "isInEmergencyCallbackMode inEcm=" + inEcm + ", slotIndex=" + index);
+            return inEcm && (slotIndex == index);
+        }
+        return false;
+    }
+
+    /**
+     * Returns the transport type of emergency data connection.
+     *
+     * @param slotIndex The logical SIM slot index.
+     * @return the transport type of emergency data connection.
+     */
+    public int getTransportType(int slotIndex) {
+        DataConnectionStateListener listener =
+                mDataConnectionStateListeners.get(Integer.valueOf(slotIndex));
+        if (listener == null) return AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
+        Log.i(TAG, "getTransportType " + listener.getTransportType());
+        return listener.getTransportType();
+    }
+
+    /**
+     * Returns the data connection state.
+     *
+     * @param slotIndex The logical SIM slot index.
+     * @return the data connection state.
+     */
+    public int getDataConnectionState(int slotIndex) {
+        DataConnectionStateListener listener =
+                mDataConnectionStateListeners.get(Integer.valueOf(slotIndex));
+        if (listener == null) return TelephonyManager.DATA_UNKNOWN;
+        Log.i(TAG, "getDataConnectionState " + listener.getState());
+        return listener.getState();
+    }
+
+    @Override
+    public void handleMessage(Message msg) {
+        switch(msg.what) {
+            default:
+                super.handleMessage(msg);
+                break;
+        }
+    }
+
+    private void onCarrierConfigChanged(int slotIndex, int subId, int carrierId) {
+        Log.i(TAG, "onCarrierConfigChanged slotIndex=" + slotIndex
+                + ", subId=" + subId + ", carrierId=" + carrierId);
+
+        if (slotIndex < 0) {
+            return;
+        }
+
+        PersistableBundle b = mConfigManager.getConfigForSubId(subId,
+                KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL);
+
+        if (b.getBoolean(KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL)) {
+            // ECBM supported
+            DataConnectionStateListener listener =
+                    mDataConnectionStateListeners.get(Integer.valueOf(slotIndex));
+
+            // Remove stale listener.
+            if (listener != null && listener.getSubId() != subId) {
+                listener.unregisterTelephonyCallback();
+                listener = null;
+            }
+
+            if (listener == null) {
+                listener = new DataConnectionStateListener(this, mTelephonyManager, subId);
+                listener.registerTelephonyCallback();
+                mDataConnectionStateListeners.put(Integer.valueOf(slotIndex), listener);
+                Log.i(TAG, "onCarrierConfigChanged register callback");
+            }
+        } else {
+            // ECBM not supported
+            DataConnectionStateListener listener =
+                    mDataConnectionStateListeners.get(Integer.valueOf(slotIndex));
+            if (listener != null) {
+                listener.unregisterTelephonyCallback();
+                mDataConnectionStateListeners.remove(Integer.valueOf(slotIndex));
+                Log.i(TAG, "onCarrierConfigChanged unregister callback");
+            }
+        }
+    }
+
+    /** Destroys the instance. */
+    public void destroy() {
+        if (DBG) Log.d(TAG, "destroy");
+        mConfigManager.unregisterCarrierConfigChangeListener(mCarrierConfigChangeListener);
+        mDataConnectionStateListeners.forEach((k, v) -> v.unregisterTelephonyCallback());
+    }
+}
diff --git a/src/com/android/services/telephony/domainselection/EmergencySmsDomainSelector.java b/src/com/android/services/telephony/domainselection/EmergencySmsDomainSelector.java
index aef193b..5adca5a 100644
--- a/src/com/android/services/telephony/domainselection/EmergencySmsDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/EmergencySmsDomainSelector.java
@@ -18,12 +18,17 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.os.CancellationSignal;
 import android.os.Looper;
+import android.os.Message;
 import android.os.PersistableBundle;
 import android.telephony.AccessNetworkConstants;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.BarringInfo;
 import android.telephony.CarrierConfigManager;
 import android.telephony.DataSpecificRegistrationInfo;
+import android.telephony.DomainSelectionService;
+import android.telephony.EmergencyRegResult;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
@@ -31,11 +36,14 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.util.List;
+
 /**
  * Implements an emergency SMS domain selector for sending an emergency SMS.
  */
 public class EmergencySmsDomainSelector extends SmsDomainSelector implements
         ImsStateTracker.BarringInfoListener, ImsStateTracker.ServiceStateListener {
+    protected static final int EVENT_EMERGENCY_NETWORK_SCAN_RESULT = 201;
     /**
      * Stores the configuration value of
      * {@link CarrierConfigManager#KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL}.
@@ -46,6 +54,8 @@
     private boolean mServiceStateReceived;
     private BarringInfo mBarringInfo;
     private boolean mBarringInfoReceived;
+    private boolean mEmergencyNetworkScanInProgress;
+    private CancellationSignal mEmergencyNetworkScanSignal;
 
     public EmergencySmsDomainSelector(Context context, int slotId, int subId,
             @NonNull Looper looper, @NonNull ImsStateTracker imsStateTracker,
@@ -68,6 +78,18 @@
     }
 
     @Override
+    public void handleMessage(@NonNull Message msg) {
+        switch (msg.what) {
+            case EVENT_EMERGENCY_NETWORK_SCAN_RESULT:
+                handleEmergencyNetworkScanResult((EmergencyRegResult) msg.obj);
+                break;
+            default:
+                super.handleMessage(msg);
+                break;
+        }
+    }
+
+    @Override
     public void finishSelection() {
         super.finishSelection();
         mServiceStateReceived = false;
@@ -75,6 +97,12 @@
         mBarringInfoReceived = false;
         mBarringInfo = null;
         mEmergencySmsOverImsSupportedByConfig = null;
+
+        mEmergencyNetworkScanInProgress = false;
+        if (mEmergencyNetworkScanSignal != null) {
+            mEmergencyNetworkScanSignal.cancel();
+            mEmergencyNetworkScanSignal = null;
+        }
     }
 
     @Override
@@ -111,7 +139,7 @@
              * when {@link CarrierConfigManager#KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL} is set
              * to true.
              */
-            if (isEmergencySmsOverImsSupportedIfLteLimitedOrInService()) {
+            if (isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService()) {
                 /**
                  * Emergency SMS should be supported via emergency PDN.
                  * If this condition is false, then need to fallback to CS network
@@ -139,60 +167,132 @@
             return;
         }
 
+        if (mEmergencyNetworkScanInProgress) {
+            logi("Emergency network scan is in progress.");
+            return;
+        }
+
         logi("selectDomain: " + mImsStateTracker.imsStateToString());
 
         if (isSmsOverImsAvailable()) {
-            boolean isEmergencySmsOverImsSupportedIfLteLimitedOrInService =
-                    isEmergencySmsOverImsSupportedIfLteLimitedOrInService();
+            boolean isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService =
+                    isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService();
 
             if (mImsStateTracker.isImsRegisteredOverWlan()) {
                 /**
                  * When {@link CarrierConfigManager#KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL}
-                 * is set to true, the emergency SMS supports on the LTE network using the
+                 * is set to true, the emergency SMS supports on the LTE/NR network using the
                  * emergency PDN. As of now, since the emergency SMS doesn't use the emergency PDN
                  * over WLAN, the domain selector reports the domain as WLAN only if
-                 * {@code isEmergencySmsOverImsSupportedIfLteLimitedOrInService} is set to false
+                 * {@code isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService} is set to false
                  * and IMS is registered over WLAN.
                  * Otherwise, the domain selector reports the domain as WWAN.
                  */
-                if (!isEmergencySmsOverImsSupportedIfLteLimitedOrInService) {
+                if (!isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService) {
                     notifyWlanSelected(false);
                     return;
                 }
 
                 logi("DomainSelected: WLAN >> WWAN");
             }
-            notifyWwanSelected(NetworkRegistrationInfo.DOMAIN_PS,
-                    isEmergencySmsOverImsSupportedIfLteLimitedOrInService);
+
+            /**
+             * The request of emergency network scan triggers the modem to request the emergency
+             * service fallback because NR network doesn't support the emergency service.
+             */
+            if (isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService
+                    && isNrEmergencyServiceFallbackRequired()) {
+                requestEmergencyNetworkScan(List.of(AccessNetworkType.EUTRAN));
+            } else {
+                notifyWwanSelected(NetworkRegistrationInfo.DOMAIN_PS,
+                        isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService);
+            }
         } else {
             notifyWwanSelected(NetworkRegistrationInfo.DOMAIN_CS, false);
         }
     }
 
+    private void requestEmergencyNetworkScan(List<Integer> preferredNetworks) {
+        mEmergencyNetworkScanInProgress = true;
+
+        if (mWwanSelectorCallback == null) {
+            mTransportSelectorCallback.onWwanSelected((callback) -> {
+                mWwanSelectorCallback = callback;
+                requestEmergencyNetworkScanInternal(preferredNetworks);
+            });
+        } else {
+            requestEmergencyNetworkScanInternal(preferredNetworks);
+        }
+    }
+
+    private void requestEmergencyNetworkScanInternal(List<Integer> preferredNetworks) {
+        logi("requestEmergencyNetworkScan: preferredNetworks=" + preferredNetworks);
+        mEmergencyNetworkScanSignal = new CancellationSignal();
+        mWwanSelectorCallback.onRequestEmergencyNetworkScan(
+                preferredNetworks,
+                DomainSelectionService.SCAN_TYPE_FULL_SERVICE, false,
+                mEmergencyNetworkScanSignal,
+                (regResult) -> {
+                    logi("requestEmergencyNetworkScan-onComplete");
+                    obtainMessage(EVENT_EMERGENCY_NETWORK_SCAN_RESULT, regResult).sendToTarget();
+                });
+    }
+
+    /**
+     * Handles the emergency network scan result.
+     *
+     * This triggers the emergency service fallback to modem when the emergency service is not
+     * supported but the emergency service fallback is supported in the current network.
+     *
+     * @param regResult The emergency registration result that is triggered
+     *                  by the emergency network scan.
+     */
+    private void handleEmergencyNetworkScanResult(EmergencyRegResult regResult) {
+        logi("handleEmergencyNetworkScanResult: " + regResult);
+
+        mEmergencyNetworkScanInProgress = false;
+        mEmergencyNetworkScanSignal = null;
+
+        int accessNetworkType = regResult.getAccessNetwork();
+        int domain = NetworkRegistrationInfo.DOMAIN_CS;
+
+        if (accessNetworkType == AccessNetworkType.NGRAN) {
+            domain = NetworkRegistrationInfo.DOMAIN_PS;
+        } else if (accessNetworkType == AccessNetworkType.EUTRAN) {
+            if (regResult.getDomain() == NetworkRegistrationInfo.DOMAIN_CS) {
+                logi("PS emergency service is not supported in LTE network.");
+            } else {
+                domain = NetworkRegistrationInfo.DOMAIN_PS;
+            }
+        }
+
+        notifyWwanSelected(domain, (domain == NetworkRegistrationInfo.DOMAIN_PS));
+    }
+
     /**
      * Checks if the emergency SMS messages over IMS is available according to the carrier
      * configuration and the current network states.
      */
     private boolean isImsEmergencySmsAvailable() {
-        boolean isEmergencySmsOverImsSupportedIfLteLimitedOrInService =
-                isEmergencySmsOverImsSupportedIfLteLimitedOrInService();
+        boolean isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService =
+                isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService();
         boolean networkAvailable = isNetworkAvailableForImsEmergencySms();
 
         logi("isImsEmergencySmsAvailable: "
-                + "emergencySmsOverIms=" + isEmergencySmsOverImsSupportedIfLteLimitedOrInService
+                + "emergencySmsOverIms=" + isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService
                 + ", mmTelFeatureAvailable=" + mImsStateTracker.isMmTelFeatureAvailable()
                 + ", networkAvailable=" + networkAvailable);
 
-        return isEmergencySmsOverImsSupportedIfLteLimitedOrInService
+        return isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService
                 && mImsStateTracker.isMmTelFeatureAvailable()
                 && networkAvailable;
     }
 
     /**
-     * Checks if sending emergency SMS messages over IMS is supported when in LTE/limited LTE
-     * (Emergency only) service mode from the carrier configuration.
+     * Checks if sending emergency SMS messages over IMS is supported when in the network(LTE/NR)
+     * normal/limited(Emergency only) service mode from the carrier configuration.
      */
-    private boolean isEmergencySmsOverImsSupportedIfLteLimitedOrInService() {
+    private boolean isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService() {
         if (mEmergencySmsOverImsSupportedByConfig == null) {
             CarrierConfigManager ccm = mContext.getSystemService(CarrierConfigManager.class);
 
@@ -257,7 +357,8 @@
      */
     private boolean isNetworkAvailableForImsEmergencySms() {
         return isLteEmergencyAvailableInService()
-                || isLteEmergencyAvailableInLimitedService();
+                || isLteEmergencyAvailableInLimitedService()
+                || isNrEmergencyAvailable();
     }
 
     /**
@@ -280,6 +381,22 @@
     }
 
     /**
+     * Checks if the emergency service fallback is supported by the network.
+     *
+     * @return {@code true} if the emergency service fallback is supported by the network,
+     *         {@code false} otherwise.
+     */
+    private boolean isEmergencyServiceFallbackSupported(@NonNull NetworkRegistrationInfo regInfo) {
+        final DataSpecificRegistrationInfo dsRegInfo = regInfo.getDataSpecificInfo();
+        if (dsRegInfo != null) {
+            final VopsSupportInfo vopsSupportInfo = dsRegInfo.getVopsSupportInfo();
+            return vopsSupportInfo != null
+                    && vopsSupportInfo.isEmergencyServiceFallbackSupported();
+        }
+        return false;
+    }
+
+    /**
      * Checks if the emergency service is allowed (not barred) by the network.
      *
      * This checks if SystemInformationBlockType2 includes the ac-BarringInfo and
@@ -297,4 +414,45 @@
                 mBarringInfo.getBarringServiceInfo(BarringInfo.BARRING_SERVICE_TYPE_EMERGENCY);
         return !bsi.isBarred();
     }
+
+    /**
+     * Checks if the emergency service fallback is available in the NR network
+     * because the emergency service is not supported.
+     */
+    private boolean isNrEmergencyServiceFallbackRequired() {
+        if (mServiceState == null) {
+            return false;
+        }
+
+        final NetworkRegistrationInfo regInfo = mServiceState.getNetworkRegistrationInfo(
+                NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+        if (regInfo != null
+                && regInfo.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_NR
+                && regInfo.isRegistered()) {
+            return !isEmergencyServiceSupported(regInfo)
+                    && isEmergencyServiceFallbackSupported(regInfo);
+        }
+        return false;
+    }
+
+    /**
+     * Checks if the emergency service is available in the NR network.
+     */
+    private boolean isNrEmergencyAvailable() {
+        if (mServiceState == null) {
+            return false;
+        }
+
+        final NetworkRegistrationInfo regInfo = mServiceState.getNetworkRegistrationInfo(
+                NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+        if (regInfo != null
+                && regInfo.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_NR
+                && regInfo.isRegistered()) {
+            return isEmergencyServiceSupported(regInfo)
+                    || isEmergencyServiceFallbackSupported(regInfo);
+        }
+        return false;
+    }
 }
diff --git a/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java b/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
index f85dabe..106bfea 100644
--- a/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
@@ -43,6 +43,7 @@
     private static final String LOG_TAG = "NCDS";
 
     private boolean mStopDomainSelection = true;
+    private boolean mDestroyed = false;
     private ServiceState mServiceState;
     private boolean mImsRegStateReceived;
     private boolean mMmTelCapabilitiesReceived;
@@ -79,7 +80,7 @@
             return;
         }
 
-        int subId = attributes.getSubId();
+        int subId = attributes.getSubscriptionId();
         boolean validSubscriptionId = SubscriptionManager.isValidSubscriptionId(subId);
         if (attributes.getSelectorType() != SELECTOR_TYPE_CALLING || attributes.isEmergency()
                 || !validSubscriptionId) {
@@ -116,19 +117,18 @@
         mImsStateTracker.removeImsStateListener(this);
         mSelectionAttributes = null;
         mTransportSelectorCallback = null;
+        destroy();
     }
 
     @Override
     public void destroy() {
-        finishSelection();
-        super.destroy();
+        logd("destroy");
+        if (!mDestroyed) {
+            mDestroyed = true;
+            super.destroy();
+        }
     }
 
-    /**
-     * Cancel an ongoing selection operation. It is up to the DomainSelectionService
-     * to clean up all ongoing operations with the framework.
-     */
-    @Override
     public void cancelSelection() {
         logd("cancelSelection");
         mStopDomainSelection = true;
@@ -238,7 +238,7 @@
 
         PersistableBundle config = null;
         if (configManager != null) {
-            config = configManager.getConfigForSubId(mSelectionAttributes.getSubId(),
+            config = configManager.getConfigForSubId(mSelectionAttributes.getSubscriptionId(),
                     new String[] {CarrierConfigManager.KEY_SUPPORT_WPS_OVER_IMS_BOOL});
         }
 
@@ -266,7 +266,7 @@
 
         PersistableBundle config = null;
         if (configManager != null) {
-            config = configManager.getConfigForSubId(mSelectionAttributes.getSubId(),
+            config = configManager.getConfigForSubId(mSelectionAttributes.getSubscriptionId(),
                     new String[] {CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL});
         }
 
@@ -382,7 +382,8 @@
         // Handle voice call.
         if (mImsStateTracker.isImsVoiceCapable()) {
             logd("IMS is voice capable");
-            if (PhoneNumberUtils.isWpsCallNumber(mSelectionAttributes.getNumber())) {
+            String number = mSelectionAttributes.getAddress().getSchemeSpecificPart();
+            if (PhoneNumberUtils.isWpsCallNumber(number)) {
                 handleWpsCall();
             } else {
                 notifyPsSelected();
diff --git a/src/com/android/services/telephony/domainselection/OWNERS b/src/com/android/services/telephony/domainselection/OWNERS
index b9112be..2a76770 100644
--- a/src/com/android/services/telephony/domainselection/OWNERS
+++ b/src/com/android/services/telephony/domainselection/OWNERS
@@ -6,3 +6,4 @@
 mkoon@google.com
 seheele@google.com
 radhikaagrawal@google.com
+jdyou@google.com
diff --git a/src/com/android/services/telephony/domainselection/SmsDomainSelector.java b/src/com/android/services/telephony/domainselection/SmsDomainSelector.java
index 95b04e2..4e41e43 100644
--- a/src/com/android/services/telephony/domainselection/SmsDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/SmsDomainSelector.java
@@ -71,12 +71,6 @@
     }
 
     @Override
-    public void cancelSelection() {
-        logi("cancelSelection");
-        finishSelection();
-    }
-
-    @Override
     public void reselectDomain(@NonNull SelectionAttributes attr) {
         if (isDomainSelectionRequested()) {
             // The domain selection is already requested,
diff --git a/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionService.java b/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionService.java
index 66894f7..c86eff9 100644
--- a/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionService.java
+++ b/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionService.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SuppressLint;
 import android.content.Context;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -74,7 +73,8 @@
                 @NonNull ImsStateTracker imsStateTracker,
                 @NonNull DomainSelectorBase.DestroyListener listener,
                 @NonNull CrossSimRedialingController crossSimRedialingController,
-                @NonNull CarrierConfigHelper carrierConfigHelper);
+                @NonNull CarrierConfigHelper carrierConfigHelper,
+                @NonNull EmergencyCallbackModeHelper emergencyCallbackModeHelper);
     }
 
     private static final class DefaultDomainSelectorFactory implements DomainSelectorFactory {
@@ -84,7 +84,8 @@
                 @NonNull ImsStateTracker imsStateTracker,
                 @NonNull DomainSelectorBase.DestroyListener listener,
                 @NonNull CrossSimRedialingController crossSimRedialingController,
-                @NonNull CarrierConfigHelper carrierConfigHelper) {
+                @NonNull CarrierConfigHelper carrierConfigHelper,
+                @NonNull EmergencyCallbackModeHelper emergencyCallbackModeHelper) {
             DomainSelectorBase selector = null;
 
             logi("create-DomainSelector: slotId=" + slotId + ", subId=" + subId
@@ -96,7 +97,7 @@
                     if (isEmergency) {
                         selector = new EmergencyCallDomainSelector(context, slotId, subId, looper,
                                 imsStateTracker, listener, crossSimRedialingController,
-                                carrierConfigHelper);
+                                carrierConfigHelper, emergencyCallbackModeHelper);
                     } else {
                         selector = new NormalCallDomainSelector(context, slotId, subId, looper,
                                 imsStateTracker, listener);
@@ -192,7 +193,7 @@
 
     // Persistent Logging
     private static final LocalLog sEventLog = new LocalLog(20);
-    private final Context mContext;
+    private Context mContext;
     // Map of slotId -> ImsStateTracker
     private final SparseArray<ImsStateTracker> mImsStateTrackers = new SparseArray<>(2);
     private final List<DomainSelectorContainer> mDomainSelectorContainers = new ArrayList<>();
@@ -201,22 +202,31 @@
     private Handler mServiceHandler;
     private CrossSimRedialingController mCrossSimRedialingController;
     private CarrierConfigHelper mCarrierConfigHelper;
+    private EmergencyCallbackModeHelper mEmergencyCallbackModeHelper;
 
-    public TelephonyDomainSelectionService(Context context) {
-        this(context, ImsStateTracker::new, new DefaultDomainSelectorFactory(), null);
+    /** Default constructor. */
+    public TelephonyDomainSelectionService() {
+        this(ImsStateTracker::new, new DefaultDomainSelectorFactory(), null, null);
     }
 
     @VisibleForTesting
-    public TelephonyDomainSelectionService(Context context,
+    protected TelephonyDomainSelectionService(
             @NonNull ImsStateTrackerFactory imsStateTrackerFactory,
             @NonNull DomainSelectorFactory domainSelectorFactory,
-            @Nullable CarrierConfigHelper carrierConfigHelper) {
-        mContext = context;
+            @Nullable CarrierConfigHelper carrierConfigHelper,
+            @Nullable EmergencyCallbackModeHelper ecbmHelper) {
         mImsStateTrackerFactory = imsStateTrackerFactory;
         mDomainSelectorFactory = domainSelectorFactory;
+        mCarrierConfigHelper = carrierConfigHelper;
+    }
+
+    @Override
+    public void onCreate() {
+        logd("onCreate");
+        mContext = getApplicationContext();
 
         // Create a worker thread for this domain selection service.
-        getExecutor();
+        onCreateExecutor();
 
         TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
         int activeModemCount = (tm != null) ? tm.getActiveModemCount() : 1;
@@ -231,9 +241,13 @@
             loge("Adding OnSubscriptionChangedListener failed");
         }
 
-        mCrossSimRedialingController = new CrossSimRedialingController(context, getLooper());
-        mCarrierConfigHelper = (carrierConfigHelper != null)
-                ? carrierConfigHelper : new CarrierConfigHelper(context, getLooper());
+        mCrossSimRedialingController = new CrossSimRedialingController(mContext, getLooper());
+        if (mCarrierConfigHelper == null) {
+            mCarrierConfigHelper = new CarrierConfigHelper(mContext, getLooper());
+        }
+        if (mEmergencyCallbackModeHelper == null) {
+            mEmergencyCallbackModeHelper = new EmergencyCallbackModeHelper(mContext, getLooper());
+        }
 
         logi("TelephonyDomainSelectionService created");
     }
@@ -282,6 +296,11 @@
             mCarrierConfigHelper = null;
         }
 
+        if (mEmergencyCallbackModeHelper != null) {
+            mEmergencyCallbackModeHelper.destroy();
+            mEmergencyCallbackModeHelper = null;
+        }
+
         if (mServiceHandler != null) {
             mServiceHandler.getLooper().quit();
             mServiceHandler = null;
@@ -297,14 +316,14 @@
     @Override
     public void onDomainSelection(@NonNull SelectionAttributes attr,
             @NonNull TransportSelectorCallback callback) {
-        final int slotId = attr.getSlotId();
-        final int subId = attr.getSubId();
+        final int slotId = attr.getSlotIndex();
+        final int subId = attr.getSubscriptionId();
         final int selectorType = attr.getSelectorType();
         final boolean isEmergency = attr.isEmergency();
         ImsStateTracker ist = getImsStateTracker(slotId);
         DomainSelectorBase selector = mDomainSelectorFactory.create(mContext, slotId, subId,
                 selectorType, isEmergency, getLooper(), ist, mDestroyListener,
-                mCrossSimRedialingController, mCarrierConfigHelper);
+                mCrossSimRedialingController, mCarrierConfigHelper, mEmergencyCallbackModeHelper);
 
         if (selector != null) {
             // Ensures that ImsStateTracker is started before selecting the domain if not started
@@ -313,15 +332,21 @@
             addDomainSelector(slotId, selectorType, isEmergency, selector);
         } else {
             loge("No proper domain selector: " + selectorTypeToString(selectorType));
-            callback.onSelectionTerminated(DisconnectCause.ERROR_UNSPECIFIED);
+            // Executed through the service handler to ensure that the callbacks are not called
+            // directly in this execution flow.
+            mServiceHandler.post(() ->
+                    callback.onSelectionTerminated(DisconnectCause.ERROR_UNSPECIFIED));
             return;
         }
 
-        // Notify the caller that the domain selector is created.
-        callback.onCreated(selector);
-
-        // Performs the domain selection.
-        selector.selectDomain(attr, callback);
+        // Executed through the service handler to ensure that the callbacks are not called
+        // directly in this execution flow.
+        mServiceHandler.post(() ->  {
+            // Notify the caller that the domain selector is created.
+            callback.onCreated(selector);
+            // Performs the domain selection.
+            selector.selectDomain(attr, callback);
+        });
     }
 
     /**
@@ -359,8 +384,15 @@
     /**
      *  Returns an Executor used to execute methods called remotely by the framework.
      */
-    @SuppressLint("OnNameExpected")
     @Override
+    public @NonNull Executor onCreateExecutor() {
+        return getExecutor();
+    }
+
+    /**
+     *  Returns an Executor used to execute methods called remotely by the framework.
+     */
+    @VisibleForTesting
     public @NonNull Executor getExecutor() {
         if (mServiceHandler == null) {
             HandlerThread handlerThread = new HandlerThread(TAG);
@@ -480,7 +512,6 @@
         switch (selectorType) {
             case SELECTOR_TYPE_CALLING: return "CALLING";
             case SELECTOR_TYPE_SMS: return "SMS";
-            case SELECTOR_TYPE_UT: return "UT";
             default: return Integer.toString(selectorType);
         }
     }
diff --git a/src/com/android/services/telephony/rcs/TransportSipMessageValidator.java b/src/com/android/services/telephony/rcs/TransportSipMessageValidator.java
index b15992e..3a8bdea 100644
--- a/src/com/android/services/telephony/rcs/TransportSipMessageValidator.java
+++ b/src/com/android/services/telephony/rcs/TransportSipMessageValidator.java
@@ -565,8 +565,8 @@
                         direction);
             } else {
                 //Message sending fail and there is no response.
-                mRcsStats.invalidatedMessageResult(mSubId, startLineSegments[0], direction,
-                        result.restrictedReason);
+                mRcsStats.invalidatedMessageResult(m.getCallIdParameter(), mSubId,
+                        startLineSegments[0], direction, result.restrictedReason);
             }
         } else if (SipMessageParsingUtils.isSipResponse(m.getStartLine())) {
             int statusCode = Integer.parseInt(startLineSegments[1]);
diff --git a/testapps/TestRcsApp/TestApp/AndroidManifest.xml b/testapps/TestRcsApp/TestApp/AndroidManifest.xml
index 35a0822..3ec9b69 100644
--- a/testapps/TestRcsApp/TestApp/AndroidManifest.xml
+++ b/testapps/TestRcsApp/TestApp/AndroidManifest.xml
@@ -56,6 +56,7 @@
         <activity android:name=".ContactListActivity" />
         <activity android:name=".ProvisioningActivity" />
         <activity android:name=".FileUploadActivity" />
+        <activity android:name=".carrierLock.CarrieLockModeListActivity" />
 
         <provider
             android:name=".util.ChatProvider"
@@ -117,6 +118,10 @@
             </intent-filter>
         </service>
 
+        <provider
+            android:name=".carrierLock.CarrierLockProvider"
+            android:authorities="com.sample.lockProvider"
+            android:exported="true" />
     </application>
 
 </manifest>
diff --git a/testapps/TestRcsApp/TestApp/lint-baseline.xml b/testapps/TestRcsApp/TestApp/lint-baseline.xml
index 8971388..872a626 100644
--- a/testapps/TestRcsApp/TestApp/lint-baseline.xml
+++ b/testapps/TestRcsApp/TestApp/lint-baseline.xml
@@ -1,26 +1,444 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.TelephonyManager#bootstrapAuthenticationRequest`"
-        errorLine1="            telephonyManager.bootstrapAuthenticationRequest(mUiccType,"
-        errorLine2="                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        message="Class requires API level 31 (current min is 30): `android.telephony.ims.stub.DelegateConnectionMessageCallback`"
+        errorLine1="            new DelegateConnectionMessageCallback() {"
+        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/GbaActivity.java"
-            line="130"
-            column="30"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="87"
+            column="17"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.gba.UaSecurityProtocolIdentifier.Builder#build`"
-        errorLine1="            UaSecurityProtocolIdentifier spId = builder.build();"
-        errorLine2="                                                        ~~~~~">
+        message="Class requires API level 31 (current min is 30): `android.telephony.ims.stub.DelegateConnectionStateCallback`"
+        errorLine1="            new DelegateConnectionStateCallback() {"
+        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="117"
+            column="17"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.FeatureTagState#getFeatureTag`"
+        errorLine1='                        stringBuilder.append(featureTagState.getFeatureTag()).append(" ").append('
+        errorLine2="                                                             ~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="148"
+            column="62"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.FeatureTagState#getState`"
+        errorLine1="                                featureTagState.getState());"
+        errorLine2="                                                ~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="149"
+            column="49"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.DelegateRegistrationState#getRegisteredFeatureTags`"
+        errorLine1="                    Set&lt;String&gt; registeredFt = registrationState.getRegisteredFeatureTags();"
+        errorLine2="                                                                 ~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="151"
+            column="66"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ImsManager#getSipDelegateManager`"
+        errorLine1="            mSipDelegateManager = imsManager.getSipDelegateManager(mDefaultSmsSubId);"
+        errorLine2="                                             ~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="220"
+            column="46"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateManager#createSipDelegate`"
+        errorLine1="                    mSipDelegateManager.createSipDelegate(new DelegateRequest(featureTags),"
+        errorLine2="                                        ~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="231"
+            column="41"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `new android.telephony.ims.DelegateRequest`"
+        errorLine1="                    mSipDelegateManager.createSipDelegate(new DelegateRequest(featureTags),"
+        errorLine2="                                                          ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="231"
+            column="59"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateManager#destroySipDelegate`"
+        errorLine1="                mSipDelegateManager.destroySipDelegate(mSipDelegateConnection,"
+        errorLine2="                                    ~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="247"
+            column="37"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateManager#destroySipDelegate`"
+        errorLine1="            mSipDelegateManager.destroySipDelegate(mSipDelegateConnection,"
+        errorLine2="                                ~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="322"
+            column="33"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getVersion`"
+        errorLine1='                + "mVersion=" + config.getVersion()'
+        errorLine2="                                       ~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="332"
+            column="40"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getTransportType`"
+        errorLine1='                + ", \n\tmTransportType=" + config.getTransportType()'
+        errorLine2="                                                   ~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="333"
+            column="52"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getLocalAddress`"
+        errorLine1='                + ", \n\tmLocalIpAddr=" + config.getLocalAddress()'
+        errorLine2="                                                 ~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="334"
+            column="50"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipServerAddress`"
+        errorLine1='                + ", \n\tmSipServerAddr=" + config.getSipServerAddress()'
+        errorLine2="                                                   ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="335"
+            column="52"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#isSipCompactFormEnabled`"
+        errorLine1='                + ", \n\tmIsSipCompactFormEnabled=" + config.isSipCompactFormEnabled()'
+        errorLine2="                                                             ~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="336"
+            column="62"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#isSipKeepaliveEnabled`"
+        errorLine1='                + ", \n\tmIsSipKeepaliveEnabled=" + config.isSipKeepaliveEnabled()'
+        errorLine2="                                                           ~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="337"
+            column="60"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getMaxUdpPayloadSizeBytes`"
+        errorLine1='                + ", \n\tmMaxUdpPayloadSize=" + config.getMaxUdpPayloadSizeBytes()'
+        errorLine2="                                                       ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="338"
+            column="56"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getPublicUserIdentifier`"
+        errorLine1='                + ", \n\tmPublicUserIdentifier=" + config.getPublicUserIdentifier()'
+        errorLine2="                                                          ~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="339"
+            column="59"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getPrivateUserIdentifier`"
+        errorLine1='                + ", \n\tmPrivateUserIdentifier=" + config.getPrivateUserIdentifier()'
+        errorLine2="                                                           ~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="340"
+            column="60"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getHomeDomain`"
+        errorLine1='                + ", \n\tmHomeDomain=" + config.getHomeDomain()'
+        errorLine2="                                                ~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="341"
+            column="49"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getImei`"
+        errorLine1='                + ", \n\tmImei=" + config.getImei()'
+        errorLine2="                                          ~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="342"
+            column="43"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getPublicGruuUri`"
+        errorLine1='                + ", \n\tmGruu=" + config.getPublicGruuUri()'
+        errorLine2="                                          ~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="343"
+            column="43"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipAuthenticationHeader`"
+        errorLine1='                + ", \n\tmSipAuthHeader=" + config.getSipAuthenticationHeader()'
+        errorLine2="                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="344"
+            column="52"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipAuthenticationNonce`"
+        errorLine1='                + ", \n\tmSipAuthNonce=" + config.getSipAuthenticationNonce()'
+        errorLine2="                                                  ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="345"
+            column="51"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipServiceRouteHeader`"
+        errorLine1='                + ", \n\tmServiceRouteHeader=" + config.getSipServiceRouteHeader()'
+        errorLine2="                                                        ~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="346"
+            column="57"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipPathHeader`"
+        errorLine1='                + ", \n\tmPathHeader=" + config.getSipPathHeader()'
+        errorLine2="                                                ~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="347"
+            column="49"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipUserAgentHeader`"
+        errorLine1='                + ", \n\tmUserAgentHeader=" + config.getSipUserAgentHeader()'
+        errorLine2="                                                     ~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="348"
+            column="54"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipContactUserParameter`"
+        errorLine1='                + ", \n\tmContactUserParam=" + config.getSipContactUserParameter()'
+        errorLine2="                                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="349"
+            column="55"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipPaniHeader`"
+        errorLine1='                + ", \n\tmPaniHeader=" + config.getSipPaniHeader()'
+        errorLine2="                                                ~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="350"
+            column="49"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipPlaniHeader`"
+        errorLine1='                + ", \n\tmPlaniHeader=" + config.getSipPlaniHeader()'
+        errorLine2="                                                 ~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="351"
+            column="50"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipCniHeader`"
+        errorLine1='                + ", \n\tmCniHeader=" + config.getSipCniHeader()'
+        errorLine2="                                               ~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="352"
+            column="48"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipAssociatedUriHeader`"
+        errorLine1='                + ", \n\tmAssociatedUriHeader=" + config.getSipAssociatedUriHeader()'
+        errorLine2="                                                         ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="353"
+            column="58"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getIpSecConfiguration`"
+        errorLine1='                + ", \n\tmIpSecConfiguration=" + config.getIpSecConfiguration()'
+        errorLine2="                                                        ~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="354"
+            column="57"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getNatSocketAddress`"
+        errorLine1="                + &quot;, \n\tmNatConfiguration=&quot; + config.getNatSocketAddress() + '}';"
+        errorLine2="                                                      ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            line="355"
+            column="55"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Class requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager.RcsProvisioningCallback`"
+        errorLine1="            new RcsProvisioningCallback() {"
+        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/FileUploadActivity.java"
+            line="89"
+            column="17"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#setRcsClientConfiguration`"
+        errorLine1="                mProvisioningManager.setRcsClientConfiguration(getDefaultClientConfiguration());"
+        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/FileUploadActivity.java"
+            line="220"
+            column="38"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#registerRcsProvisioningCallback`"
+        errorLine1="                mProvisioningManager.registerRcsProvisioningCallback(getMainExecutor(), mCallback);"
+        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/FileUploadActivity.java"
+            line="221"
+            column="38"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `new android.telephony.ims.RcsClientConfiguration`"
+        errorLine1="        return new RcsClientConfiguration("
+        errorLine2="               ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/FileUploadActivity.java"
+            line="231"
+            column="16"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#unregisterRcsProvisioningCallback`"
+        errorLine1="            mProvisioningManager.unregisterRcsProvisioningCallback(mCallback);"
+        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/FileUploadActivity.java"
+            line="348"
+            column="34"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `new android.telephony.gba.UaSecurityProtocolIdentifier.Builder`"
+        errorLine1="                    new UaSecurityProtocolIdentifier.Builder();"
+        errorLine2="                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/GbaActivity.java"
-            line="129"
-            column="57"/>
+            line="120"
+            column="21"/>
     </issue>
 
     <issue
@@ -58,134 +476,68 @@
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.DelegateRegistrationState#getRegisteredFeatureTags`"
-        errorLine1="                    Set&lt;String&gt; registeredFt = registrationState.getRegisteredFeatureTags();"
-        errorLine2="                                                                 ~~~~~~~~~~~~~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `android.telephony.gba.UaSecurityProtocolIdentifier.Builder#build`"
+        errorLine1="            UaSecurityProtocolIdentifier spId = builder.build();"
+        errorLine2="                                                        ~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="151"
-            column="66"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/GbaActivity.java"
+            line="129"
+            column="57"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.FeatureTagState#getFeatureTag`"
-        errorLine1='                        stringBuilder.append(featureTagState.getFeatureTag()).append(" ").append('
-        errorLine2="                                                             ~~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `android.telephony.TelephonyManager#bootstrapAuthenticationRequest`"
+        errorLine1="            telephonyManager.bootstrapAuthenticationRequest(mUiccType,"
+        errorLine2="                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="148"
-            column="62"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/GbaActivity.java"
+            line="130"
+            column="30"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.FeatureTagState#getState`"
-        errorLine1="                                featureTagState.getState());"
-        errorLine2="                                                ~~~~~~~~">
+        message="Cast to `BootstrapAuthenticationCallback` requires API level 31 (current min is 30)"
+        errorLine1="                    new BootstrapAuthenticationCallback() {"
+        errorLine2="                    ^">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="149"
-            column="49"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/GbaActivity.java"
+            line="135"
+            column="21"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ImsManager#getSipDelegateManager`"
-        errorLine1="            mSipDelegateManager = imsManager.getSipDelegateManager(mDefaultSmsSubId);"
-        errorLine2="                                             ~~~~~~~~~~~~~~~~~~~~~">
+        message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyManager.BootstrapAuthenticationCallback`"
+        errorLine1="                    new BootstrapAuthenticationCallback() {"
+        errorLine2="                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="220"
-            column="46"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/GbaActivity.java"
+            line="135"
+            column="25"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#isRcsVolteSingleRegistrationCapable`"
-        errorLine1="                    boolean capable = mProvisioningManager.isRcsVolteSingleRegistrationCapable();"
-        errorLine2="                                                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        message="Class requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager.RcsProvisioningCallback`"
+        errorLine1="            new RcsProvisioningCallback() {"
+        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ProvisioningActivity.java"
-            line="204"
-            column="60"/>
+            line="80"
+            column="17"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#isRcsVolteSingleRegistrationCapable`"
-        errorLine1="            mProvisioningManager.isRcsVolteSingleRegistrationCapable();"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `new android.telephony.ims.RcsClientConfiguration`"
+        errorLine1="        return new RcsClientConfiguration("
+        errorLine2="               ~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ProvisioningActivity.java"
-            line="166"
-            column="34"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#registerRcsProvisioningCallback`"
-        errorLine1="                    mProvisioningManager.registerRcsProvisioningCallback(mExecutorService,"
-        errorLine2="                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ProvisioningActivity.java"
-            line="181"
-            column="42"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#registerRcsProvisioningCallback`"
-        errorLine1="                mProvisioningManager.registerRcsProvisioningCallback(getMainExecutor(), mCallback);"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/FileUploadActivity.java"
-            line="221"
-            column="38"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#setRcsClientConfiguration`"
-        errorLine1="                    mProvisioningManager.setRcsClientConfiguration(getDefaultClientConfiguration());"
-        errorLine2="                                         ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ProvisioningActivity.java"
-            line="180"
-            column="42"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#setRcsClientConfiguration`"
-        errorLine1="                mProvisioningManager.setRcsClientConfiguration(getDefaultClientConfiguration());"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/FileUploadActivity.java"
-            line="220"
-            column="38"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#unregisterRcsProvisioningCallback`"
-        errorLine1="                mProvisioningManager.unregisterRcsProvisioningCallback(mCallback);"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ProvisioningActivity.java"
-            line="195"
-            column="38"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#unregisterRcsProvisioningCallback`"
-        errorLine1="            mProvisioningManager.unregisterRcsProvisioningCallback(mCallback);"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/FileUploadActivity.java"
-            line="348"
-            column="34"/>
+            line="106"
+            column="16"/>
     </issue>
 
     <issue
@@ -201,122 +553,122 @@
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactPresenceTuple#getContactUri`"
-        errorLine1="                b.append(t.getContactUri());"
-        errorLine2="                           ~~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#isRcsVolteSingleRegistrationCapable`"
+        errorLine1="            mProvisioningManager.isRcsVolteSingleRegistrationCapable();"
+        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
-            line="220"
-            column="28"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ProvisioningActivity.java"
+            line="166"
+            column="34"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactPresenceTuple#getServiceCapabilities`"
-        errorLine1="                            t.getServiceCapabilities();"
-        errorLine2="                              ~~~~~~~~~~~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#setRcsClientConfiguration`"
+        errorLine1="                    mProvisioningManager.setRcsClientConfiguration(getDefaultClientConfiguration());"
+        errorLine2="                                         ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
-            line="227"
-            column="31"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ProvisioningActivity.java"
+            line="180"
+            column="42"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactPresenceTuple#getServiceCapabilities`"
-        errorLine1="                if (t.getServiceCapabilities() != null) {"
-        errorLine2="                      ~~~~~~~~~~~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#registerRcsProvisioningCallback`"
+        errorLine1="                    mProvisioningManager.registerRcsProvisioningCallback(mExecutorService,"
+        errorLine2="                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
-            line="225"
-            column="23"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ProvisioningActivity.java"
+            line="181"
+            column="42"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactPresenceTuple#getServiceId`"
-        errorLine1="                b.append(t.getServiceId());"
-        errorLine2="                           ~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#unregisterRcsProvisioningCallback`"
+        errorLine1="                mProvisioningManager.unregisterRcsProvisioningCallback(mCallback);"
+        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
-            line="222"
-            column="28"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ProvisioningActivity.java"
+            line="195"
+            column="38"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactPresenceTuple#getServiceVersion`"
-        errorLine1="                b.append(t.getServiceVersion());"
-        errorLine2="                           ~~~~~~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#isRcsVolteSingleRegistrationCapable`"
+        errorLine1="                    boolean capable = mProvisioningManager.isRcsVolteSingleRegistrationCapable();"
+        errorLine2="                                                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
-            line="224"
-            column="28"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ProvisioningActivity.java"
+            line="204"
+            column="60"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities#getSupportedDuplexModes`"
-        errorLine1="                    b.append(servCaps.getSupportedDuplexModes());"
-        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
-            line="233"
-            column="39"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities#getUnsupportedDuplexModes`"
-        errorLine1="                    b.append(servCaps.getUnsupportedDuplexModes());"
-        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
-            line="235"
-            column="39"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities#isAudioCapable`"
-        errorLine1="                    b.append(servCaps.isAudioCapable());"
-        errorLine2="                                      ~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
-            line="229"
-            column="39"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities#isVideoCapable`"
-        errorLine1="                    b.append(servCaps.isVideoCapable());"
-        errorLine2="                                      ~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
-            line="231"
-            column="39"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactUceCapability#getCapabilityMechanism`"
-        errorLine1="        if (c.getCapabilityMechanism() == RcsContactUceCapability.CAPABILITY_MECHANISM_PRESENCE) {"
-        errorLine2="              ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
-            line="216"
-            column="15"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactUceCapability#getCapabilityTuples`"
-        errorLine1="            for (RcsContactPresenceTuple t : c.getCapabilityTuples()) {"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsUceAdapter#requestCapabilities`"
+        errorLine1="                mImsRcsManager.getUceAdapter().requestCapabilities(contactList, getMainExecutor(),"
         errorLine2="                                               ~~~~~~~~~~~~~~~~~~~">
         <location
             file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
-            line="218"
+            line="95"
+            column="48"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Cast to `CapabilitiesCallback` requires API level 31 (current min is 30)"
+        errorLine1="                        new RcsUceAdapter.CapabilitiesCallback() {"
+        errorLine2="                        ^">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
+            line="96"
+            column="25"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Class requires API level 31 (current min is 30): `android.telephony.ims.RcsUceAdapter.CapabilitiesCallback`"
+        errorLine1="                        new RcsUceAdapter.CapabilitiesCallback() {"
+        errorLine2="                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
+            line="96"
+            column="29"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsUceAdapter#requestAvailability`"
+        errorLine1="                mImsRcsManager.getUceAdapter().requestAvailability(contactList.get(0),"
+        errorLine2="                                               ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
+            line="135"
+            column="48"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Cast to `CapabilitiesCallback` requires API level 31 (current min is 30)"
+        errorLine1="                        getMainExecutor(), new RcsUceAdapter.CapabilitiesCallback() {"
+        errorLine2="                                           ^">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
+            line="136"
+            column="44"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Class requires API level 31 (current min is 30): `android.telephony.ims.RcsUceAdapter.CapabilitiesCallback`"
+        errorLine1="                        getMainExecutor(), new RcsUceAdapter.CapabilitiesCallback() {"
+        errorLine2="                                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
+            line="136"
             column="48"/>
     </issue>
 
@@ -355,475 +707,123 @@
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsUceAdapter#requestAvailability`"
-        errorLine1="                mImsRcsManager.getUceAdapter().requestAvailability(contactList.get(0),"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactUceCapability#getCapabilityMechanism`"
+        errorLine1="        if (c.getCapabilityMechanism() == RcsContactUceCapability.CAPABILITY_MECHANISM_PRESENCE) {"
+        errorLine2="              ~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
+            line="216"
+            column="15"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactUceCapability#getCapabilityTuples`"
+        errorLine1="            for (RcsContactPresenceTuple t : c.getCapabilityTuples()) {"
         errorLine2="                                               ~~~~~~~~~~~~~~~~~~~">
         <location
             file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
-            line="135"
+            line="218"
             column="48"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsUceAdapter#requestCapabilities`"
-        errorLine1="                mImsRcsManager.getUceAdapter().requestCapabilities(contactList, getMainExecutor(),"
-        errorLine2="                                               ~~~~~~~~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactPresenceTuple#getContactUri`"
+        errorLine1="                b.append(t.getContactUri());"
+        errorLine2="                           ~~~~~~~~~~~~~">
         <location
             file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
-            line="95"
-            column="48"/>
+            line="220"
+            column="28"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getHomeDomain`"
-        errorLine1='                + ", \n\tmHomeDomain=" + config.getHomeDomain()'
-        errorLine2="                                                ~~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactPresenceTuple#getServiceId`"
+        errorLine1="                b.append(t.getServiceId());"
+        errorLine2="                           ~~~~~~~~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="341"
-            column="49"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
+            line="222"
+            column="28"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getImei`"
-        errorLine1='                + ", \n\tmImei=" + config.getImei()'
-        errorLine2="                                          ~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactPresenceTuple#getServiceVersion`"
+        errorLine1="                b.append(t.getServiceVersion());"
+        errorLine2="                           ~~~~~~~~~~~~~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="342"
-            column="43"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
+            line="224"
+            column="28"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getIpSecConfiguration`"
-        errorLine1='                + ", \n\tmIpSecConfiguration=" + config.getIpSecConfiguration()'
-        errorLine2="                                                        ~~~~~~~~~~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactPresenceTuple#getServiceCapabilities`"
+        errorLine1="                if (t.getServiceCapabilities() != null) {"
+        errorLine2="                      ~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="354"
-            column="57"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
+            line="225"
+            column="23"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getLocalAddress`"
-        errorLine1='                + ", \n\tmLocalIpAddr=" + config.getLocalAddress()'
-        errorLine2="                                                 ~~~~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactPresenceTuple#getServiceCapabilities`"
+        errorLine1="                            t.getServiceCapabilities();"
+        errorLine2="                              ~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="334"
-            column="50"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
+            line="227"
+            column="31"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getMaxUdpPayloadSizeBytes`"
-        errorLine1='                + ", \n\tmMaxUdpPayloadSize=" + config.getMaxUdpPayloadSizeBytes()'
-        errorLine2="                                                       ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities#isAudioCapable`"
+        errorLine1="                    b.append(servCaps.isAudioCapable());"
+        errorLine2="                                      ~~~~~~~~~~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="338"
-            column="56"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
+            line="229"
+            column="39"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getNatSocketAddress`"
-        errorLine1="                + &quot;, \n\tmNatConfiguration=&quot; + config.getNatSocketAddress() + '}';"
-        errorLine2="                                                      ~~~~~~~~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities#isVideoCapable`"
+        errorLine1="                    b.append(servCaps.isVideoCapable());"
+        errorLine2="                                      ~~~~~~~~~~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="355"
-            column="55"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getPrivateUserIdentifier`"
-        errorLine1='                + ", \n\tmPrivateUserIdentifier=" + config.getPrivateUserIdentifier()'
-        errorLine2="                                                           ~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="340"
-            column="60"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getPublicGruuUri`"
-        errorLine1='                + ", \n\tmGruu=" + config.getPublicGruuUri()'
-        errorLine2="                                          ~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="343"
-            column="43"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getPublicUserIdentifier`"
-        errorLine1='                + ", \n\tmPublicUserIdentifier=" + config.getPublicUserIdentifier()'
-        errorLine2="                                                          ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="339"
-            column="59"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipAssociatedUriHeader`"
-        errorLine1='                + ", \n\tmAssociatedUriHeader=" + config.getSipAssociatedUriHeader()'
-        errorLine2="                                                         ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="353"
-            column="58"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipAuthenticationHeader`"
-        errorLine1='                + ", \n\tmSipAuthHeader=" + config.getSipAuthenticationHeader()'
-        errorLine2="                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="344"
-            column="52"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipAuthenticationNonce`"
-        errorLine1='                + ", \n\tmSipAuthNonce=" + config.getSipAuthenticationNonce()'
-        errorLine2="                                                  ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="345"
-            column="51"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipCniHeader`"
-        errorLine1='                + ", \n\tmCniHeader=" + config.getSipCniHeader()'
-        errorLine2="                                               ~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="352"
-            column="48"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipContactUserParameter`"
-        errorLine1='                + ", \n\tmContactUserParam=" + config.getSipContactUserParameter()'
-        errorLine2="                                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="349"
-            column="55"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipPaniHeader`"
-        errorLine1='                + ", \n\tmPaniHeader=" + config.getSipPaniHeader()'
-        errorLine2="                                                ~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="350"
-            column="49"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipPathHeader`"
-        errorLine1='                + ", \n\tmPathHeader=" + config.getSipPathHeader()'
-        errorLine2="                                                ~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="347"
-            column="49"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipPlaniHeader`"
-        errorLine1='                + ", \n\tmPlaniHeader=" + config.getSipPlaniHeader()'
-        errorLine2="                                                 ~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="351"
-            column="50"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipServerAddress`"
-        errorLine1='                + ", \n\tmSipServerAddr=" + config.getSipServerAddress()'
-        errorLine2="                                                   ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="335"
-            column="52"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipServiceRouteHeader`"
-        errorLine1='                + ", \n\tmServiceRouteHeader=" + config.getSipServiceRouteHeader()'
-        errorLine2="                                                        ~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="346"
-            column="57"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipUserAgentHeader`"
-        errorLine1='                + ", \n\tmUserAgentHeader=" + config.getSipUserAgentHeader()'
-        errorLine2="                                                     ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="348"
-            column="54"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getTransportType`"
-        errorLine1='                + ", \n\tmTransportType=" + config.getTransportType()'
-        errorLine2="                                                   ~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="333"
-            column="52"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getVersion`"
-        errorLine1='                + "mVersion=" + config.getVersion()'
-        errorLine2="                                       ~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="332"
-            column="40"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#isSipCompactFormEnabled`"
-        errorLine1='                + ", \n\tmIsSipCompactFormEnabled=" + config.isSipCompactFormEnabled()'
-        errorLine2="                                                             ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="336"
-            column="62"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#isSipKeepaliveEnabled`"
-        errorLine1='                + ", \n\tmIsSipKeepaliveEnabled=" + config.isSipKeepaliveEnabled()'
-        errorLine2="                                                           ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="337"
-            column="60"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateManager#createSipDelegate`"
-        errorLine1="                    mSipDelegateManager.createSipDelegate(new DelegateRequest(featureTags),"
-        errorLine2="                                        ~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
+            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
             line="231"
-            column="41"/>
+            column="39"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateManager#destroySipDelegate`"
-        errorLine1="                mSipDelegateManager.destroySipDelegate(mSipDelegateConnection,"
-        errorLine2="                                    ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="247"
-            column="37"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateManager#destroySipDelegate`"
-        errorLine1="            mSipDelegateManager.destroySipDelegate(mSipDelegateConnection,"
-        errorLine2="                                ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="322"
-            column="33"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `new android.telephony.gba.UaSecurityProtocolIdentifier.Builder`"
-        errorLine1="                    new UaSecurityProtocolIdentifier.Builder();"
-        errorLine2="                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/GbaActivity.java"
-            line="120"
-            column="21"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `new android.telephony.ims.DelegateRequest`"
-        errorLine1="                    mSipDelegateManager.createSipDelegate(new DelegateRequest(featureTags),"
-        errorLine2="                                                          ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="231"
-            column="59"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `new android.telephony.ims.RcsClientConfiguration`"
-        errorLine1="        return new RcsClientConfiguration("
-        errorLine2="               ~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/FileUploadActivity.java"
-            line="231"
-            column="16"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `new android.telephony.ims.RcsClientConfiguration`"
-        errorLine1="        return new RcsClientConfiguration("
-        errorLine2="               ~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ProvisioningActivity.java"
-            line="106"
-            column="16"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Cast to `BootstrapAuthenticationCallback` requires API level 31 (current min is 30)"
-        errorLine1="                    new BootstrapAuthenticationCallback() {"
-        errorLine2="                    ^">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/GbaActivity.java"
-            line="135"
-            column="21"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Cast to `CapabilitiesCallback` requires API level 31 (current min is 30)"
-        errorLine1="                        getMainExecutor(), new RcsUceAdapter.CapabilitiesCallback() {"
-        errorLine2="                                           ^">
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities#getSupportedDuplexModes`"
+        errorLine1="                    b.append(servCaps.getSupportedDuplexModes());"
+        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
-            line="136"
-            column="44"/>
+            line="233"
+            column="39"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Cast to `CapabilitiesCallback` requires API level 31 (current min is 30)"
-        errorLine1="                        new RcsUceAdapter.CapabilitiesCallback() {"
-        errorLine2="                        ^">
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities#getUnsupportedDuplexModes`"
+        errorLine1="                    b.append(servCaps.getUnsupportedDuplexModes());"
+        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
-            line="96"
-            column="25"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyManager.BootstrapAuthenticationCallback`"
-        errorLine1="                    new BootstrapAuthenticationCallback() {"
-        errorLine2="                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/GbaActivity.java"
-            line="135"
-            column="25"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Class requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager.RcsProvisioningCallback`"
-        errorLine1="            new RcsProvisioningCallback() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/FileUploadActivity.java"
-            line="89"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Class requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager.RcsProvisioningCallback`"
-        errorLine1="            new RcsProvisioningCallback() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/ProvisioningActivity.java"
-            line="80"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Class requires API level 31 (current min is 30): `android.telephony.ims.RcsUceAdapter.CapabilitiesCallback`"
-        errorLine1="                        getMainExecutor(), new RcsUceAdapter.CapabilitiesCallback() {"
-        errorLine2="                                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
-            line="136"
-            column="48"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Class requires API level 31 (current min is 30): `android.telephony.ims.RcsUceAdapter.CapabilitiesCallback`"
-        errorLine1="                        new RcsUceAdapter.CapabilitiesCallback() {"
-        errorLine2="                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/UceActivity.java"
-            line="96"
-            column="29"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Class requires API level 31 (current min is 30): `android.telephony.ims.stub.DelegateConnectionMessageCallback`"
-        errorLine1="            new DelegateConnectionMessageCallback() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="87"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Class requires API level 31 (current min is 30): `android.telephony.ims.stub.DelegateConnectionStateCallback`"
-        errorLine1="            new DelegateConnectionStateCallback() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java"
-            line="117"
-            column="17"/>
+            line="235"
+            column="39"/>
     </issue>
 
 </issues>
\ No newline at end of file
diff --git a/testapps/TestRcsApp/TestApp/res/layout/CarrierLockListLayout.xml b/testapps/TestRcsApp/TestApp/res/layout/CarrierLockListLayout.xml
new file mode 100644
index 0000000..f07c65c
--- /dev/null
+++ b/testapps/TestRcsApp/TestApp/res/layout/CarrierLockListLayout.xml
@@ -0,0 +1,77 @@
+<!--
+  ~ 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.
+  -->
+
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".MainActivity">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <Button
+            android:id="@+id/noLockMode"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/no_LockMode"
+            android:textAlignment="center"
+            android:textAllCaps="false" />
+
+        <Button
+            android:id="@+id/lockToVZW"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/no_LockTo_VZW"
+            android:textAlignment="center"
+            android:textAllCaps="false" />
+
+        <Button
+            android:id="@+id/lockToATT"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/no_LockTo_ATT"
+            android:textAlignment="center"
+            android:textAllCaps="false" />
+
+        <Button
+            android:id="@+id/lockToTMO"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/no_LockTo_TMO"
+            android:textAlignment="center"
+            android:textAllCaps="false" />
+
+        <Button
+            android:id="@+id/lockToKOODOS"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/no_LockTo_KOODOS"
+            android:textAlignment="center"
+            android:textAllCaps="false" />
+
+        <Button
+            android:id="@+id/lockToTELUS"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/no_LockTo_TELUS"
+            android:textAlignment="center"
+            android:textAllCaps="false" />
+    </LinearLayout>
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/testapps/TestRcsApp/TestApp/res/layout/activity_main.xml b/testapps/TestRcsApp/TestApp/res/layout/activity_main.xml
index 939feb0..ebf5508 100644
--- a/testapps/TestRcsApp/TestApp/res/layout/activity_main.xml
+++ b/testapps/TestRcsApp/TestApp/res/layout/activity_main.xml
@@ -74,6 +74,14 @@
             android:textAlignment="center"
             android:textAllCaps="false" />
 
+        <Button
+            android:id="@+id/setCarrierLockMode"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/setCarrierLockMode"
+            android:textAlignment="center"
+            android:textAllCaps="false"/>
+
         <TextView
             android:id="@+id/version_info"
             android:layout_width="match_parent"
diff --git a/testapps/TestRcsApp/TestApp/res/values/donottranslate_strings.xml b/testapps/TestRcsApp/TestApp/res/values/donottranslate_strings.xml
index f52b70d..b017139 100644
--- a/testapps/TestRcsApp/TestApp/res/values/donottranslate_strings.xml
+++ b/testapps/TestRcsApp/TestApp/res/values/donottranslate_strings.xml
@@ -72,6 +72,8 @@
     <string name="browse">Browse</string>
     <string name="upload">Upload</string>
     <string name="upload_file_gba">Upload File with GBA</string>
+    <string name="setCarrierLockMode">CarrierLock</string>
+
     <string name="invalid_parameters">Invalid Parameters</string>
     <string name="server">Server:</string>
     <string name="file_name">File Name:</string>
@@ -79,6 +81,13 @@
     <string name="file_empty">File is empty</string>
     <string name="version_info">Version: %s</string>
 
+    <string name="no_LockMode">NoLock/ UnLocked</string>
+    <string name="no_LockTo_VZW">Lock to Verizon</string>
+    <string name="no_LockTo_ATT">Lock to ATT</string>
+    <string name="no_LockTo_TMO">Lock to TMO</string>
+    <string name="no_LockTo_KOODOS">Lock to KOODO</string>
+    <string name="no_LockTo_TELUS">Lock to TELUS</string>
+
     <string-array name="rcs_profile">
         <item>UP_1.0</item>
         <item>UP_2.3</item>
diff --git a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/MainActivity.java b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/MainActivity.java
index 89c5268..5d2db73 100644
--- a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/MainActivity.java
+++ b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/MainActivity.java
@@ -29,6 +29,8 @@
 
 import androidx.appcompat.app.AppCompatActivity;
 
+import com.google.android.sample.rcsclient.carrierLock.CarrieLockModeListActivity;
+
 /** An activity to show function list. */
 public class MainActivity extends AppCompatActivity {
     private static final String TAG = "TestRcsApp.MainActivity";
@@ -39,6 +41,7 @@
     private Button mMessageClientButton;
     private Button mFileUploadButton;
     private TextView mVersionInfo;
+    private Button mCarrierLockModeListBtn;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -56,6 +59,7 @@
         mGbaButton = (Button) this.findViewById(R.id.gba);
         mFileUploadButton = findViewById(R.id.uploadFile);
         mVersionInfo = this.findViewById(R.id.version_info);
+        mCarrierLockModeListBtn = findViewById(R.id.setCarrierLockMode);
         mProvisionButton.setOnClickListener(view -> {
             Intent intent = new Intent(this, ProvisioningActivity.class);
             MainActivity.this.startActivity(intent);
@@ -90,6 +94,11 @@
                     appVersionName);
             mVersionInfo.setText(version);
         }
+
+        mCarrierLockModeListBtn.setOnClickListener(view -> {
+            Intent intent = new Intent(this, CarrieLockModeListActivity.class);
+            MainActivity.this.startActivity(intent);
+        });
     }
 
     @Override
diff --git a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/carrierLock/CarrieLockModeListActivity.java b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/carrierLock/CarrieLockModeListActivity.java
new file mode 100644
index 0000000..6547aeb
--- /dev/null
+++ b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/carrierLock/CarrieLockModeListActivity.java
@@ -0,0 +1,79 @@
+/*
+ * 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.google.android.sample.rcsclient.carrierLock;
+
+import android.os.Bundle;
+import android.widget.Button;
+import android.widget.Toast;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.google.android.sample.rcsclient.R;
+
+public class CarrieLockModeListActivity extends AppCompatActivity {
+
+    private final CarrierLockProvider mCarrierLockProvider = new CarrierLockProvider();
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.CarrierLockListLayout);
+
+        Button noLockModeBtn = this.findViewById(R.id.noLockMode);
+        assert noLockModeBtn != null;
+        noLockModeBtn.setOnClickListener(view -> {
+            mCarrierLockProvider.setLockMode(CarrierRestriction.UNLOCKED);
+            Toast.makeText(this, "Lock mode set to UNLOCKED", Toast.LENGTH_LONG).show();
+        });
+
+        Button vzwLockModeBtn = this.findViewById(R.id.lockToVZW);
+        assert vzwLockModeBtn != null;
+        vzwLockModeBtn.setOnClickListener(view -> {
+            mCarrierLockProvider.setLockMode(CarrierRestriction.LOCK_TO_VZW);
+            Toast.makeText(this, "Lock mode set to VZW", Toast.LENGTH_LONG).show();
+        });
+
+        Button attLockModeBtn = this.findViewById(R.id.lockToATT);
+        assert attLockModeBtn != null;
+        attLockModeBtn.setOnClickListener(view -> {
+            mCarrierLockProvider.setLockMode(CarrierRestriction.LOCK_TO_ATT);
+            Toast.makeText(this, "Lock mode set to ATT", Toast.LENGTH_LONG).show();
+        });
+
+        Button tmoLockModeBtn = this.findViewById(R.id.lockToTMO);
+        assert tmoLockModeBtn != null;
+        tmoLockModeBtn.setOnClickListener(view -> {
+            mCarrierLockProvider.setLockMode(CarrierRestriction.LOCK_TO_TMO);
+            Toast.makeText(this, "Lock mode set to TMO", Toast.LENGTH_LONG).show();
+        });
+
+        Button koodoLockModeBtn = this.findViewById(R.id.lockToKOODOS);
+        assert koodoLockModeBtn != null;
+        koodoLockModeBtn.setOnClickListener(view -> {
+            mCarrierLockProvider.setLockMode(CarrierRestriction.LOCK_TO_KOODO);
+            Toast.makeText(this, "Lock mode set to KOODO", Toast.LENGTH_LONG).show();
+        });
+
+        Button telusLockModeBtn = this.findViewById(R.id.lockToTELUS);
+        assert telusLockModeBtn != null;
+        telusLockModeBtn.setOnClickListener(view -> {
+            mCarrierLockProvider.setLockMode(CarrierRestriction.LOCK_TO_TELUS);
+            Toast.makeText(this, "Lock mode set to TELUS", Toast.LENGTH_LONG).show();
+        });
+    }
+}
diff --git a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/carrierLock/CarrierLockProvider.java b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/carrierLock/CarrierLockProvider.java
new file mode 100644
index 0000000..8fa3cd6
--- /dev/null
+++ b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/carrierLock/CarrierLockProvider.java
@@ -0,0 +1,175 @@
+/*
+ * 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.google.android.sample.rcsclient.carrierLock;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringJoiner;
+
+public class CarrierLockProvider extends ContentProvider {
+
+    public static final String AUTHORITY = "com.sample.lockProvider";
+    public static final String TAG = "TestCarrierLockProvider";
+
+    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/carrierLock");
+    // content://com.sample.lockProvider/carrierLock
+
+    private static CarrierRestriction mLockMode = CarrierRestriction.UNLOCKED;
+    private static final ArrayList<Integer> mCarrierIds = new ArrayList<>();
+
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    @Override
+    public Bundle call(String method, String args, Bundle extras) {
+        Bundle result = new Bundle();
+        Log.d(TAG, "call query STARTED on method = " + method);
+        switch (method) {
+            case "getCarrierRestrictionStatus":
+                try {
+                    if (mLockMode == CarrierRestriction.UNLOCKED) {
+                        result.putInt("restriction_status", 0); // Unlocked
+                    } else {
+                        result.putInt("restriction_status", 2); // Locked/Restricted
+                    }
+                    mCarrierIds.clear();
+                    Log.d(TAG, "Query come : Lock mode set to " + mLockMode);
+                    switch (mLockMode) {
+                        case UNLOCKED:
+                            // Do Nothing
+                            break;
+                        case LOCK_TO_VZW:
+                            mCarrierIds.add(1839);
+                            break;
+                        case LOCK_TO_ATT:
+                            mCarrierIds.add(1187);
+                            mCarrierIds.add(10021);
+                            mCarrierIds.add(2119);
+                            mCarrierIds.add(2120);
+                            mCarrierIds.add(1779);
+                            mCarrierIds.add(10028);
+                            break;
+                        case LOCK_TO_TMO:
+                            mCarrierIds.add(1);
+                            break;
+                        case LOCK_TO_KOODO:
+                            mCarrierIds.add(2020);
+                            break;
+                        case LOCK_TO_TELUS:
+                            mCarrierIds.add(1404);
+                            break;
+                        default:
+                            // Nothing
+                    }
+                    StringJoiner joiner = new StringJoiner(", ");
+                    if (!mCarrierIds.isEmpty()) {
+                        result.putIntegerArrayList("allowed_carrier_ids", mCarrierIds);
+                        for (Integer num : mCarrierIds) {
+                            joiner.add(num.toString());
+                        }
+                        result.putString("PrintableCarrierIds", joiner.toString());
+                        Log.d(TAG, "Locked to carrierIds = " + joiner.toString());
+                    } else {
+                        result.putString("allowed_carrier_ids", "");
+                        result.putString("PrintableCarrierIds", "");
+                    }
+
+                } catch (Exception e) {
+                    Log.e(TAG, " call :: query :: exception = " + e.getMessage());
+                }
+                return result;
+
+            case "getList:":
+                String list = String.valueOf(
+                        mCarrierIds.size());
+                result.putString("carrierList", list);
+                return result;
+            default:
+                return null;
+        }
+    }
+
+    private void updateLockValue(int lockValue) {
+        Log.d(TAG, "updateLockValue through ADB to = " + lockValue);
+        switch (lockValue) {
+            case 1:
+                mLockMode = CarrierRestriction.LOCK_TO_VZW;
+                break;
+            case 2:
+                mLockMode = CarrierRestriction.LOCK_TO_ATT;
+                break;
+            case 3:
+                mLockMode = CarrierRestriction.LOCK_TO_TMO;
+                break;
+            case 4:
+                mLockMode = CarrierRestriction.LOCK_TO_KOODO;
+                break;
+            case 5:
+                mLockMode = CarrierRestriction.LOCK_TO_TELUS;
+                break;
+            default:
+                mLockMode = CarrierRestriction.UNLOCKED;
+                break;
+        }
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        Log.d(TAG, "CarrierLockProvider Query");
+        return null;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return "vnd.android.cursor.dir/vnd." + AUTHORITY + ".books";
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        Log.d(TAG, "CarrierLockProvider insert START");
+        assert values != null;
+        int newValue = values.getAsInteger("newValue");
+        updateLockValue(newValue);
+        return CONTENT_URI;
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    public void setLockMode(CarrierRestriction lockMode) {
+        mLockMode = lockMode;
+        Log.d(TAG, "Setting lockMode to " + mLockMode);
+    }
+}
\ No newline at end of file
diff --git a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/carrierLock/CarrierRestriction.java b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/carrierLock/CarrierRestriction.java
new file mode 100644
index 0000000..34f9e7b
--- /dev/null
+++ b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/carrierLock/CarrierRestriction.java
@@ -0,0 +1,26 @@
+/*
+ * 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.google.android.sample.rcsclient.carrierLock;
+
+public enum CarrierRestriction {
+    UNLOCKED,
+    LOCK_TO_VZW,
+    LOCK_TO_ATT,
+    LOCK_TO_TMO,
+    LOCK_TO_KOODO,
+    LOCK_TO_TELUS
+}
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/lint-baseline.xml b/testapps/TestRcsApp/aosp_test_rcsclient/lint-baseline.xml
index e0c7c3e..b2110a3 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/lint-baseline.xml
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/lint-baseline.xml
@@ -1,48 +1,15 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.net.ConnectivityManager#registerQosCallback`"
-        errorLine1="            connectivityManager.registerQosCallback(new QosSocketInfo(network, socket),"
-        errorLine2="                                ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpSession.java"
-            line="118"
-            column="33"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.net.ConnectivityManager#unregisterQosCallback`"
-        errorLine1="        connectivityManager.unregisterQosCallback(qosCallback);"
-        errorLine2="                            ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpSession.java"
-            line="181"
-            column="29"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.TelephonyManager#bootstrapAuthenticationRequest`"
-        errorLine1="        telephonyManager.bootstrapAuthenticationRequest("
-        errorLine2="                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `new android.telephony.gba.UaSecurityProtocolIdentifier.Builder`"
+        errorLine1="                new UaSecurityProtocolIdentifier.Builder();"
+        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/GbaAuthenticationProvider.java"
-            line="97"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.gba.UaSecurityProtocolIdentifier.Builder#build`"
-        errorLine1="        UaSecurityProtocolIdentifier spId = builder.build();"
-        errorLine2="                                                    ~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/GbaAuthenticationProvider.java"
-            line="79"
-            column="53"/>
+            line="55"
+            column="17"/>
     </issue>
 
     <issue
@@ -91,673 +58,57 @@
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.DelegateRegistrationState#getRegisteredFeatureTags`"
-        errorLine1="                                .getRegisteredFeatureTags()"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `android.telephony.gba.UaSecurityProtocolIdentifier.Builder#build`"
+        errorLine1="        UaSecurityProtocolIdentifier spId = builder.build();"
+        errorLine2="                                                    ~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="139"
-            column="34"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.DelegateRegistrationState#getRegisteredFeatureTags`"
-        errorLine1="            Set&lt;String&gt; registeredFt = registrationState.getRegisteredFeatureTags();"
-        errorLine2="                                                         ~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="223"
-            column="58"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.FeatureTagState#getFeatureTag`"
-        errorLine1='                stringBuilder.append(featureTagState.getFeatureTag()).append(" ").append('
-        errorLine2="                                                     ~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="220"
-            column="54"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.FeatureTagState#getState`"
-        errorLine1="                        featureTagState.getState());"
-        errorLine2="                                        ~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="221"
-            column="41"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ImsManager#getSipDelegateManager`"
-        errorLine1="        this.sipDelegateManager = imsManager.getSipDelegateManager(subscriptionId);"
-        errorLine2="                                             ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="77"
-            column="46"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#isRcsVolteSingleRegistrationCapable`"
-        errorLine1="        return provisioningManager.isRcsVolteSingleRegistrationCapable();"
-        errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java"
-            line="166"
-            column="36"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#registerRcsProvisioningCallback`"
-        errorLine1="            provisioningManager.registerRcsProvisioningCallback(executorService, callback);"
-        errorLine2="                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java"
-            line="147"
-            column="33"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#setRcsClientConfiguration`"
-        errorLine1="        provisioningManager.setRcsClientConfiguration(clientConfiguration);"
-        errorLine2="                            ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java"
-            line="111"
-            column="29"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#triggerRcsReconfiguration`"
-        errorLine1="        provisioningManager.triggerRcsReconfiguration();"
-        errorLine2="                            ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java"
-            line="176"
-            column="29"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#unregisterRcsProvisioningCallback`"
-        errorLine1="            provisioningManager.unregisterRcsProvisioningCallback(callback);"
-        errorLine2="                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java"
-            line="158"
-            column="33"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getHomeDomain`"
-        errorLine1='                    + ", \n\tmHomeDomain=" + config.getHomeDomain()'
-        errorLine2="                                                    ~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="246"
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/GbaAuthenticationProvider.java"
+            line="79"
             column="53"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getHomeDomain`"
-        errorLine1="            return mConfiguration.getHomeDomain();"
-        errorLine2="                                  ~~~~~~~~~~~~~">
+        message="Cast to `BootstrapAuthenticationCallback` requires API level 31 (current min is 30)"
+        errorLine1="                new TelephonyManager.BootstrapAuthenticationCallback() {"
+        errorLine2="                ^">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="317"
-            column="35"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/GbaAuthenticationProvider.java"
+            line="81"
+            column="17"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getImei`"
-        errorLine1='                    + ", \n\tmImei=" + config.getImei()'
-        errorLine2="                                              ~~~~~~~">
+        message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyManager.BootstrapAuthenticationCallback`"
+        errorLine1="                new TelephonyManager.BootstrapAuthenticationCallback() {"
+        errorLine2="                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="247"
-            column="47"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/GbaAuthenticationProvider.java"
+            line="81"
+            column="21"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getImei`"
-        errorLine1="            return mConfiguration.getImei();"
-        errorLine2="                                  ~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `android.telephony.TelephonyManager#bootstrapAuthenticationRequest`"
+        errorLine1="        telephonyManager.bootstrapAuthenticationRequest("
+        errorLine2="                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="357"
-            column="35"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/GbaAuthenticationProvider.java"
+            line="97"
+            column="26"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getIpSecConfiguration`"
-        errorLine1='                    + ", \n\tmIpSecConfiguration=" + config.getIpSecConfiguration()'
-        errorLine2="                                                            ~~~~~~~~~~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `new android.telephony.ims.SipMessage`"
+        errorLine1="        return new SipMessage(startLine, headers.toString(), rawContent);"
+        errorLine2="               ~~~~~~~~~~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="259"
-            column="61"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getIpSecConfiguration`"
-        errorLine1="            SipDelegateConfiguration.IpSecConfiguration c = mConfiguration.getIpSecConfiguration();"
-        errorLine2="                                                                           ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="333"
-            column="76"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getLocalAddress`"
-        errorLine1='                    + ", \n\tmLocalAddr=" + config.getLocalAddress()'
-        errorLine2="                                                   ~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="239"
-            column="52"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getLocalAddress`"
-        errorLine1="            return mConfiguration.getLocalAddress().getAddress().getHostAddress();"
-        errorLine2="                                  ~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="296"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getLocalAddress`"
-        errorLine1="            return mConfiguration.getLocalAddress().getPort();"
-        errorLine2="                                  ~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="301"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getMaxUdpPayloadSizeBytes`"
-        errorLine1='                    + ", \n\tmMaxUdpPayloadSize=" + config.getMaxUdpPayloadSizeBytes()'
-        errorLine2="                                                           ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="243"
-            column="60"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getMaxUdpPayloadSizeBytes`"
-        errorLine1="                    ? mConfiguration.getMaxUdpPayloadSizeBytes() : 1500;"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="378"
-            column="38"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getMaxUdpPayloadSizeBytes`"
-        errorLine1="            return mConfiguration.getMaxUdpPayloadSizeBytes() &gt; 0"
-        errorLine2="                                  ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="377"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getNatSocketAddress`"
-        errorLine1="                    + &quot;, \n\tmNatConfiguration=&quot; + config.getNatSocketAddress() + '}';"
-        errorLine2="                                                          ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="260"
-            column="59"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getPrivateUserIdentifier`"
-        errorLine1='                    + ", \n\tmPrivateUserIdentifier=" + config.getPrivateUserIdentifier()'
-        errorLine2="                                                               ~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="245"
-            column="64"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getPublicGruuUri`"
-        errorLine1='                    + ", \n\tmGruu=" + config.getPublicGruuUri()'
-        errorLine2="                                              ~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="248"
-            column="47"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getPublicUserIdentifier`"
-        errorLine1='                    + ", \n\tmPublicUserIdentifier=" + config.getPublicUserIdentifier()'
-        errorLine2="                                                              ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="244"
-            column="63"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getPublicUserIdentifier`"
-        errorLine1="            return mConfiguration.getPublicUserIdentifier();"
-        errorLine2="                                  ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="312"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipAssociatedUriHeader`"
-        errorLine1='                    + ", \n\tmAssociatedUriHeader=" + config.getSipAssociatedUriHeader()'
-        errorLine2="                                                             ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="258"
-            column="62"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipAssociatedUriHeader`"
-        errorLine1="            String associatedUris = mConfiguration.getSipAssociatedUriHeader();"
-        errorLine2="                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="322"
-            column="52"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipAuthenticationHeader`"
-        errorLine1='                    + ", \n\tmSipAuthHeader=" + config.getSipAuthenticationHeader()'
-        errorLine2="                                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="249"
-            column="56"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipAuthenticationNonce`"
-        errorLine1='                    + ", \n\tmSipAuthNonce=" + config.getSipAuthenticationNonce()'
-        errorLine2="                                                      ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="250"
-            column="55"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipCniHeader`"
-        errorLine1='                    + ", \n\tmCniHeader=" + config.getSipCniHeader()'
-        errorLine2="                                                   ~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="257"
-            column="52"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipContactUserParameter`"
-        errorLine1='                    + ", \n\tmContactUserParam=" + config.getSipContactUserParameter()'
-        errorLine2="                                                          ~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="254"
-            column="59"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipContactUserParameter`"
-        errorLine1="            return mConfiguration.getSipContactUserParameter();"
-        errorLine2="                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="352"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipPaniHeader`"
-        errorLine1='                    + ", \n\tmPaniHeader=" + config.getSipPaniHeader()'
-        errorLine2="                                                    ~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="255"
-            column="53"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipPaniHeader`"
-        errorLine1="            return mConfiguration.getSipPaniHeader();"
-        errorLine2="                                  ~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="362"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipPathHeader`"
-        errorLine1='                    + ", \n\tmPathHeader=" + config.getSipPathHeader()'
-        errorLine2="                                                    ~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="252"
-            column="53"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipPlaniHeader`"
-        errorLine1='                    + ", \n\tmPlaniHeader=" + config.getSipPlaniHeader()'
-        errorLine2="                                                     ~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="256"
-            column="54"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipPlaniHeader`"
-        errorLine1="            return mConfiguration.getSipPlaniHeader();"
-        errorLine2="                                  ~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="367"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipServerAddress`"
-        errorLine1='                    + ", \n\tmSipServerAddr=" + config.getSipServerAddress()'
-        errorLine2="                                                       ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="240"
-            column="56"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipServerAddress`"
-        errorLine1="            return mConfiguration.getSipServerAddress().getAddress().getHostAddress();"
-        errorLine2="                                  ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="286"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipServerAddress`"
-        errorLine1="            return mConfiguration.getSipServerAddress().getPort();"
-        errorLine2="                                  ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="291"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipServiceRouteHeader`"
-        errorLine1='                    + ", \n\tmServiceRouteHeader=" + config.getSipServiceRouteHeader()'
-        errorLine2="                                                            ~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="251"
-            column="61"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipServiceRouteHeader`"
-        errorLine1="                    mConfiguration.getSipServiceRouteHeader();"
-        errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="343"
-            column="36"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipUserAgentHeader`"
-        errorLine1='                    + ", \n\tmUserAgentHeader=" + config.getSipUserAgentHeader()'
-        errorLine2="                                                         ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="253"
-            column="58"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipUserAgentHeader`"
-        errorLine1="            return mConfiguration.getSipUserAgentHeader();"
-        errorLine2="                                  ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="372"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getTransportType`"
-        errorLine1='                    + ", \n\tmTransportType=" + config.getTransportType()'
-        errorLine2="                                                       ~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="238"
-            column="56"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getTransportType`"
-        errorLine1="            int sipTransport = mConfiguration.getTransportType();"
-        errorLine2="                                              ~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="306"
-            column="47"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getVersion`"
-        errorLine1="                                        + registeredSipConfig.getVersion());"
-        errorLine2="                                                              ~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="127"
-            column="63"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getVersion`"
-        errorLine1='                    + "mVersion=" + config.getVersion()'
-        errorLine2="                                           ~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="237"
-            column="44"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getVersion`"
-        errorLine1="            return mConfiguration.getVersion();"
-        errorLine2="                                  ~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="281"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#isSipCompactFormEnabled`"
-        errorLine1='                    + ", \n\tmIsSipCompactFormEnabled=" + config.isSipCompactFormEnabled()'
-        errorLine2="                                                                 ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="241"
-            column="66"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#isSipKeepaliveEnabled`"
-        errorLine1='                    + ", \n\tmIsSipKeepaliveEnabled=" + config.isSipKeepaliveEnabled()'
-        errorLine2="                                                               ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="242"
-            column="64"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration.IpSecConfiguration#getSipSecurityVerifyHeader`"
-        errorLine1="            return c.getSipSecurityVerifyHeader();"
-        errorLine2="                     ~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="337"
-            column="22"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConnection#sendMessage`"
-        errorLine1="            sipDelegateConnection.sendMessage(MessageConverter.toPlatformMessage(message),"
-        errorLine2="                                  ~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="271"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateManager#createSipDelegate`"
-        errorLine1="                controller.sipDelegateManager.createSipDelegate("
-        errorLine2="                                              ~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="205"
-            column="47"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateManager#destroySipDelegate`"
-        errorLine1="            sipDelegateManager.destroySipDelegate(context.sipDelegateConnection,"
-        errorLine2="                               ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="92"
-            column="32"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipMessage#getContent`"
-        errorLine1="            return new SipMessage(message.getStartLine(), headers, message.getContent());"
-        errorLine2="                                                                           ~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="395"
-            column="76"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipMessage#getHeaderSection`"
-        errorLine1='                        + message.getHeaderSection().substring(0, 10) + "-&gt;"'
-        errorLine2="                                  ~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="392"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipMessage#getHeaderSection`"
-        errorLine1="            String headers = message.getHeaderSection();"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="387"
-            column="38"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipMessage#getStartLine`"
-        errorLine1="            return new SipMessage(message.getStartLine(), headers, message.getContent());"
-        errorLine2="                                          ~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="395"
-            column="43"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/MessageConverter.java"
+            line="72"
+            column="16"/>
     </issue>
 
     <issue
@@ -784,94 +135,6 @@
 
     <issue
         id="NewApi"
-        message="Call requires API level 31 (current min is 30): `new android.net.QosSocketInfo`"
-        errorLine1="            connectivityManager.registerQosCallback(new QosSocketInfo(network, socket),"
-        errorLine2="                                                    ~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpSession.java"
-            line="118"
-            column="53"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `new android.telephony.gba.UaSecurityProtocolIdentifier.Builder`"
-        errorLine1="                new UaSecurityProtocolIdentifier.Builder();"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/GbaAuthenticationProvider.java"
-            line="55"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `new android.telephony.ims.DelegateRequest`"
-        errorLine1="            DelegateRequest request = new DelegateRequest(imsService.getFeatureTags());"
-        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="203"
-            column="39"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `new android.telephony.ims.RcsClientConfiguration`"
-        errorLine1="        return new RcsClientConfiguration("
-        errorLine2="               ~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java"
-            line="74"
-            column="16"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `new android.telephony.ims.SipMessage`"
-        errorLine1="            return new SipMessage(message.getStartLine(), headers, message.getContent());"
-        errorLine2="                   ~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
-            line="395"
-            column="20"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `new android.telephony.ims.SipMessage`"
-        errorLine1="        return new SipMessage(startLine, headers.toString(), rawContent);"
-        errorLine2="               ~~~~~~~~~~~~~~">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/MessageConverter.java"
-            line="72"
-            column="16"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Cast to `BootstrapAuthenticationCallback` requires API level 31 (current min is 30)"
-        errorLine1="                new TelephonyManager.BootstrapAuthenticationCallback() {"
-        errorLine2="                ^">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/GbaAuthenticationProvider.java"
-            line="81"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Cast to `RcsProvisioningCallback` requires API level 31 (current min is 30)"
-        errorLine1="                new RcsProvisioningCallback() {"
-        errorLine2="                ^">
-        <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java"
-            line="114"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="NewApi"
         message="Class requires API level 31 (current min is 30): `android.net.QosCallback`"
         errorLine1="    private final QosCallback qosCallback = new QosCallback() {"
         errorLine2="                                                ~~~~~~~~~~~">
@@ -883,24 +146,68 @@
 
     <issue
         id="NewApi"
-        message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyManager.BootstrapAuthenticationCallback`"
-        errorLine1="                new TelephonyManager.BootstrapAuthenticationCallback() {"
-        errorLine2="                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `new android.net.QosSocketInfo`"
+        errorLine1="            connectivityManager.registerQosCallback(new QosSocketInfo(network, socket),"
+        errorLine2="                                                    ~~~~~~~~~~~~~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/filetransfer/requestexecutor/GbaAuthenticationProvider.java"
-            line="81"
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/msrp/MsrpSession.java"
+            line="118"
+            column="53"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ImsManager#getSipDelegateManager`"
+        errorLine1="        this.sipDelegateManager = imsManager.getSipDelegateManager(subscriptionId);"
+        errorLine2="                                             ~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="77"
+            column="46"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateManager#destroySipDelegate`"
+        errorLine1="            sipDelegateManager.destroySipDelegate(context.sipDelegateConnection,"
+        errorLine2="                               ~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="92"
+            column="32"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Class requires API level 31 (current min is 30): `android.telephony.ims.stub.DelegateConnectionStateCallback`"
+        errorLine1="                new DelegateConnectionStateCallback() {"
+        errorLine2="                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="114"
             column="21"/>
     </issue>
 
     <issue
         id="NewApi"
-        message="Class requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager.RcsProvisioningCallback`"
-        errorLine1="                new RcsProvisioningCallback() {"
-        errorLine2="                    ~~~~~~~~~~~~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getVersion`"
+        errorLine1="                                        + registeredSipConfig.getVersion());"
+        errorLine2="                                                              ~~~~~~~~~~">
         <location
-            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java"
-            line="114"
-            column="21"/>
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="127"
+            column="63"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.DelegateRegistrationState#getRegisteredFeatureTags`"
+        errorLine1="                                .getRegisteredFeatureTags()"
+        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="139"
+            column="34"/>
     </issue>
 
     <issue
@@ -916,13 +223,684 @@
 
     <issue
         id="NewApi"
-        message="Class requires API level 31 (current min is 30): `android.telephony.ims.stub.DelegateConnectionStateCallback`"
-        errorLine1="                new DelegateConnectionStateCallback() {"
-        errorLine2="                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        message="Call requires API level 31 (current min is 30): `new android.telephony.ims.DelegateRequest`"
+        errorLine1="            DelegateRequest request = new DelegateRequest(imsService.getFeatureTags());"
+        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~">
         <location
             file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="203"
+            column="39"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateManager#createSipDelegate`"
+        errorLine1="                controller.sipDelegateManager.createSipDelegate("
+        errorLine2="                                              ~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="205"
+            column="47"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.FeatureTagState#getFeatureTag`"
+        errorLine1='                stringBuilder.append(featureTagState.getFeatureTag()).append(" ").append('
+        errorLine2="                                                     ~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="220"
+            column="54"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.FeatureTagState#getState`"
+        errorLine1="                        featureTagState.getState());"
+        errorLine2="                                        ~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="221"
+            column="41"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.DelegateRegistrationState#getRegisteredFeatureTags`"
+        errorLine1="            Set&lt;String&gt; registeredFt = registrationState.getRegisteredFeatureTags();"
+        errorLine2="                                                         ~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="223"
+            column="58"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getVersion`"
+        errorLine1='                    + "mVersion=" + config.getVersion()'
+        errorLine2="                                           ~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="237"
+            column="44"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getTransportType`"
+        errorLine1='                    + ", \n\tmTransportType=" + config.getTransportType()'
+        errorLine2="                                                       ~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="238"
+            column="56"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getLocalAddress`"
+        errorLine1='                    + ", \n\tmLocalAddr=" + config.getLocalAddress()'
+        errorLine2="                                                   ~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="239"
+            column="52"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipServerAddress`"
+        errorLine1='                    + ", \n\tmSipServerAddr=" + config.getSipServerAddress()'
+        errorLine2="                                                       ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="240"
+            column="56"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#isSipCompactFormEnabled`"
+        errorLine1='                    + ", \n\tmIsSipCompactFormEnabled=" + config.isSipCompactFormEnabled()'
+        errorLine2="                                                                 ~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="241"
+            column="66"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#isSipKeepaliveEnabled`"
+        errorLine1='                    + ", \n\tmIsSipKeepaliveEnabled=" + config.isSipKeepaliveEnabled()'
+        errorLine2="                                                               ~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="242"
+            column="64"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getMaxUdpPayloadSizeBytes`"
+        errorLine1='                    + ", \n\tmMaxUdpPayloadSize=" + config.getMaxUdpPayloadSizeBytes()'
+        errorLine2="                                                           ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="243"
+            column="60"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getPublicUserIdentifier`"
+        errorLine1='                    + ", \n\tmPublicUserIdentifier=" + config.getPublicUserIdentifier()'
+        errorLine2="                                                              ~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="244"
+            column="63"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getPrivateUserIdentifier`"
+        errorLine1='                    + ", \n\tmPrivateUserIdentifier=" + config.getPrivateUserIdentifier()'
+        errorLine2="                                                               ~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="245"
+            column="64"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getHomeDomain`"
+        errorLine1='                    + ", \n\tmHomeDomain=" + config.getHomeDomain()'
+        errorLine2="                                                    ~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="246"
+            column="53"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getImei`"
+        errorLine1='                    + ", \n\tmImei=" + config.getImei()'
+        errorLine2="                                              ~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="247"
+            column="47"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getPublicGruuUri`"
+        errorLine1='                    + ", \n\tmGruu=" + config.getPublicGruuUri()'
+        errorLine2="                                              ~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="248"
+            column="47"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipAuthenticationHeader`"
+        errorLine1='                    + ", \n\tmSipAuthHeader=" + config.getSipAuthenticationHeader()'
+        errorLine2="                                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="249"
+            column="56"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipAuthenticationNonce`"
+        errorLine1='                    + ", \n\tmSipAuthNonce=" + config.getSipAuthenticationNonce()'
+        errorLine2="                                                      ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="250"
+            column="55"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipServiceRouteHeader`"
+        errorLine1='                    + ", \n\tmServiceRouteHeader=" + config.getSipServiceRouteHeader()'
+        errorLine2="                                                            ~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="251"
+            column="61"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipPathHeader`"
+        errorLine1='                    + ", \n\tmPathHeader=" + config.getSipPathHeader()'
+        errorLine2="                                                    ~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="252"
+            column="53"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipUserAgentHeader`"
+        errorLine1='                    + ", \n\tmUserAgentHeader=" + config.getSipUserAgentHeader()'
+        errorLine2="                                                         ~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="253"
+            column="58"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipContactUserParameter`"
+        errorLine1='                    + ", \n\tmContactUserParam=" + config.getSipContactUserParameter()'
+        errorLine2="                                                          ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="254"
+            column="59"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipPaniHeader`"
+        errorLine1='                    + ", \n\tmPaniHeader=" + config.getSipPaniHeader()'
+        errorLine2="                                                    ~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="255"
+            column="53"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipPlaniHeader`"
+        errorLine1='                    + ", \n\tmPlaniHeader=" + config.getSipPlaniHeader()'
+        errorLine2="                                                     ~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="256"
+            column="54"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipCniHeader`"
+        errorLine1='                    + ", \n\tmCniHeader=" + config.getSipCniHeader()'
+        errorLine2="                                                   ~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="257"
+            column="52"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipAssociatedUriHeader`"
+        errorLine1='                    + ", \n\tmAssociatedUriHeader=" + config.getSipAssociatedUriHeader()'
+        errorLine2="                                                             ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="258"
+            column="62"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getIpSecConfiguration`"
+        errorLine1='                    + ", \n\tmIpSecConfiguration=" + config.getIpSecConfiguration()'
+        errorLine2="                                                            ~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="259"
+            column="61"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getNatSocketAddress`"
+        errorLine1="                    + &quot;, \n\tmNatConfiguration=&quot; + config.getNatSocketAddress() + '}';"
+        errorLine2="                                                          ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="260"
+            column="59"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConnection#sendMessage`"
+        errorLine1="            sipDelegateConnection.sendMessage(MessageConverter.toPlatformMessage(message),"
+        errorLine2="                                  ~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="271"
+            column="35"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getVersion`"
+        errorLine1="            return mConfiguration.getVersion();"
+        errorLine2="                                  ~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="281"
+            column="35"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipServerAddress`"
+        errorLine1="            return mConfiguration.getSipServerAddress().getAddress().getHostAddress();"
+        errorLine2="                                  ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="286"
+            column="35"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipServerAddress`"
+        errorLine1="            return mConfiguration.getSipServerAddress().getPort();"
+        errorLine2="                                  ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="291"
+            column="35"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getLocalAddress`"
+        errorLine1="            return mConfiguration.getLocalAddress().getAddress().getHostAddress();"
+        errorLine2="                                  ~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="296"
+            column="35"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getLocalAddress`"
+        errorLine1="            return mConfiguration.getLocalAddress().getPort();"
+        errorLine2="                                  ~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="301"
+            column="35"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getTransportType`"
+        errorLine1="            int sipTransport = mConfiguration.getTransportType();"
+        errorLine2="                                              ~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="306"
+            column="47"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getPublicUserIdentifier`"
+        errorLine1="            return mConfiguration.getPublicUserIdentifier();"
+        errorLine2="                                  ~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="312"
+            column="35"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getHomeDomain`"
+        errorLine1="            return mConfiguration.getHomeDomain();"
+        errorLine2="                                  ~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="317"
+            column="35"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipAssociatedUriHeader`"
+        errorLine1="            String associatedUris = mConfiguration.getSipAssociatedUriHeader();"
+        errorLine2="                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="322"
+            column="52"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getIpSecConfiguration`"
+        errorLine1="            SipDelegateConfiguration.IpSecConfiguration c = mConfiguration.getIpSecConfiguration();"
+        errorLine2="                                                                           ~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="333"
+            column="76"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration.IpSecConfiguration#getSipSecurityVerifyHeader`"
+        errorLine1="            return c.getSipSecurityVerifyHeader();"
+        errorLine2="                     ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="337"
+            column="22"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipServiceRouteHeader`"
+        errorLine1="                    mConfiguration.getSipServiceRouteHeader();"
+        errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="343"
+            column="36"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipContactUserParameter`"
+        errorLine1="            return mConfiguration.getSipContactUserParameter();"
+        errorLine2="                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="352"
+            column="35"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getImei`"
+        errorLine1="            return mConfiguration.getImei();"
+        errorLine2="                                  ~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="357"
+            column="35"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipPaniHeader`"
+        errorLine1="            return mConfiguration.getSipPaniHeader();"
+        errorLine2="                                  ~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="362"
+            column="35"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipPlaniHeader`"
+        errorLine1="            return mConfiguration.getSipPlaniHeader();"
+        errorLine2="                                  ~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="367"
+            column="35"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getSipUserAgentHeader`"
+        errorLine1="            return mConfiguration.getSipUserAgentHeader();"
+        errorLine2="                                  ~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="372"
+            column="35"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getMaxUdpPayloadSizeBytes`"
+        errorLine1="            return mConfiguration.getMaxUdpPayloadSizeBytes() &gt; 0"
+        errorLine2="                                  ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="377"
+            column="35"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipDelegateConfiguration#getMaxUdpPayloadSizeBytes`"
+        errorLine1="                    ? mConfiguration.getMaxUdpPayloadSizeBytes() : 1500;"
+        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="378"
+            column="38"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipMessage#getHeaderSection`"
+        errorLine1="            String headers = message.getHeaderSection();"
+        errorLine2="                                     ~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="387"
+            column="38"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipMessage#getHeaderSection`"
+        errorLine1='                        + message.getHeaderSection().substring(0, 10) + "-&gt;"'
+        errorLine2="                                  ~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="392"
+            column="35"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipMessage#getContent`"
+        errorLine1="            return new SipMessage(message.getStartLine(), headers, message.getContent());"
+        errorLine2="                                                                           ~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="395"
+            column="76"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.SipMessage#getStartLine`"
+        errorLine1="            return new SipMessage(message.getStartLine(), headers, message.getContent());"
+        errorLine2="                                          ~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="395"
+            column="43"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `new android.telephony.ims.SipMessage`"
+        errorLine1="            return new SipMessage(message.getStartLine(), headers, message.getContent());"
+        errorLine2="                   ~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java"
+            line="395"
+            column="20"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `new android.telephony.ims.RcsClientConfiguration`"
+        errorLine1="        return new RcsClientConfiguration("
+        errorLine2="               ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java"
+            line="74"
+            column="16"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#setRcsClientConfiguration`"
+        errorLine1="        provisioningManager.setRcsClientConfiguration(clientConfiguration);"
+        errorLine2="                            ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java"
+            line="111"
+            column="29"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Cast to `RcsProvisioningCallback` requires API level 31 (current min is 30)"
+        errorLine1="                new RcsProvisioningCallback() {"
+        errorLine2="                ^">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java"
+            line="114"
+            column="17"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Class requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager.RcsProvisioningCallback`"
+        errorLine1="                new RcsProvisioningCallback() {"
+        errorLine2="                    ~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java"
             line="114"
             column="21"/>
     </issue>
 
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#registerRcsProvisioningCallback`"
+        errorLine1="            provisioningManager.registerRcsProvisioningCallback(executorService, callback);"
+        errorLine2="                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java"
+            line="147"
+            column="33"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#unregisterRcsProvisioningCallback`"
+        errorLine1="            provisioningManager.unregisterRcsProvisioningCallback(callback);"
+        errorLine2="                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java"
+            line="158"
+            column="33"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#isRcsVolteSingleRegistrationCapable`"
+        errorLine1="        return provisioningManager.isRcsVolteSingleRegistrationCapable();"
+        errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java"
+            line="166"
+            column="36"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.telephony.ims.ProvisioningManager#triggerRcsReconfiguration`"
+        errorLine1="        provisioningManager.triggerRcsReconfiguration();"
+        errorLine2="                            ~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/services/Telephony/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/provisioning/StaticConfigProvisioningController.java"
+            line="176"
+            column="29"/>
+    </issue>
+
 </issues>
\ No newline at end of file
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/Datagram.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/Datagram.java
index 97f676f..015ddcd 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/Datagram.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/Datagram.java
@@ -33,7 +33,7 @@
 import android.telephony.satellite.SatelliteDatagram;
 import android.telephony.satellite.SatelliteDatagramCallback;
 import android.telephony.satellite.SatelliteManager;
-import android.telephony.satellite.SatelliteStateCallback;
+import android.telephony.satellite.SatelliteModemStateCallback;
 import android.telephony.satellite.SatelliteTransmissionUpdateCallback;
 import android.telephony.satellite.stub.SatelliteResult;
 import android.util.Log;
@@ -61,7 +61,7 @@
 
     private SatelliteManager mSatelliteManager;
     private SatelliteDatagramCallbackTestApp mDatagramCallback;
-    private SatelliteStateCallbackTestApp mStateCallback;
+    private SatelliteModemStateCallbackTestApp mStateCallback;
     private SatelliteTransmissionUpdateCallbackTestApp mCallback;
     private android.telephony.satellite.stub.SatelliteDatagram mReceivedDatagram;
 
@@ -75,32 +75,32 @@
         super.onCreate(savedInstanceState);
         mSatelliteManager = getSystemService(SatelliteManager.class);
         mDatagramCallback = new SatelliteDatagramCallbackTestApp();
-        mStateCallback = new SatelliteStateCallbackTestApp();
+        mStateCallback = new SatelliteModemStateCallbackTestApp();
         mCallback = new SatelliteTransmissionUpdateCallbackTestApp();
 
         mReceivedDatagram = new android.telephony.satellite.stub.SatelliteDatagram();
 
         setContentView(R.layout.activity_Datagram);
         findViewById(R.id.startSatelliteTransmissionUpdates)
-                .setOnClickListener(this::startSatelliteTransmissionUpdatesApp);
+                .setOnClickListener(this::startTransmissionUpdatesApp);
         findViewById(R.id.stopSatelliteTransmissionUpdates)
-                .setOnClickListener(this::stopSatelliteTransmissionUpdatesApp);
+                .setOnClickListener(this::stopTransmissionUpdatesApp);
         findViewById(R.id.pollPendingSatelliteDatagrams)
-                .setOnClickListener(this::pollPendingSatelliteDatagramsApp);
+                .setOnClickListener(this::pollPendingDatagramsApp);
         findViewById(R.id.sendSatelliteDatagram)
-                .setOnClickListener(this::sendSatelliteDatagramApp);
+                .setOnClickListener(this::sendDatagramApp);
         findViewById(R.id.registerForSatelliteDatagram)
-                .setOnClickListener(this::registerForSatelliteDatagramApp);
+                .setOnClickListener(this::registerForIncomingDatagramApp);
         findViewById(R.id.unregisterForSatelliteDatagram)
-                .setOnClickListener(this::unregisterForSatelliteDatagramApp);
+                .setOnClickListener(this::unregisterForIncomingDatagramApp);
         findViewById(R.id.showDatagramSendStateTransition)
                 .setOnClickListener(this::showDatagramSendStateTransitionApp);
         findViewById(R.id.showDatagramReceiveStateTransition)
                 .setOnClickListener(this::showDatagramReceiveStateTransitionApp);
         findViewById(R.id.registerForSatelliteModemStateChanged)
-                .setOnClickListener(this::registerForSatelliteModemStateChangedApp);
+                .setOnClickListener(this::registerForModemStateChangedApp);
         findViewById(R.id.unregisterForSatelliteModemStateChanged)
-                .setOnClickListener(this::unregisterForSatelliteModemStateChangedApp);
+                .setOnClickListener(this::unregisterForModemStateChangedApp);
         findViewById(R.id.showSatelliteModemStateTransition)
                 .setOnClickListener(this::showSatelliteModemStateTransitionApp);
 
@@ -121,7 +121,7 @@
         }
     }
 
-    protected class SatelliteStateCallbackTestApp implements SatelliteStateCallback {
+    protected class SatelliteModemStateCallbackTestApp implements SatelliteModemStateCallback {
         @Override
         public void onSatelliteModemStateChanged(int state) {
             mModemState = state;
@@ -166,10 +166,10 @@
         }
     }
 
-    private void startSatelliteTransmissionUpdatesApp(View view) {
+    private void startTransmissionUpdatesApp(View view) {
         TextView textView = findViewById(R.id.text_id);
         LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1);
-        mSatelliteManager.requestSatelliteEnabled(true, true, Runnable::run, error::offer);
+        mSatelliteManager.requestEnabled(true, true, Runnable::run, error::offer);
         TextView showErrorStatusTextView = findViewById(R.id.showErrorStatus);
         try {
             Integer value = error.poll(TIMEOUT, TimeUnit.MILLISECONDS);
@@ -186,7 +186,7 @@
             return;
         }
         error.clear();
-        mSatelliteManager.startSatelliteTransmissionUpdates(Runnable::run, error::offer, mCallback);
+        mSatelliteManager.startTransmissionUpdates(Runnable::run, error::offer, mCallback);
         try {
             Integer value = error.poll(TIMEOUT, TimeUnit.MILLISECONDS);
             if (value == null) {
@@ -202,10 +202,10 @@
         }
     }
 
-    private void stopSatelliteTransmissionUpdatesApp(View view) {
+    private void stopTransmissionUpdatesApp(View view) {
         TextView textView = findViewById(R.id.text_id);
         LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1);
-        mSatelliteManager.stopSatelliteTransmissionUpdates(mCallback, Runnable::run, error::offer);
+        mSatelliteManager.stopTransmissionUpdates(mCallback, Runnable::run, error::offer);
         try {
             Integer value = error.poll(TIMEOUT, TimeUnit.MILLISECONDS);
             if (value == null) {
@@ -220,7 +220,7 @@
             textView.setText("stopSatelliteTransmissionUpdates exception caught =" + e);
         }
     }
-    private void pollPendingSatelliteDatagramsApp(View view) {
+    private void pollPendingDatagramsApp(View view) {
         LinkedBlockingQueue<Integer> resultListener = new LinkedBlockingQueue<>(1);
         TextView showErrorStatusTextView = findViewById(R.id.showErrorStatus);
         TextView textView = findViewById(R.id.text_id);
@@ -228,7 +228,7 @@
         if (SatelliteTestApp.getTestSatelliteService() != null) {
             SatelliteTestApp.getTestSatelliteService().sendOnPendingDatagrams();
         }
-        mSatelliteManager.requestSatelliteEnabled(true, true, Runnable::run, resultListener::offer);
+        mSatelliteManager.requestEnabled(true, true, Runnable::run, resultListener::offer);
         try {
             Integer value = resultListener.poll(TIMEOUT, TimeUnit.MILLISECONDS);
             if (value == null) {
@@ -246,61 +246,61 @@
             showErrorStatusTextView.setText("Enable SatelliteService exception caught = " + e);
             return;
         }
-        mSatelliteManager.pollPendingSatelliteDatagrams(Runnable::run, resultListener::offer);
+        mSatelliteManager.pollPendingDatagrams(Runnable::run, resultListener::offer);
         try {
             Integer value = resultListener.poll(TIMEOUT, TimeUnit.MILLISECONDS);
             if (value == null) {
                 textView.setText("Timed out for poll message");
             } else if (value != SatelliteResult.SATELLITE_RESULT_SUCCESS) {
-                textView.setText("Failed to pollPendingSatelliteDatagrams with error = "
+                textView.setText("Failed to pollPendingDatagrams with error = "
                         + SatelliteErrorUtils.mapError(value));
             } else {
-                textView.setText("pollPendingSatelliteDatagrams is successful");
+                textView.setText("pollPendingDatagrams is successful");
             }
         } catch (InterruptedException e) {
-            textView.setText("pollPendingSatelliteDatagrams exception caught =" + e);
+            textView.setText("pollPendingDatagrams exception caught =" + e);
         }
     }
 
-    private void sendSatelliteDatagramApp(View view) {
+    private void sendDatagramApp(View view) {
         TextView textView = findViewById(R.id.text_id);
         mSatelliteManager.setDeviceAlignedWithSatellite(true);
         LinkedBlockingQueue<Integer> resultListener = new LinkedBlockingQueue<>(1);
         String mText = "This is a test datagram message";
         SatelliteDatagram datagram = new SatelliteDatagram(mText.getBytes());
-        mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+        mSatelliteManager.sendDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
                 datagram, true, Runnable::run, resultListener::offer);
         try {
             Integer value = resultListener.poll(TIMEOUT, TimeUnit.MILLISECONDS);
             if (value == null) {
-                textView.setText("Timed out for sendSatelliteDatagram");
+                textView.setText("Timed out for sendDatagram");
             } else if (value != SatelliteResult.SATELLITE_RESULT_SUCCESS) {
-                textView.setText("Failed to sendSatelliteDatagram with error = "
+                textView.setText("Failed to sendDatagram with error = "
                         + SatelliteErrorUtils.mapError(value));
             } else {
-                textView.setText("sendSatelliteDatagram is successful");
+                textView.setText("sendDatagram is successful");
             }
         } catch (InterruptedException e) {
-            textView.setText("sendSatelliteDatagram exception caught =" + e);
+            textView.setText("sendDatagram exception caught =" + e);
         }
     }
 
-    private void registerForSatelliteDatagramApp(View view) {
-        int result = mSatelliteManager.registerForSatelliteDatagram(Runnable::run,
+    private void registerForIncomingDatagramApp(View view) {
+        int result = mSatelliteManager.registerForIncomingDatagram(Runnable::run,
                 mDatagramCallback);
         TextView textView = findViewById(R.id.text_id);
         if (result == 0) {
-            textView.setText("registerForSatelliteDatagram is successful");
+            textView.setText("registerForIncomingDatagram is successful");
         } else {
-            textView.setText("Status for registerForSatelliteDatagram : "
+            textView.setText("Status for registerForIncomingDatagram : "
                     + SatelliteErrorUtils.mapError(result));
         }
     }
 
-    private void unregisterForSatelliteDatagramApp(View view) {
-        mSatelliteManager.unregisterForSatelliteDatagram(mDatagramCallback);
+    private void unregisterForIncomingDatagramApp(View view) {
+        mSatelliteManager.unregisterForIncomingDatagram(mDatagramCallback);
         TextView textView = findViewById(R.id.text_id);
-        textView.setText("unregisterForSatelliteDatagram is successful");
+        textView.setText("unregisterForIncomingDatagram is successful");
     }
 
     private void showDatagramSendStateTransitionApp(View view) {
@@ -315,22 +315,22 @@
                 + mShowDatagramReceiveStateTransition);
     }
 
-    private void registerForSatelliteModemStateChangedApp(View view) {
-        int result = mSatelliteManager.registerForSatelliteModemStateChanged(Runnable::run,
+    private void registerForModemStateChangedApp(View view) {
+        int result = mSatelliteManager.registerForModemStateChanged(Runnable::run,
                 mStateCallback);
         TextView textView = findViewById(R.id.text_id);
         if (result == 0) {
-            textView.setText("registerForSatelliteModemStateChanged is successful");
+            textView.setText("registerForModemStateChanged is successful");
         } else {
-            textView.setText("Status for registerForSatelliteModemStateChanged : "
+            textView.setText("Status for registerForModemStateChanged : "
                     + SatelliteErrorUtils.mapError(result));
         }
     }
 
-    private void unregisterForSatelliteModemStateChangedApp(View view) {
-        mSatelliteManager.unregisterForSatelliteModemStateChanged(mStateCallback);
+    private void unregisterForModemStateChangedApp(View view) {
+        mSatelliteManager.unregisterForModemStateChanged(mStateCallback);
         TextView textView = findViewById(R.id.text_id);
-        textView.setText("unregisterForSatelliteModemStateChanged is successful");
+        textView.setText("unregisterForModemStateChanged is successful");
     }
 
     private void showSatelliteModemStateTransitionApp(View view) {
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/MultipleSendReceive.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/MultipleSendReceive.java
index 3c0b2fd..0e5ab4f 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/MultipleSendReceive.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/MultipleSendReceive.java
@@ -66,20 +66,20 @@
         SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
                 mReceivedDatagram, 4);
         LinkedBlockingQueue<Integer> resultListener = new LinkedBlockingQueue<>(1);
-        mSatelliteManager.requestSatelliteEnabled(true, true, Runnable::run, resultListener::offer);
-        mSatelliteManager.pollPendingSatelliteDatagrams(Runnable::run, resultListener::offer);
+        mSatelliteManager.requestEnabled(true, true, Runnable::run, resultListener::offer);
+        mSatelliteManager.pollPendingDatagrams(Runnable::run, resultListener::offer);
         SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
                 mReceivedDatagram, 3);
-        mSatelliteManager.pollPendingSatelliteDatagrams(Runnable::run, resultListener::offer);
+        mSatelliteManager.pollPendingDatagrams(Runnable::run, resultListener::offer);
         SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
                 mReceivedDatagram, 2);
-        mSatelliteManager.pollPendingSatelliteDatagrams(Runnable::run, resultListener::offer);
+        mSatelliteManager.pollPendingDatagrams(Runnable::run, resultListener::offer);
         SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
                 mReceivedDatagram, 1);
-        mSatelliteManager.pollPendingSatelliteDatagrams(Runnable::run, resultListener::offer);
+        mSatelliteManager.pollPendingDatagrams(Runnable::run, resultListener::offer);
         SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
                 mReceivedDatagram, 0);
-        mSatelliteManager.pollPendingSatelliteDatagrams(Runnable::run, resultListener::offer);
+        mSatelliteManager.pollPendingDatagrams(Runnable::run, resultListener::offer);
         try {
             Integer value = resultListener.poll(1000, TimeUnit.MILLISECONDS);
             TextView textView = findViewById(R.id.text_id);
@@ -100,15 +100,15 @@
         LinkedBlockingQueue<Integer> resultListener = new LinkedBlockingQueue<>(1);
         String mText = "This is a test datagram message";
         SatelliteDatagram datagram = new SatelliteDatagram(mText.getBytes());
-        mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+        mSatelliteManager.sendDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
                 datagram, true, Runnable::run, resultListener::offer);
-        mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+        mSatelliteManager.sendDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
                 datagram, true, Runnable::run, resultListener::offer);
-        mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+        mSatelliteManager.sendDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
                 datagram, true, Runnable::run, resultListener::offer);
-        mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+        mSatelliteManager.sendDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
                 datagram, true, Runnable::run, resultListener::offer);
-        mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+        mSatelliteManager.sendDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
                 datagram, true, Runnable::run, resultListener::offer);
         try {
             Integer value = resultListener.poll(1000, TimeUnit.MILLISECONDS);
@@ -127,27 +127,27 @@
     private void multipleSendReceiveSatelliteDatagramApp(View view) {
         mSatelliteManager.setDeviceAlignedWithSatellite(true);
         LinkedBlockingQueue<Integer> resultListener = new LinkedBlockingQueue<>(1);
-        mSatelliteManager.requestSatelliteEnabled(true, true, Runnable::run, resultListener::offer);
+        mSatelliteManager.requestEnabled(true, true, Runnable::run, resultListener::offer);
         String mText = "This is a test datagram message";
         SatelliteDatagram datagram = new SatelliteDatagram(mText.getBytes());
-        mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+        mSatelliteManager.sendDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
                 datagram, true, Runnable::run, resultListener::offer);
         SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
                 mReceivedDatagram, 4);
-        mSatelliteManager.pollPendingSatelliteDatagrams(Runnable::run, resultListener::offer);
-        mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+        mSatelliteManager.pollPendingDatagrams(Runnable::run, resultListener::offer);
+        mSatelliteManager.sendDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
                 datagram, true, Runnable::run, resultListener::offer);
         SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
                 mReceivedDatagram, 3);
-        mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+        mSatelliteManager.sendDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
                 datagram, true, Runnable::run, resultListener::offer);
         SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
                 mReceivedDatagram, 2);
-        mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+        mSatelliteManager.sendDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
                 datagram, true, Runnable::run, resultListener::offer);
         SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
                 mReceivedDatagram, 1);
-        mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+        mSatelliteManager.sendDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
                 datagram, true, Runnable::run, resultListener::offer);
         SatelliteTestApp.getTestSatelliteService().sendOnSatelliteDatagramReceived(
                 mReceivedDatagram, 0);
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/Provisioning.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/Provisioning.java
index 940435e..20c5ef5 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/Provisioning.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/Provisioning.java
@@ -55,15 +55,15 @@
 
         setContentView(R.layout.activity_Provisioning);
         findViewById(R.id.provisionSatelliteService)
-                .setOnClickListener(this::provisionSatelliteServiceApp);
+                .setOnClickListener(this::provisionServiceApp);
         findViewById(R.id.deprovisionSatelliteService)
-                .setOnClickListener(this::deprovisionSatelliteServiceApp);
+                .setOnClickListener(this::deprovisionServiceApp);
         findViewById(R.id.requestIsSatelliteProvisioned)
-                .setOnClickListener(this::requestIsSatelliteProvisionedApp);
+                .setOnClickListener(this::requestIsProvisionedApp);
         findViewById(R.id.registerForSatelliteProvisionStateChanged)
-                .setOnClickListener(this::registerForSatelliteProvisionStateChangedApp);
+                .setOnClickListener(this::registerForProvisionStateChangedApp);
         findViewById(R.id.unregisterForSatelliteProvisionStateChanged)
-                .setOnClickListener(this::unregisterForSatelliteProvisionStateChangedApp);
+                .setOnClickListener(this::unregisterForProvisionStateChangedApp);
         findViewById(R.id.showCurrentSatelliteProvisionState)
                 .setOnClickListener(this::showCurrentSatelliteProvisionStateApp);
         findViewById(R.id.Back).setOnClickListener(new OnClickListener() {
@@ -84,13 +84,13 @@
         }
     }
 
-    private void provisionSatelliteServiceApp(View view) {
+    private void provisionServiceApp(View view) {
         TextView textView = findViewById(R.id.text_id);
         CancellationSignal cancellationSignal = new CancellationSignal();
         LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1);
         String mText = "This is test provision data.";
         byte[] testProvisionData = mText.getBytes();
-        mSatelliteManager.provisionSatelliteService("SATELLITE_TOKEN", testProvisionData,
+        mSatelliteManager.provisionService("SATELLITE_TOKEN", testProvisionData,
                 cancellationSignal, Runnable::run, error::offer);
         try {
             Integer value = error.poll(TIMEOUT, TimeUnit.MILLISECONDS);
@@ -107,10 +107,10 @@
         }
     }
 
-    private void deprovisionSatelliteServiceApp(View view) {
+    private void deprovisionServiceApp(View view) {
         TextView textView = findViewById(R.id.text_id);
         LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1);
-        mSatelliteManager.deprovisionSatelliteService("SATELLITE_TOKEN", Runnable::run,
+        mSatelliteManager.deprovisionService("SATELLITE_TOKEN", Runnable::run,
                 error::offer);
         try {
             Integer value = error.poll(TIMEOUT, TimeUnit.MILLISECONDS);
@@ -127,7 +127,7 @@
         }
     }
 
-    private void requestIsSatelliteProvisionedApp(View view) {
+    private void requestIsProvisionedApp(View view) {
         final AtomicReference<Boolean> enabled = new AtomicReference<>();
         final AtomicReference<Integer> errorCode = new AtomicReference<>();
         OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> mReceiver =
@@ -148,19 +148,19 @@
                         + SatelliteErrorUtils.mapError(errorCode.get()));
             }
         };
-        mSatelliteManager.requestIsSatelliteProvisioned(Runnable::run, mReceiver);
+        mSatelliteManager.requestIsProvisioned(Runnable::run, mReceiver);
     }
 
-    private void registerForSatelliteProvisionStateChangedApp(View view) {
-        int result = mSatelliteManager.registerForSatelliteProvisionStateChanged(Runnable::run,
+    private void registerForProvisionStateChangedApp(View view) {
+        int result = mSatelliteManager.registerForProvisionStateChanged(Runnable::run,
                 mCallback);
         TextView textView = findViewById(R.id.text_id);
         textView.setText("Status for registerForSatelliteProvisionStateChanged : "
                 + SatelliteErrorUtils.mapError(result));
     }
 
-    private void unregisterForSatelliteProvisionStateChangedApp(View view) {
-        mSatelliteManager.unregisterForSatelliteProvisionStateChanged(mCallback);
+    private void unregisterForProvisionStateChangedApp(View view) {
+        mSatelliteManager.unregisterForProvisionStateChanged(mCallback);
         TextView textView = findViewById(R.id.text_id);
         textView.setText("unregisterForSatelliteProvisionStateChanged is successful");
     }
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteControl.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteControl.java
index 4e339a3..2d01aec 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteControl.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteControl.java
@@ -52,16 +52,15 @@
         findViewById(R.id.disableSatellite)
                 .setOnClickListener(this::disableSatelliteApp);
         findViewById(R.id.requestIsSatelliteEnabled)
-                .setOnClickListener(this::requestIsSatelliteEnabledApp);
+                .setOnClickListener(this::requestIsEnabledApp);
         findViewById(R.id.requestIsDemoModeEnabled)
                 .setOnClickListener(this::requestIsDemoModeEnabledApp);
         findViewById(R.id.requestIsSatelliteSupported)
-                .setOnClickListener(this::requestIsSatelliteSupportedApp);
+                .setOnClickListener(this::requestIsSupportedApp);
         findViewById(R.id.requestSatelliteCapabilities)
-                .setOnClickListener(this::requestSatelliteCapabilitiesApp);
+                .setOnClickListener(this::requestCapabilitiesApp);
         findViewById(R.id.requestIsSatelliteCommunicationAllowedForCurrentLocation)
-                .setOnClickListener(
-                this::requestIsSatelliteCommunicationAllowedForCurrentLocationApp);
+                .setOnClickListener(this::requestIsCommunicationAllowedForCurrentLocationApp);
         findViewById(R.id.requestTimeForNextSatelliteVisibility)
                 .setOnClickListener(this::requestTimeForNextSatelliteVisibilityApp);
         findViewById(R.id.Back).setOnClickListener(new OnClickListener() {
@@ -74,7 +73,7 @@
 
     private void enableSatelliteApp(View view) {
         LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1);
-        mSatelliteManager.requestSatelliteEnabled(true, true, Runnable::run, error::offer);
+        mSatelliteManager.requestEnabled(true, true, Runnable::run, error::offer);
         TextView textView = findViewById(R.id.text_id);
         try {
             Integer value = error.poll(TIMEOUT, TimeUnit.MILLISECONDS);
@@ -93,7 +92,7 @@
 
     private void disableSatelliteApp(View view) {
         LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1);
-        mSatelliteManager.requestSatelliteEnabled(false, true, Runnable::run, error::offer);
+        mSatelliteManager.requestEnabled(false, true, Runnable::run, error::offer);
         TextView textView = findViewById(R.id.text_id);
         try {
             Integer value = error.poll(TIMEOUT, TimeUnit.MILLISECONDS);
@@ -110,7 +109,7 @@
         }
     }
 
-    private void requestIsSatelliteEnabledApp(View view) {
+    private void requestIsEnabledApp(View view) {
         final AtomicReference<Boolean> enabled = new AtomicReference<>();
         final AtomicReference<Integer> errorCode = new AtomicReference<>();
         OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> receiver =
@@ -120,9 +119,9 @@
                 enabled.set(result);
                 TextView textView = findViewById(R.id.text_id);
                 if (enabled.get()) {
-                    textView.setText("requestIsSatelliteEnabled is true");
+                    textView.setText("requestIsEnabled is true");
                 } else {
-                    textView.setText("Status for requestIsSatelliteEnabled result : "
+                    textView.setText("Status for requestIsEnabled result : "
                             + enabled.get());
                 }
             }
@@ -131,11 +130,11 @@
             public void onError(SatelliteManager.SatelliteException exception) {
                 errorCode.set(exception.getErrorCode());
                 TextView textView = findViewById(R.id.text_id);
-                textView.setText("Status for requestIsSatelliteEnabled error : "
+                textView.setText("Status for requestIsEnabled error : "
                         + SatelliteErrorUtils.mapError(errorCode.get()));
             }
         };
-        mSatelliteManager.requestIsSatelliteEnabled(Runnable::run, receiver);
+        mSatelliteManager.requestIsEnabled(Runnable::run, receiver);
     }
 
     private void requestIsDemoModeEnabledApp(View view) {
@@ -166,7 +165,7 @@
         mSatelliteManager.requestIsDemoModeEnabled(Runnable::run, receiver);
     }
 
-    private void requestIsSatelliteSupportedApp(View view) {
+    private void requestIsSupportedApp(View view) {
         final AtomicReference<Boolean> enabled = new AtomicReference<>();
         final AtomicReference<Integer> errorCode = new AtomicReference<>();
         OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> receiver =
@@ -176,9 +175,9 @@
                 enabled.set(result);
                 TextView textView = findViewById(R.id.text_id);
                 if (enabled.get()) {
-                    textView.setText("requestIsSatelliteSupported is true");
+                    textView.setText("requestIsSupported is true");
                 } else {
-                    textView.setText("Status for requestIsSatelliteSupported result : "
+                    textView.setText("Status for requestIsSupported result : "
                             + enabled.get());
                 }
             }
@@ -187,14 +186,14 @@
             public void onError(SatelliteManager.SatelliteException exception) {
                 errorCode.set(exception.getErrorCode());
                 TextView textView = findViewById(R.id.text_id);
-                textView.setText("Status for requestIsSatelliteSupported error : "
+                textView.setText("Status for requestIsSupported error : "
                         + SatelliteErrorUtils.mapError(errorCode.get()));
             }
         };
-        mSatelliteManager.requestIsSatelliteSupported(Runnable::run, receiver);
+        mSatelliteManager.requestIsSupported(Runnable::run, receiver);
     }
 
-    private void requestSatelliteCapabilitiesApp(View view) {
+    private void requestCapabilitiesApp(View view) {
         final AtomicReference<SatelliteCapabilities> capabilities = new AtomicReference<>();
         final AtomicReference<Integer> errorCode = new AtomicReference<>();
         OutcomeReceiver<SatelliteCapabilities, SatelliteManager.SatelliteException> receiver =
@@ -203,7 +202,7 @@
             public void onResult(SatelliteCapabilities result) {
                 capabilities.set(result);
                 TextView textView = findViewById(R.id.text_id);
-                textView.setText("Status for requestSatelliteCapabilities result: "
+                textView.setText("Status for requestCapabilities result: "
                         + capabilities.get());
             }
 
@@ -211,17 +210,17 @@
             public void onError(SatelliteManager.SatelliteException exception) {
                 errorCode.set(exception.getErrorCode());
                 TextView textView = findViewById(R.id.text_id);
-                textView.setText("Status for requestSatelliteCapabilities error : "
+                textView.setText("Status for requestCapabilities error : "
                         + SatelliteErrorUtils.mapError(errorCode.get()));
             }
         };
-        mSatelliteManager.requestSatelliteCapabilities(Runnable::run, receiver);
+        mSatelliteManager.requestCapabilities(Runnable::run, receiver);
     }
 
-    private void requestIsSatelliteCommunicationAllowedForCurrentLocationApp(View view) {
+    private void requestIsCommunicationAllowedForCurrentLocationApp(View view) {
         final AtomicReference<Boolean> enabled = new AtomicReference<>();
         final AtomicReference<Integer> errorCode = new AtomicReference<>();
-        String display = "requestIsSatelliteCommunicationAllowedForCurrentLocation";
+        String display = "requestIsCommunicationAllowedForCurrentLocation";
         OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> receiver =
                 new OutcomeReceiver<>() {
             @Override
@@ -244,7 +243,7 @@
                         + SatelliteErrorUtils.mapError(errorCode.get()));
             }
         };
-        mSatelliteManager.requestIsSatelliteCommunicationAllowedForCurrentLocation(Runnable::run,
+        mSatelliteManager.requestIsCommunicationAllowedForCurrentLocation(Runnable::run,
                 receiver);
     }
 
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SendReceive.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SendReceive.java
index a64aa5d..b5e82b1 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SendReceive.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SendReceive.java
@@ -124,7 +124,7 @@
 
         SatelliteDatagram datagram = new SatelliteDatagram(mMessageInput.getBytes());
         //Sending Message
-        mSatelliteManager.sendSatelliteDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+        mSatelliteManager.sendDatagram(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
                 datagram, true, Runnable::run, error::offer);
         TextView messageStatusTextView = findViewById(R.id.messageStatus);
         try {
@@ -139,7 +139,7 @@
                         + mEnterMessage.getText().toString());
             }
         } catch (InterruptedException e) {
-            messageStatusTextView.setText("sendSatelliteDatagram exception caught = " + e);
+            messageStatusTextView.setText("sendDatagram exception caught = " + e);
         }
     }
 
@@ -148,16 +148,16 @@
         byte[] testProvisionData = mMessageOutput.getBytes();
         setupForTransferringDatagram(testProvisionData);
 
-        int result = mSatelliteManager.registerForSatelliteDatagram(Runnable::run, mCallback);
+        int result = mSatelliteManager.registerForIncomingDatagram(Runnable::run, mCallback);
         TextView showErrorStatusTextView = findViewById(R.id.showErrorStatus);
         if (result != SatelliteResult.SATELLITE_RESULT_SUCCESS) {
-            showErrorStatusTextView.setText("Status for registerForSatelliteDatagram : "
+            showErrorStatusTextView.setText("Status for registerForIncomingDatagram : "
                     + SatelliteErrorUtils.mapError(result));
         }
         if (SatelliteTestApp.getTestSatelliteService() != null) {
             SatelliteTestApp.getTestSatelliteService().sendOnPendingDatagrams();
         }
-        mSatelliteManager.requestSatelliteEnabled(true, true, Runnable::run, resultListener::offer);
+        mSatelliteManager.requestEnabled(true, true, Runnable::run, resultListener::offer);
         try {
             Integer value = resultListener.poll(TIMEOUT, TimeUnit.MILLISECONDS);
             if (value == null) {
@@ -173,7 +173,7 @@
             return;
         }
 
-        mSatelliteManager.pollPendingSatelliteDatagrams(Runnable::run, resultListener::offer);
+        mSatelliteManager.pollPendingDatagrams(Runnable::run, resultListener::offer);
         try {
             Integer value = resultListener.poll(TIMEOUT, TimeUnit.MILLISECONDS);
             if (value == null) {
@@ -185,7 +185,7 @@
                 mMessageStatusTextView.setText("Successfully polled pending messages");
             }
         } catch (InterruptedException e) {
-            mMessageStatusTextView.setText("pollPendingSatelliteDatagrams exception caught = " + e);
+            mMessageStatusTextView.setText("pollPendingDatagrams exception caught = " + e);
         }
     }
 
@@ -195,7 +195,7 @@
         LinkedBlockingQueue<Integer> error = new LinkedBlockingQueue<>(1);
 
         //Provisioning
-        mSatelliteManager.provisionSatelliteService("SATELLITE_TOKEN", provisionData,
+        mSatelliteManager.provisionService("SATELLITE_TOKEN", provisionData,
                 cancellationSignal, Runnable::run, error::offer);
         try {
             Integer value = error.poll(TIMEOUT, TimeUnit.MILLISECONDS);
@@ -233,12 +233,12 @@
                                 + SatelliteErrorUtils.mapError(errorCode.get()));
                     }
                 };
-        mSatelliteManager.requestSatelliteCapabilities(Runnable::run, receiver);
+        mSatelliteManager.requestCapabilities(Runnable::run, receiver);
 
         //Satellite Position
         SatelliteTransmissionUpdateCallbackTestApp callback =
                 new SatelliteTransmissionUpdateCallbackTestApp();
-        mSatelliteManager.requestSatelliteEnabled(true, true, Runnable::run, error::offer);
+        mSatelliteManager.requestEnabled(true, true, Runnable::run, error::offer);
         try {
             Integer value = error.poll(TIMEOUT, TimeUnit.MILLISECONDS);
             if (value == null) {
@@ -254,7 +254,7 @@
         }
         error.clear();
 
-        mSatelliteManager.startSatelliteTransmissionUpdates(Runnable::run, error::offer, callback);
+        mSatelliteManager.startTransmissionUpdates(Runnable::run, error::offer, callback);
         // Position update
         android.telephony.satellite.stub.PointingInfo pointingInfo =
                 new android.telephony.satellite.stub.PointingInfo();
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteService.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteService.java
index 929a2e5..9bea30c 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteService.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteService.java
@@ -330,14 +330,14 @@
         if (mLocalListener != null) {
             runWithExecutor(() -> mLocalListener.onPollPendingSatelliteDatagrams());
         } else {
-            loge("pollPendingSatelliteDatagrams: mLocalListener is null");
+            loge("pollPendingDatagrams: mLocalListener is null");
         }
     }
 
     @Override
     public void sendSatelliteDatagram(@NonNull SatelliteDatagram datagram, boolean isEmergency,
             @NonNull IIntegerConsumer errorCallback) {
-        logd("sendSatelliteDatagram: mErrorCode=" + mErrorCode);
+        logd("sendDatagram: mErrorCode=" + mErrorCode);
         if (mErrorCode != SatelliteResult.SATELLITE_RESULT_SUCCESS) {
             runWithExecutor(() -> errorCallback.accept(mErrorCode));
         } else {
@@ -347,7 +347,7 @@
         if (mLocalListener != null) {
             runWithExecutor(() -> mLocalListener.onSendSatelliteDatagram(datagram, isEmergency));
         } else {
-            loge("sendSatelliteDatagram: mLocalListener is null");
+            loge("sendDatagram: mLocalListener is null");
         }
     }
 
@@ -365,7 +365,7 @@
     @Override
     public void requestIsSatelliteCommunicationAllowedForCurrentLocation(
             @NonNull IIntegerConsumer errorCallback, @NonNull IBooleanConsumer callback) {
-        logd("requestIsSatelliteCommunicationAllowedForCurrentLocation: mErrorCode=" + mErrorCode);
+        logd("requestIsCommunicationAllowedForCurrentLocation: mErrorCode=" + mErrorCode);
         if (mErrorCode != SatelliteResult.SATELLITE_RESULT_SUCCESS) {
             runWithExecutor(() -> errorCallback.accept(mErrorCode));
             return;
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java
index 792c984..e4c2005 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java
@@ -23,7 +23,6 @@
 import android.os.OutcomeReceiver;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
-import android.telephony.satellite.SatelliteManager;
 import android.telephony.satellite.wrapper.NtnSignalStrengthCallbackWrapper;
 import android.telephony.satellite.wrapper.NtnSignalStrengthWrapper;
 import android.telephony.satellite.wrapper.SatelliteCapabilitiesCallbackWrapper;
@@ -41,7 +40,6 @@
 import java.util.concurrent.Executors;
 import java.util.stream.Collectors;
 
-
 /**
  * Activity related to SatelliteControl APIs for satellite.
  */
@@ -74,9 +72,9 @@
         findViewById(R.id.isOnlyNonTerrestrialNetworkSubscription)
                 .setOnClickListener(this::isOnlyNonTerrestrialNetworkSubscription);
         findViewById(R.id.registerForSatelliteCapabilitiesChanged)
-                .setOnClickListener(this::registerForSatelliteCapabilitiesChanged);
+                .setOnClickListener(this::registerForCapabilitiesChanged);
         findViewById(R.id.unregisterForSatelliteCapabilitiesChanged)
-                .setOnClickListener(this::unregisterForSatelliteCapabilitiesChanged);
+                .setOnClickListener(this::unregisterForCapabilitiesChanged);
         findViewById(R.id.Back).setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View view) {
@@ -114,8 +112,8 @@
                         mNtnSignalStrengthCallback);
             }
             if (mSatelliteCapabilitiesCallback != null) {
-                Log.d(TAG, "unregisterForSatelliteCapabilitiesChanged()");
-                mSatelliteManagerWrapper.unregisterForSatelliteCapabilitiesChanged(
+                Log.d(TAG, "unregisterForCapabilitiesChanged()");
+                mSatelliteManagerWrapper.unregisterForCapabilitiesChanged(
                         mSatelliteCapabilitiesCallback);
             }
         }
@@ -148,7 +146,7 @@
 
         try {
             mSatelliteManagerWrapper.requestNtnSignalStrength(mExecutor, receiver);
-        } catch (SecurityException | IllegalStateException ex) {
+        } catch (SecurityException ex) {
             String errorMessage = "requestNtnSignalStrength: " + ex.getMessage();
             Log.d(TAG, errorMessage);
             addLogMessage(errorMessage);
@@ -167,18 +165,10 @@
             mSatelliteManagerWrapper.registerForNtnSignalStrengthChanged(mExecutor,
                     mNtnSignalStrengthCallback);
         } catch (Exception ex) {
-            String errorMessage;
-            if (ex instanceof SatelliteManager.SatelliteException) {
-                errorMessage =
-                        "registerForNtnSignalStrengthChanged: " + translateResultCodeToString(
-                                ((SatelliteManager.SatelliteException) ex).getErrorCode());
-            } else {
-                errorMessage = "registerForNtnSignalStrengthChanged: " + ex.getMessage();
-            }
+            String errorMessage = "registerForNtnSignalStrengthChanged: " + ex.getMessage();
             Log.d(TAG, errorMessage);
             addLogMessage(errorMessage);
             mNtnSignalStrengthCallback = null;
-
         }
     }
 
@@ -222,9 +212,9 @@
         }
     }
 
-    private void registerForSatelliteCapabilitiesChanged(View view) {
-        addLogMessage("registerForSatelliteCapabilitiesChanged");
-        Log.d(TAG, "registerForSatelliteCapabilitiesChanged()");
+    private void registerForCapabilitiesChanged(View view) {
+        addLogMessage("registerForCapabilitiesChanged");
+        Log.d(TAG, "registerForCapabilitiesChanged()");
         if (mSatelliteCapabilitiesCallback == null) {
             mSatelliteCapabilitiesCallback =
                     SatelliteCapabilities -> {
@@ -235,7 +225,7 @@
                     };
         }
 
-        int result = mSatelliteManagerWrapper.registerForSatelliteCapabilitiesChanged(mExecutor,
+        int result = mSatelliteManagerWrapper.registerForCapabilitiesChanged(mExecutor,
                 mSatelliteCapabilitiesCallback);
         if (result != SatelliteManagerWrapper.SATELLITE_RESULT_SUCCESS) {
             String onError = translateResultCodeToString(result);
@@ -245,11 +235,11 @@
         }
     }
 
-    private void unregisterForSatelliteCapabilitiesChanged(View view) {
-        addLogMessage("unregisterForSatelliteCapabilitiesChanged");
-        Log.d(TAG, "unregisterForSatelliteCapabilitiesChanged()");
+    private void unregisterForCapabilitiesChanged(View view) {
+        addLogMessage("unregisterForCapabilitiesChanged");
+        Log.d(TAG, "unregisterForCapabilitiesChanged()");
         if (mSatelliteCapabilitiesCallback != null) {
-            mSatelliteManagerWrapper.unregisterForSatelliteCapabilitiesChanged(
+            mSatelliteManagerWrapper.unregisterForCapabilitiesChanged(
                     mSatelliteCapabilitiesCallback);
             mSatelliteCapabilitiesCallback = null;
             addLogMessage("mSatelliteCapabilitiesCallback was unregistered");
@@ -317,6 +307,8 @@
                 return "SATELLITE_RESULT_REQUEST_IN_PROGRESS";
             case SatelliteManagerWrapper.SATELLITE_RESULT_MODEM_BUSY:
                 return "SATELLITE_RESULT_MODEM_BUSY";
+            case SatelliteManagerWrapper.SATELLITE_RESULT_ILLEGAL_STATE:
+                return "SATELLITE_RESULT_ILLEGAL_STATE";
             default:
                 return "INVALID CODE: " + result;
         }
diff --git a/tests/src/com/android/phone/DiagnosticDataCollectorTest.java b/tests/src/com/android/phone/DiagnosticDataCollectorTest.java
index e0d89bc..983d135 100644
--- a/tests/src/com/android/phone/DiagnosticDataCollectorTest.java
+++ b/tests/src/com/android/phone/DiagnosticDataCollectorTest.java
@@ -25,6 +25,7 @@
 import static org.mockito.Mockito.verify;
 
 import android.os.DropBoxManager;
+import android.os.SystemClock;
 import android.telephony.TelephonyManager;
 
 import org.junit.After;
@@ -94,30 +95,37 @@
 
     @Test
     public void testPersistForTelecomDumpsys() throws IOException, InterruptedException {
-        TelephonyManager.EmergencyCallDiagnosticParams dp =
-                new TelephonyManager.EmergencyCallDiagnosticParams();
-        dp.setTelecomDumpSysCollection(true);
-        mDiagnosticDataCollector.persistEmergencyDianosticData(mConfig, dp, "test_tag_telecom");
+        TelephonyManager.EmergencyCallDiagnosticData.Builder callDiagnosticBuilder =
+                new TelephonyManager.EmergencyCallDiagnosticData.Builder();
+        TelephonyManager.EmergencyCallDiagnosticData ecdData =
+                callDiagnosticBuilder.setTelecomDumpsysCollectionEnabled(true).build();
+        mDiagnosticDataCollector.persistEmergencyDianosticData(
+                mConfig, ecdData, "test_tag_telecom");
 
         verifyCmdAndDropboxTag(TELECOM_DUMPSYS_COMMAND, "test_tag_telecom", false);
     }
 
     @Test
     public void testPersistForTelephonyDumpsys() throws IOException, InterruptedException {
-        TelephonyManager.EmergencyCallDiagnosticParams dp =
-                new TelephonyManager.EmergencyCallDiagnosticParams();
-        dp.setTelephonyDumpSysCollection(true);
-        mDiagnosticDataCollector.persistEmergencyDianosticData(mConfig, dp, "test_tag_telephony");
+        TelephonyManager.EmergencyCallDiagnosticData.Builder callDiagnosticBuilder =
+                new TelephonyManager.EmergencyCallDiagnosticData.Builder();
+        TelephonyManager.EmergencyCallDiagnosticData ecdData =
+                callDiagnosticBuilder.setTelephonyDumpsysCollectionEnabled(true).build();
+        mDiagnosticDataCollector.persistEmergencyDianosticData(
+                mConfig, ecdData, "test_tag_telephony");
 
         verifyCmdAndDropboxTag(TELEPHONY_DUMPSYS_COMMAND, "test_tag_telephony", false);
     }
 
     @Test
     public void testPersistForLogcat() throws IOException, InterruptedException {
-        TelephonyManager.EmergencyCallDiagnosticParams dp =
-                new TelephonyManager.EmergencyCallDiagnosticParams();
-        dp.setLogcatCollection(true, System.currentTimeMillis());
-        mDiagnosticDataCollector.persistEmergencyDianosticData(mConfig, dp, "test_tag_logcat");
+        TelephonyManager.EmergencyCallDiagnosticData.Builder callDiagnosticBuilder =
+                new TelephonyManager.EmergencyCallDiagnosticData.Builder();
+        TelephonyManager.EmergencyCallDiagnosticData ecdData =
+                callDiagnosticBuilder.setLogcatCollectionStartTimeMillis(
+                        SystemClock.elapsedRealtime()).build();
+        mDiagnosticDataCollector.persistEmergencyDianosticData(
+                mConfig, ecdData, "test_tag_logcat");
 
         verifyCmdAndDropboxTag(LOGCAT_BINARY, "test_tag_logcat", true);
     }
diff --git a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
index 611373f..2d338f2 100644
--- a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
+++ b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
@@ -108,6 +108,7 @@
         TelephonyManager.setupISubForTest(mSubscriptionManagerService);
         mSharedPreferences = mPhoneInterfaceManager.getSharedPreferences();
         mSharedPreferences.edit().remove(Phone.PREF_NULL_CIPHER_AND_INTEGRITY_ENABLED).commit();
+        mSharedPreferences.edit().remove(Phone.PREF_NULL_CIPHER_NOTIFICATIONS_ENABLED).commit();
         mIIntegerConsumer = mock(IIntegerConsumer.class);
 
         // In order not to affect the existing implementation, define a telephony features
@@ -292,6 +293,108 @@
                 mPhoneInterfaceManager).getDefaultPhone();
     }
 
+    @Test
+    public void setNullCipherNotificationsEnabled_allReqsMet_successfullyEnabled() {
+        setModemSupportsNullCipherNotification(true);
+        doNothing().when(mPhoneInterfaceManager).enforceModifyPermission();
+        doReturn(202).when(mPhoneInterfaceManager).getHalVersion(anyInt());
+        assertFalse(mSharedPreferences.contains(Phone.PREF_NULL_CIPHER_NOTIFICATIONS_ENABLED));
+
+        mPhoneInterfaceManager.setNullCipherNotificationsEnabled(true);
+
+        assertTrue(
+                mSharedPreferences.getBoolean(Phone.PREF_NULL_CIPHER_NOTIFICATIONS_ENABLED, false));
+    }
+
+    @Test
+    public void setNullCipherNotificationsEnabled_allReqsMet_successfullyDisabled() {
+        setModemSupportsNullCipherNotification(true);
+        doNothing().when(mPhoneInterfaceManager).enforceModifyPermission();
+        doReturn(202).when(mPhoneInterfaceManager).getHalVersion(anyInt());
+        assertFalse(mSharedPreferences.contains(Phone.PREF_NULL_CIPHER_NOTIFICATIONS_ENABLED));
+
+        mPhoneInterfaceManager.setNullCipherNotificationsEnabled(false);
+
+        assertFalse(
+                mSharedPreferences.getBoolean(Phone.PREF_NULL_CIPHER_NOTIFICATIONS_ENABLED, true));
+    }
+
+    @Test
+    public void setNullCipherNotificationsEnabled_lackingNecessaryHal_throwsException() {
+        setModemSupportsNullCipherNotification(true);
+        doNothing().when(mPhoneInterfaceManager).enforceModifyPermission();
+        doReturn(102).when(mPhoneInterfaceManager).getHalVersion(anyInt());
+
+        assertThrows(UnsupportedOperationException.class,
+                () -> mPhoneInterfaceManager.setNullCipherNotificationsEnabled(true));
+    }
+
+    @Test
+    public void setNullCipherNotificationsEnabled_lackingModemSupport_throwsException() {
+        setModemSupportsNullCipherNotification(false);
+        doNothing().when(mPhoneInterfaceManager).enforceModifyPermission();
+        doReturn(202).when(mPhoneInterfaceManager).getHalVersion(anyInt());
+
+        assertThrows(UnsupportedOperationException.class,
+                () -> mPhoneInterfaceManager.setNullCipherNotificationsEnabled(true));
+    }
+
+    @Test
+    public void setNullCipherNotificationsEnabled_lackingPermissions_throwsException() {
+        setModemSupportsNullCipherNotification(true);
+        doReturn(202).when(mPhoneInterfaceManager).getHalVersion(anyInt());
+        doThrow(SecurityException.class).when(mPhoneInterfaceManager).enforceModifyPermission();
+
+        assertThrows(SecurityException.class, () ->
+                mPhoneInterfaceManager.setNullCipherNotificationsEnabled(true));
+    }
+
+    @Test
+    public void isNullCipherNotificationsEnabled_allReqsMet_returnsTrue() {
+        setModemSupportsNullCipherNotification(true);
+        doReturn(202).when(mPhoneInterfaceManager).getHalVersion(anyInt());
+        doNothing().when(mPhoneInterfaceManager).enforceReadPrivilegedPermission(anyString());
+        doReturn(true).when(mPhone).getNullCipherNotificationsPreferenceEnabled();
+
+        assertTrue(mPhoneInterfaceManager.isNullCipherNotificationsEnabled());
+    }
+
+    @Test
+    public void isNullCipherNotificationsEnabled_lackingNecessaryHal_throwsException() {
+        setModemSupportsNullCipherNotification(true);
+        doReturn(102).when(mPhoneInterfaceManager).getHalVersion(anyInt());
+        doNothing().when(mPhoneInterfaceManager).enforceReadPrivilegedPermission(anyString());
+
+        assertThrows(UnsupportedOperationException.class, () ->
+                mPhoneInterfaceManager.isNullCipherNotificationsEnabled());
+    }
+
+    @Test
+    public void isNullCipherNotificationsEnabled_lackingModemSupport_throwsException() {
+        setModemSupportsNullCipherNotification(false);
+        doReturn(202).when(mPhoneInterfaceManager).getHalVersion(anyInt());
+        doNothing().when(mPhoneInterfaceManager).enforceReadPrivilegedPermission(anyString());
+
+        assertThrows(UnsupportedOperationException.class, () ->
+                mPhoneInterfaceManager.isNullCipherNotificationsEnabled());
+    }
+
+    @Test
+    public void isNullCipherNotificationsEnabled_lackingPermissions_throwsException() {
+        setModemSupportsNullCipherNotification(true);
+        doReturn(202).when(mPhoneInterfaceManager).getHalVersion(anyInt());
+        doThrow(SecurityException.class).when(
+                mPhoneInterfaceManager).enforceReadPrivilegedPermission(anyString());
+
+        assertThrows(SecurityException.class, () ->
+                mPhoneInterfaceManager.isNullCipherNotificationsEnabled());
+    }
+
+    private void setModemSupportsNullCipherNotification(boolean enable) {
+        doReturn(enable).when(mPhone).isNullCipherNotificationSupported();
+        doReturn(mPhone).when(mPhoneInterfaceManager).getDefaultPhone();
+    }
+
     /**
      * Verify getCarrierRestrictionStatus throws exception for invalid caller package name.
      */
@@ -385,14 +488,11 @@
 
     @Test
     @EnableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING})
-    public void testTelephonyFeatureAndCompatChanges() {
-        doNothing().when(mPhoneInterfaceManager).enforceModifyPermission();
-        mPhoneInterfaceManager.setFeatureFlags(mFeatureFlags);
+    public void testWithTelephonyFeatureAndCompatChanges() throws Exception {
         doReturn(true).when(mFeatureFlags).enforceTelephonyFeatureMappingForPublicApis();
-        mPhoneInterfaceManager.setPackageManager(mPackageManager);
-        doReturn(true).when(mPackageManager).hasSystemFeature(anyString());
+        mPhoneInterfaceManager.setFeatureFlags(mFeatureFlags);
+        doNothing().when(mPhoneInterfaceManager).enforceModifyPermission();
 
-        // Enabled FeatureFlags and ENABLE_FEATURE_MAPPING, telephony features are defined
         try {
             // FEATURE_TELEPHONY_CALLING
             mPhoneInterfaceManager.handlePinMmiForSubscriber(1, "123456789");
@@ -402,9 +502,21 @@
         } catch (Exception e) {
             fail("Not expect exception " + e.getMessage());
         }
+    }
 
+    @Test
+    @EnableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING})
+    public void testWithoutTelephonyFeatureAndCompatChanges() throws Exception {
         // telephony features is not defined, expect UnsupportedOperationException.
-        doReturn(false).when(mPackageManager).hasSystemFeature(anyString());
+        doReturn(false).when(mPackageManager).hasSystemFeature(
+                PackageManager.FEATURE_TELEPHONY_CALLING);
+        doReturn(false).when(mPackageManager).hasSystemFeature(
+                PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS);
+        mPhoneInterfaceManager.setPackageManager(mPackageManager);
+        doReturn(true).when(mFeatureFlags).enforceTelephonyFeatureMappingForPublicApis();
+        mPhoneInterfaceManager.setFeatureFlags(mFeatureFlags);
+        doNothing().when(mPhoneInterfaceManager).enforceModifyPermission();
+
         assertThrows(UnsupportedOperationException.class,
                 () -> mPhoneInterfaceManager.handlePinMmiForSubscriber(1, "123456789"));
         assertThrows(UnsupportedOperationException.class,
diff --git a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
index f8c5051..c44b347 100644
--- a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
+++ b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
@@ -268,7 +268,7 @@
     public void testRequestIsSatelliteCommunicationAllowedForCurrentLocation() throws Exception {
         // OEM-enabled satellite is not supported
         when(mMockFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(false);
-        mSatelliteAccessControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
                 SUB_ID, mSatelliteAllowedReceiver);
         mTestableLooper.processAllMessages();
         assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(
@@ -277,14 +277,14 @@
 
         // OEM-enabled satellite is supported, but SatelliteController returns error for the query
         when(mMockFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
-        mSatelliteAccessControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
                 SUB_ID, mSatelliteAllowedReceiver);
         mTestableLooper.processAllMessages();
         verify(mMockSatelliteController).requestIsSatelliteCommunicationAllowedForCurrentLocation(
                 anyInt(), mResultReceiverFromSatelliteControllerCaptor.capture());
 
         clearInvocations(mMockSatelliteController);
-        mSatelliteAccessControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
                 SUB_ID, mSatelliteAllowedReceiver2);
         mTestableLooper.processAllMessages();
         verify(mMockSatelliteController, never())
@@ -304,7 +304,7 @@
         // SatelliteController returns success result but the result bundle does not have
         // KEY_SATELLITE_COMMUNICATION_ALLOWED
         clearAllInvocations();
-        mSatelliteAccessControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
                 SUB_ID, mSatelliteAllowedReceiver);
         mTestableLooper.processAllMessages();
         verify(mMockSatelliteController).requestIsSatelliteCommunicationAllowedForCurrentLocation(
@@ -317,7 +317,7 @@
 
         // SatelliteController returns disallowed result
         clearAllInvocations();
-        mSatelliteAccessControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
                 SUB_ID, mSatelliteAllowedReceiver);
         mTestableLooper.processAllMessages();
         verify(mMockSatelliteController).requestIsSatelliteCommunicationAllowedForCurrentLocation(
@@ -332,7 +332,7 @@
         // country code is not in the allowed list
         clearAllInvocations();
         when(mMockCountryDetector.getCurrentNetworkCountryIso()).thenReturn(listOf("US", "IN"));
-        mSatelliteAccessControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
                 SUB_ID, mSatelliteAllowedReceiver);
         mTestableLooper.processAllMessages();
         verify(mMockSatelliteController).requestIsSatelliteCommunicationAllowedForCurrentLocation(
@@ -347,7 +347,7 @@
         // country codes are in the allowed list
         clearAllInvocations();
         when(mMockCountryDetector.getCurrentNetworkCountryIso()).thenReturn(listOf("US", "CA"));
-        mSatelliteAccessControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
                 SUB_ID, mSatelliteAllowedReceiver);
         mTestableLooper.processAllMessages();
         verify(mMockSatelliteController).requestIsSatelliteCommunicationAllowedForCurrentLocation(
@@ -367,7 +367,7 @@
         mSatelliteAccessControllerUT.elapsedRealtimeNanos = TEST_LOCATION_FRESH_DURATION_NANOS + 1;
         when(mMockLocation0.getElapsedRealtimeNanos()).thenReturn(2L);
         when(mMockLocation1.getElapsedRealtimeNanos()).thenReturn(0L);
-        mSatelliteAccessControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
                 SUB_ID, mSatelliteAllowedReceiver);
         mTestableLooper.processAllMessages();
         verify(mMockSatelliteController).requestIsSatelliteCommunicationAllowedForCurrentLocation(
@@ -406,7 +406,7 @@
         mSatelliteAccessControllerUT.elapsedRealtimeNanos = TEST_LOCATION_FRESH_DURATION_NANOS + 1;
         when(mMockLocation0.getElapsedRealtimeNanos()).thenReturn(0L);
         when(mMockLocation1.getElapsedRealtimeNanos()).thenReturn(0L);
-        mSatelliteAccessControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
                 SUB_ID, mSatelliteAllowedReceiver);
         mTestableLooper.processAllMessages();
         verify(mMockSatelliteController).requestIsSatelliteCommunicationAllowedForCurrentLocation(
@@ -438,7 +438,7 @@
         when(mMockLocation1.getElapsedRealtimeNanos()).thenReturn(0L);
         when(mMockCountryDetector.getCachedLocationCountryIsoInfo()).thenReturn(new Pair<>("", 0L));
         when(mMockCountryDetector.getCachedNetworkCountryIsoInfo()).thenReturn(new HashMap<>());
-        mSatelliteAccessControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
                 SUB_ID, mSatelliteAllowedReceiver);
         mTestableLooper.processAllMessages();
         verify(mMockSatelliteController).requestIsSatelliteCommunicationAllowedForCurrentLocation(
@@ -477,7 +477,7 @@
         mSatelliteAccessControllerUT.elapsedRealtimeNanos = TEST_LOCATION_FRESH_DURATION_NANOS + 1;
         when(mMockLocation0.getElapsedRealtimeNanos()).thenReturn(0L);
         when(mMockLocation1.getElapsedRealtimeNanos()).thenReturn(0L);
-        mSatelliteAccessControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
                 SUB_ID, mSatelliteAllowedReceiver);
         mTestableLooper.processAllMessages();
         verify(mMockSatelliteController).requestIsSatelliteCommunicationAllowedForCurrentLocation(
@@ -513,7 +513,7 @@
         mSatelliteAccessControllerUT.elapsedRealtimeNanos = TEST_LOCATION_FRESH_DURATION_NANOS + 1;
         when(mMockLocation0.getElapsedRealtimeNanos()).thenReturn(0L);
         when(mMockLocation1.getElapsedRealtimeNanos()).thenReturn(0L);
-        mSatelliteAccessControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
                 SUB_ID, mSatelliteAllowedReceiver);
         mTestableLooper.processAllMessages();
         verify(mMockSatelliteController).requestIsSatelliteCommunicationAllowedForCurrentLocation(
@@ -550,7 +550,7 @@
             try {
                 if (!semaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) {
                     logd("Timeout to receive "
-                            + "requestIsSatelliteCommunicationAllowedForCurrentLocation()"
+                            + "requestIsCommunicationAllowedForCurrentLocation()"
                             + " callback");
                     return false;
                 }
diff --git a/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementApiTest.java b/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementApiTest.java
new file mode 100644
index 0000000..f096e0d
--- /dev/null
+++ b/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementApiTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2024 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.phone.satellite.entitlement;
+
+import static com.android.phone.satellite.entitlement.SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_DISABLED;
+import static com.android.phone.satellite.entitlement.SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_ENABLED;
+import static com.android.phone.satellite.entitlement.SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_INCOMPATIBLE;
+import static com.android.phone.satellite.entitlement.SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_PROVISIONING;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyVararg;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+
+import android.content.Context;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.libraries.entitlement.ServiceEntitlement;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class SatelliteEntitlementApiTest {
+    private static final String TEST_URL = "https://test.url";
+    private static final List<String> TEST_PLMN_ALLOWED = Arrays.asList("31026", "302820");
+    @Mock
+    Context mContext;
+    @Mock
+    ServiceEntitlement mServiceEntitlement;
+    @Mock
+    CarrierConfigManager mCarrierConfigManager;
+    @Mock
+    TelephonyManager mTelephonyManager;
+    private PersistableBundle mCarrierConfigBundle;
+    private SatelliteEntitlementApi mSatelliteEntitlementAPI;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        doReturn(Context.CARRIER_CONFIG_SERVICE).when(mContext).getSystemServiceName(
+                CarrierConfigManager.class);
+        doReturn(mCarrierConfigManager).when(mContext).getSystemService(
+                Context.CARRIER_CONFIG_SERVICE);
+        mCarrierConfigBundle = new PersistableBundle();
+        doReturn(mCarrierConfigBundle)
+                .when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyVararg());
+        doReturn(Context.TELEPHONY_SERVICE).when(mContext).getSystemServiceName(
+                TelephonyManager.class);
+        doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE);
+        doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
+
+        mSatelliteEntitlementAPI = new SatelliteEntitlementApi(mContext, mCarrierConfigBundle,
+                SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
+    }
+
+    @Test
+    public void testCheckEntitlementStatus() throws Exception {
+        mCarrierConfigBundle.putString(
+                CarrierConfigManager.ImsServiceEntitlement.KEY_ENTITLEMENT_SERVER_URL_STRING,
+                TEST_URL);
+        Field fieldServiceEntitlement = SatelliteEntitlementApi.class.getDeclaredField(
+                "mServiceEntitlement");
+        fieldServiceEntitlement.setAccessible(true);
+        fieldServiceEntitlement.set(mSatelliteEntitlementAPI, mServiceEntitlement);
+
+        // Get the EntitlementStatus to DISABLED
+        int expectedEntitlementStatus = SATELLITE_ENTITLEMENT_STATUS_DISABLED;
+        doReturn(getResponse(SATELLITE_ENTITLEMENT_STATUS_DISABLED))
+                .when(mServiceEntitlement)
+                .queryEntitlementStatus(eq(ServiceEntitlement.APP_SATELLITE_ENTITLEMENT), any());
+        SatelliteEntitlementResult result =
+                mSatelliteEntitlementAPI.checkEntitlementStatus();
+        assertNotNull(result);
+        assertEquals(expectedEntitlementStatus, result.getEntitlementStatus());
+        assertTrue(result.getAllowedPLMNList().size() == 0);
+
+        // Get the EntitlementStatus to ENABLED
+        expectedEntitlementStatus = SATELLITE_ENTITLEMENT_STATUS_ENABLED;
+        doReturn(getResponse(SATELLITE_ENTITLEMENT_STATUS_ENABLED))
+                .when(mServiceEntitlement)
+                .queryEntitlementStatus(eq(ServiceEntitlement.APP_SATELLITE_ENTITLEMENT), any());
+        result = mSatelliteEntitlementAPI.checkEntitlementStatus();
+        assertNotNull(result);
+        assertEquals(expectedEntitlementStatus, result.getEntitlementStatus());
+        assertEquals(TEST_PLMN_ALLOWED, result.getAllowedPLMNList());
+
+        // Get the EntitlementStatus to INCOMPATIBLE
+        expectedEntitlementStatus = SATELLITE_ENTITLEMENT_STATUS_INCOMPATIBLE;
+        doReturn(getResponse(SATELLITE_ENTITLEMENT_STATUS_INCOMPATIBLE))
+                .when(mServiceEntitlement)
+                .queryEntitlementStatus(eq(ServiceEntitlement.APP_SATELLITE_ENTITLEMENT), any());
+        result = mSatelliteEntitlementAPI.checkEntitlementStatus();
+        assertNotNull(result);
+        assertEquals(expectedEntitlementStatus, result.getEntitlementStatus());
+        assertTrue(result.getAllowedPLMNList().size() == 0);
+
+        // Get the EntitlementStatus to PROVISIONING
+        expectedEntitlementStatus = SATELLITE_ENTITLEMENT_STATUS_PROVISIONING;
+        doReturn(getResponse(SATELLITE_ENTITLEMENT_STATUS_PROVISIONING))
+                .when(mServiceEntitlement)
+                .queryEntitlementStatus(eq(ServiceEntitlement.APP_SATELLITE_ENTITLEMENT), any());
+        result = mSatelliteEntitlementAPI.checkEntitlementStatus();
+        assertNotNull(result);
+        assertEquals(expectedEntitlementStatus, result.getEntitlementStatus());
+        assertTrue(result.getAllowedPLMNList().size() == 0);
+    }
+
+    private String getResponse(int entitlementStatus) {
+        return "{\"VERS\":{\"version\":\"1\",\"validity\":\"172800\"},"
+                + "\"TOKEN\":{\"token\":\"ASH127AHHA88SF\"},\""
+                + ServiceEntitlement.APP_SATELLITE_ENTITLEMENT + "\":{"
+                + "\"EntitlementStatus\":\"" + entitlementStatus + "\""
+                + getPLMNListOrEmpty(entitlementStatus)
+                + "}}";
+    }
+
+    private String getPLMNListOrEmpty(int entitlementStatus) {
+        return entitlementStatus == SATELLITE_ENTITLEMENT_STATUS_ENABLED ? ","
+                + "\"PLMNAllowed\":[{\"PLMN\":\"31026\",\"DataPlanType\":\"unmetered\"},"
+                + "{\"PLMN\":\"302820\",\"DataPlanType\":\"metered\"}]" : "";
+    }
+}
diff --git a/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java b/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java
new file mode 100644
index 0000000..18a0284
--- /dev/null
+++ b/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2024 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.phone.satellite.entitlement;
+
+import static com.android.phone.satellite.entitlement.SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_ENABLED;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.anyVararg;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.wifi.WifiInfo;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.TelephonyManager;
+import android.testing.TestableLooper;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.TelephonyTestBase;
+import com.android.internal.telephony.ExponentialBackoff;
+import com.android.internal.telephony.satellite.SatelliteController;
+import com.android.internal.telephony.subscription.SubscriptionManagerService;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+@RunWith(AndroidJUnit4.class)
+public class SatelliteEntitlementControllerTest extends TelephonyTestBase {
+    private static final String TAG = "SatelliteEntitlementControllerTest";
+    private static final int SUB_ID = 0;
+    private static final int SUB_ID_2 = 1;
+    private static final int[] ACTIVE_SUB_ID = {SUB_ID};
+    private static final int DEFAULT_QUERY_REFRESH_DAY = 30;
+    private static final List<String> PLMN_ALLOWED_LIST = Arrays.asList("31026", "302820");
+    @Mock
+    CarrierConfigManager mCarrierConfigManager;
+    @Mock
+    ConnectivityManager mConnectivityManager;
+    @Mock Network mNetwork;
+    @Mock TelephonyManager mTelephonyManager;
+    @Mock SubscriptionManagerService mMockSubscriptionManagerService;
+    @Mock SatelliteEntitlementApi mSatelliteEntitlementApi;
+    @Mock SatelliteEntitlementResult mSatelliteEntitlementResult;
+    @Mock SatelliteController mSatelliteController;
+    @Mock ExponentialBackoff mExponentialBackoff;
+    private PersistableBundle mCarrierConfigBundle;
+    private TestSatelliteEntitlementController mSatelliteEntitlementController;
+    private Handler mHandler;
+    private TestableLooper mTestableLooper;
+    private List<Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener>>
+            mCarrierConfigChangedListenerList = new ArrayList<>();
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        MockitoAnnotations.initMocks(this);
+
+        replaceInstance(SubscriptionManagerService.class, "sInstance", null,
+                mMockSubscriptionManagerService);
+        replaceInstance(SatelliteController.class, "sInstance", null, mSatelliteController);
+
+        HandlerThread handlerThread = new HandlerThread("SatelliteEntitlementController");
+        handlerThread.start();
+        mHandler = new Handler(handlerThread.getLooper()) {
+            @Override
+            public void handleMessage(Message msg) {
+            }
+        };
+        mTestableLooper = new TestableLooper(mHandler.getLooper());
+        doReturn(Context.TELEPHONY_SERVICE).when(mContext).getSystemServiceName(
+                TelephonyManager.class);
+        doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE);
+        doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
+        doReturn(Context.CARRIER_CONFIG_SERVICE).when(mContext).getSystemServiceName(
+                CarrierConfigManager.class);
+        doReturn(mCarrierConfigManager).when(mContext).getSystemService(
+                Context.CARRIER_CONFIG_SERVICE);
+        doAnswer(invocation -> {
+            Executor executor = invocation.getArgument(0);
+            CarrierConfigManager.CarrierConfigChangeListener listener = invocation.getArgument(1);
+            mCarrierConfigChangedListenerList.add(new Pair<>(executor, listener));
+            return null;
+        }).when(mCarrierConfigManager).registerCarrierConfigChangeListener(
+                any(Executor.class),
+                any(CarrierConfigManager.CarrierConfigChangeListener.class));
+        mCarrierConfigBundle = new PersistableBundle();
+        mCarrierConfigBundle.putInt(
+                CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_STATUS_REFRESH_DAYS_INT,
+                DEFAULT_QUERY_REFRESH_DAY);
+        mCarrierConfigBundle.putBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, true);
+        doReturn(mCarrierConfigBundle)
+                .when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyVararg());
+        doReturn(Context.CONNECTIVITY_SERVICE).when(mContext).getSystemServiceName(
+                ConnectivityManager.class);
+        doReturn(mConnectivityManager).when(mContext).getSystemService(
+                Context.CONNECTIVITY_SERVICE);
+        doReturn(mNetwork).when(mConnectivityManager).getActiveNetwork();
+        doReturn(ACTIVE_SUB_ID).when(mMockSubscriptionManagerService).getActiveSubIdList(true);
+        mSatelliteEntitlementController = new TestSatelliteEntitlementController(mContext,
+                mHandler.getLooper(), mSatelliteEntitlementApi);
+        mSatelliteEntitlementController = spy(mSatelliteEntitlementController);
+        doReturn(mSatelliteEntitlementResult).when(
+                mSatelliteEntitlementApi).checkEntitlementStatus();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    @Test
+    public void testIsQueryAvailable() throws Exception {
+        doReturn(ACTIVE_SUB_ID).when(mMockSubscriptionManagerService).getActiveSubIdList(true);
+
+        // Verify don't start the query when KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL is false.
+        mCarrierConfigBundle.putBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, false);
+        mSatelliteEntitlementController.handleCmdStartQueryEntitlement();
+
+        verify(mSatelliteEntitlementApi, never()).checkEntitlementStatus();
+        verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
+                anyBoolean(), anyList(), any());
+
+        mCarrierConfigBundle.putBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, true);
+        // Verify don't start the query when ExponentialBackoff is in progressed.
+        replaceInstance(SatelliteEntitlementController.class, "mExponentialBackoffPerSub",
+                mSatelliteEntitlementController, Map.of(SUB_ID, mExponentialBackoff));
+        mSatelliteEntitlementController.handleCmdStartQueryEntitlement();
+
+        verify(mSatelliteEntitlementApi, never()).checkEntitlementStatus();
+        verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
+                anyBoolean(), anyList(), any());
+
+        replaceInstance(SatelliteEntitlementController.class, "mExponentialBackoffPerSub",
+                mSatelliteEntitlementController, new HashMap<>());
+        // Verify don't start the query when Internet is disconnected.
+        doReturn(ACTIVE_SUB_ID).when(mMockSubscriptionManagerService).getActiveSubIdList(true);
+        setInternetConnected(false);
+        mSatelliteEntitlementController.handleCmdStartQueryEntitlement();
+
+        verify(mSatelliteEntitlementApi, never()).checkEntitlementStatus();
+        verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
+                anyBoolean(), anyList(), any());
+
+        setInternetConnected(true);
+        // Verify don't start the query when last query refresh time is not expired.
+        setLastQueryTime(System.currentTimeMillis());
+        mSatelliteEntitlementController.handleCmdStartQueryEntitlement();
+
+        verify(mSatelliteEntitlementApi, never()).checkEntitlementStatus();
+        verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
+                anyBoolean(), anyList(), any());
+
+        // Verify start the query when isQueryAvailable return true
+        setLastQueryTime(0L);
+        doReturn(mSatelliteEntitlementResult).when(
+                mSatelliteEntitlementApi).checkEntitlementStatus();
+        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST);
+        mSatelliteEntitlementController.handleCmdStartQueryEntitlement();
+
+        verify(mSatelliteEntitlementApi).checkEntitlementStatus();
+        verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(anyInt(),
+                anyBoolean(), anyList(), any());
+    }
+
+    @Test
+    public void testCheckSatelliteEntitlementStatus() throws Exception {
+        setIsQueryAvailableTrue();
+        // Verify don't call the checkSatelliteEntitlementStatus when getActiveSubIdList is empty.
+        doReturn(new int[]{}).when(mMockSubscriptionManagerService).getActiveSubIdList(true);
+        mSatelliteEntitlementController.handleCmdStartQueryEntitlement();
+
+        verify(mSatelliteEntitlementApi, never()).checkEntitlementStatus();
+        // Verify don't call the updateSatelliteEntitlementStatus.
+        verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
+                anyBoolean(), anyList(), any());
+
+        // Verify call the checkSatelliteEntitlementStatus with invalid response.
+        setIsQueryAvailableTrue();
+        doReturn(mSatelliteEntitlementResult).when(
+                mSatelliteEntitlementApi).checkEntitlementStatus();
+        replaceInstance(SatelliteEntitlementController.class,
+                "mSatelliteEntitlementResultPerSub", mSatelliteEntitlementController,
+                new HashMap<>());
+        mSatelliteEntitlementController.handleCmdStartQueryEntitlement();
+
+        verify(mSatelliteEntitlementApi).checkEntitlementStatus();
+        // Verify call the updateSatelliteEntitlementStatus with satellite service is disabled
+        // and empty PLMNAllowed
+        verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID),
+                eq(false), eq(new ArrayList<>()), any());
+
+        // Verify call the checkSatelliteEntitlementStatus with the subscribed result.
+        clearInvocationsForMock();
+        setIsQueryAvailableTrue();
+        doReturn(mSatelliteEntitlementResult).when(
+                mSatelliteEntitlementApi).checkEntitlementStatus();
+        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST);
+        mSatelliteEntitlementController.handleCmdStartQueryEntitlement();
+
+        verify(mSatelliteEntitlementApi).checkEntitlementStatus();
+        // Verify call the updateSatelliteEntitlementStatus with satellite service is enable and
+        // availablePLMNAllowedList
+        verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID), eq(true),
+                eq(PLMN_ALLOWED_LIST), any());
+
+        // Change subId and verify call the updateSatelliteEntitlementStatus with  satellite
+        // service is enable and availablePLMNAllowedList
+        clearInvocationsForMock();
+        doReturn(new int[]{SUB_ID_2}).when(mMockSubscriptionManagerService).getActiveSubIdList(
+                true);
+        mSatelliteEntitlementController.handleCmdStartQueryEntitlement();
+
+        verify(mSatelliteEntitlementApi).checkEntitlementStatus();
+        verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID_2), eq(true),
+                eq(PLMN_ALLOWED_LIST), any());
+    }
+
+    @Test
+    public void testCheckSatelliteEntitlementStatusWhenInternetConnected() throws Exception {
+        Field fieldNetworkCallback = SatelliteEntitlementController.class.getDeclaredField(
+                "mNetworkCallback");
+        fieldNetworkCallback.setAccessible(true);
+        ConnectivityManager.NetworkCallback networkCallback =
+                (ConnectivityManager.NetworkCallback) fieldNetworkCallback.get(
+                        mSatelliteEntitlementController);
+        Network mockNetwork = mock(Network.class);
+
+        // Verify the called the checkSatelliteEntitlementStatus when Internet is connected.
+        setInternetConnected(true);
+        setLastQueryTime(0L);
+        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST);
+
+        networkCallback.onAvailable(mockNetwork);
+        mTestableLooper.processAllMessages();
+
+        verify(mSatelliteEntitlementApi).checkEntitlementStatus();
+        // Verify call the updateSatelliteEntitlementStatus with satellite service is available.
+        verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID), eq(true),
+                eq(PLMN_ALLOWED_LIST), any());
+    }
+
+    @Test
+    public void testCheckSatelliteEntitlementStatusWhenCarrierConfigChanged() throws Exception {
+        // Verify the called the checkSatelliteEntitlementStatus when CarrierConfigChanged
+        // occurred and Internet is connected.
+        setInternetConnected(true);
+        setLastQueryTime(0L);
+        setSatelliteEntitlementResult(SATELLITE_ENTITLEMENT_STATUS_ENABLED, PLMN_ALLOWED_LIST);
+        triggerCarrierConfigChanged();
+
+        verify(mSatelliteEntitlementApi).checkEntitlementStatus();
+        // Verify call the updateSatelliteEntitlementStatus with satellite service is available.
+        verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID), eq(true),
+                eq(PLMN_ALLOWED_LIST), any());
+    }
+
+    private void triggerCarrierConfigChanged() {
+        for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair
+                : mCarrierConfigChangedListenerList) {
+            pair.first.execute(() -> pair.second.onCarrierConfigChanged(
+                    /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0)
+            );
+        }
+        mTestableLooper.processAllMessages();
+    }
+
+    private void clearInvocationsForMock() {
+        clearInvocations(mSatelliteEntitlementApi);
+        clearInvocations(mSatelliteController);
+    }
+
+    private void setIsQueryAvailableTrue() throws Exception {
+        doReturn(ACTIVE_SUB_ID).when(mMockSubscriptionManagerService).getActiveSubIdList(true);
+        mCarrierConfigBundle.putBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, true);
+        replaceInstance(SatelliteEntitlementController.class, "mRetryCountPerSub",
+                mSatelliteEntitlementController, new HashMap<>());
+        setInternetConnected(true);
+        setLastQueryTime(0L);
+        replaceInstance(SatelliteEntitlementController.class,
+                "mSatelliteEntitlementResultPerSub", mSatelliteEntitlementController,
+                new HashMap<>());
+    }
+
+    private void setInternetConnected(boolean connected) {
+        NetworkCapabilities networkCapabilities = new NetworkCapabilities.Builder().build();
+
+        if (connected) {
+            networkCapabilities = new NetworkCapabilities.Builder()
+                    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                    .setTransportInfo(mock(WifiInfo.class))
+                    .build();
+        }
+        doReturn(networkCapabilities).when(mConnectivityManager).getNetworkCapabilities(mNetwork);
+    }
+
+    private void setSatelliteEntitlementResult(int entitlementStatus,
+            List<String> plmnAllowedList) {
+        doReturn(entitlementStatus).when(mSatelliteEntitlementResult).getEntitlementStatus();
+        doReturn(plmnAllowedList).when(mSatelliteEntitlementResult).getAllowedPLMNList();
+    }
+
+    private void setLastQueryTime(Long lastQueryTime) throws Exception {
+        Map<Integer, Long> lastQueryTimePerSub = new HashMap<>();
+        replaceInstance(SatelliteEntitlementController.class, "mLastQueryTimePerSub",
+                mSatelliteEntitlementController, lastQueryTimePerSub);
+        lastQueryTimePerSub.put(SUB_ID, lastQueryTime);
+    }
+
+    public static class TestSatelliteEntitlementController extends SatelliteEntitlementController {
+        private SatelliteEntitlementApi mInjectSatelliteEntitlementApi;
+
+        TestSatelliteEntitlementController(@NonNull Context context, @NonNull Looper looper,
+                SatelliteEntitlementApi api) {
+            super(context, looper);
+            mInjectSatelliteEntitlementApi = api;
+        }
+
+        @Override
+        public SatelliteEntitlementApi getSatelliteEntitlementApi(int subId) {
+            logd("getSatelliteEntitlementApi");
+            return mInjectSatelliteEntitlementApi;
+        }
+    }
+
+    private static void logd(String log) {
+        Log.d(TAG, log);
+    }
+}
diff --git a/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResponseTest.java b/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResponseTest.java
new file mode 100644
index 0000000..45e2a71
--- /dev/null
+++ b/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementResponseTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2024 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.phone.satellite.entitlement;
+
+import static com.android.phone.satellite.entitlement.SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_DISABLED;
+import static com.android.phone.satellite.entitlement.SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_ENABLED;
+import static com.android.phone.satellite.entitlement.SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_INCOMPATIBLE;
+import static com.android.phone.satellite.entitlement.SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_PROVISIONING;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.internal.telephony.satellite.SatelliteNetworkInfo;
+import com.android.libraries.entitlement.ServiceEntitlement;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class SatelliteEntitlementResponseTest {
+    private static final String TEST_OTHER_APP_ID = "ap201x";
+    private static final List<SatelliteNetworkInfo> TEST_PLMN_DATA_PLAN_TYPE_LIST = Arrays.asList(
+            new SatelliteNetworkInfo("31026", "unmetered"),
+            new SatelliteNetworkInfo("302820", "metered"));
+    private static final List<String> TEST_PLMN_BARRED_LIST = Arrays.asList("31017", "302020");
+    private static final String RESPONSE_WITHOUT_SATELLITE_APP_ID =
+            "{\"VERS\":{\"version\":\"1\",\"validity\":\"172800\"},"
+                    + "\"TOKEN\":{\"token\":\"ASH127AHHA88SF\"},\""
+                    + TEST_OTHER_APP_ID + "\":{"
+                    + "\"EntitlementStatus\":\"" + SATELLITE_ENTITLEMENT_STATUS_ENABLED + "\"}}";
+    private static final String RESPONSE_WITHOUT_ENTITLEMENT_STATUS =
+            "{\"VERS\":{\"version\":\"1\",\"validity\":\"172800\"},"
+                    + "\"TOKEN\":{\"token\":\"ASH127AHHA88SF\"},\""
+                    + ServiceEntitlement.APP_SATELLITE_ENTITLEMENT + "\":{}}";
+
+    @Test
+    public void testGetSatelliteEntitlementResponse() throws Exception {
+        // Received the body with satellite service enabled.
+        SatelliteEntitlementResponse response = new SatelliteEntitlementResponse(
+                getResponse(SATELLITE_ENTITLEMENT_STATUS_ENABLED));
+        assertEquals(SATELLITE_ENTITLEMENT_STATUS_ENABLED, response.getEntitlementStatus());
+        assertEquals(TEST_PLMN_DATA_PLAN_TYPE_LIST.get(0).mPlmn,
+                response.getPlmnAllowed().get(0).mPlmn);
+        assertEquals(TEST_PLMN_DATA_PLAN_TYPE_LIST.get(0).mDataPlanType,
+                response.getPlmnAllowed().get(0).mDataPlanType);
+        assertEquals(TEST_PLMN_DATA_PLAN_TYPE_LIST.get(1).mPlmn,
+                response.getPlmnAllowed().get(1).mPlmn);
+        assertEquals(TEST_PLMN_DATA_PLAN_TYPE_LIST.get(1).mDataPlanType,
+                response.getPlmnAllowed().get(1).mDataPlanType);
+        assertEquals(TEST_PLMN_BARRED_LIST, response.getPlmnBarredList());
+
+        // Received the empty body.
+        response = new SatelliteEntitlementResponse("");
+        assertEquals(SATELLITE_ENTITLEMENT_STATUS_DISABLED, response.getEntitlementStatus());
+        assertTrue(response.getPlmnAllowed().size() == 0);
+        assertTrue(response.getPlmnBarredList().size() == 0);
+
+        // Received the body without satellite app id.
+        response = new SatelliteEntitlementResponse(RESPONSE_WITHOUT_SATELLITE_APP_ID);
+        assertEquals(SATELLITE_ENTITLEMENT_STATUS_DISABLED, response.getEntitlementStatus());
+        assertTrue(response.getPlmnAllowed().size() == 0);
+        assertTrue(response.getPlmnBarredList().size() == 0);
+
+        // Received the body without EntitlementStatus.
+        response = new SatelliteEntitlementResponse(RESPONSE_WITHOUT_ENTITLEMENT_STATUS);
+        assertEquals(SATELLITE_ENTITLEMENT_STATUS_DISABLED, response.getEntitlementStatus());
+        assertTrue(response.getPlmnAllowed().size() == 0);
+        assertTrue(response.getPlmnBarredList().size() == 0);
+
+        // Received the body with an entitlementStatus value of DISABLED.
+        response = new SatelliteEntitlementResponse(
+                getResponse(SATELLITE_ENTITLEMENT_STATUS_DISABLED));
+        assertEquals(SATELLITE_ENTITLEMENT_STATUS_DISABLED, response.getEntitlementStatus());
+        assertTrue(response.getPlmnAllowed().size() == 0);
+        assertTrue(response.getPlmnBarredList().size() == 0);
+
+        // Received the body with an entitlementStatus value of INCOMPATIBLE.
+        response = new SatelliteEntitlementResponse(
+                getResponse(SATELLITE_ENTITLEMENT_STATUS_INCOMPATIBLE));
+        assertEquals(SATELLITE_ENTITLEMENT_STATUS_INCOMPATIBLE, response.getEntitlementStatus());
+        assertTrue(response.getPlmnAllowed().size() == 0);
+        assertTrue(response.getPlmnBarredList().size() == 0);
+
+        // Received the body with an entitlementStatus value of PROVISIONING.
+        response = new SatelliteEntitlementResponse(
+                getResponse(SATELLITE_ENTITLEMENT_STATUS_PROVISIONING));
+        assertEquals(SATELLITE_ENTITLEMENT_STATUS_PROVISIONING, response.getEntitlementStatus());
+        assertTrue(response.getPlmnAllowed().size() == 0);
+        assertTrue(response.getPlmnBarredList().size() == 0);
+    }
+
+    private String getResponse(int entitlementStatus) {
+        return "{\"VERS\":{\"version\":\"1\",\"validity\":\"172800\"},"
+                + "\"TOKEN\":{\"token\":\"ASH127AHHA88SF\"},\""
+                + ServiceEntitlement.APP_SATELLITE_ENTITLEMENT + "\":{"
+                + "\"EntitlementStatus\":\"" + entitlementStatus + "\""
+                + getPLMNListOrEmpty(entitlementStatus)
+                + "}}";
+    }
+
+    private String getPLMNListOrEmpty(int entitlementStatus) {
+        return entitlementStatus == SATELLITE_ENTITLEMENT_STATUS_ENABLED ? ","
+                + "\"PLMNAllowed\":[{\"PLMN\":\"31026\",\"DataPlanType\":\"unmetered\"},"
+                + "{\"PLMN\":\"302820\",\"DataPlanType\":\"metered\"}],"
+                + "\"PLMNBarred\":[{\"PLMN\":\"31017\"},"
+                + "{\"PLMN\":\"302020\"}]" : "";
+    }
+}
diff --git a/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java b/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java
index 16a5cdb..e5f7fd3 100644
--- a/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java
+++ b/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java
@@ -41,7 +41,7 @@
 import com.android.internal.telephony.GsmCdmaPhone;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
-import com.android.phone.common.R;
+import com.android.phone.R;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index 250d27c..6f18c21 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -2402,132 +2402,83 @@
     @Test
     public void testDomainSelectionNormalRoutingEmergencyNumber_exitingApm_InService()
             throws Exception {
-        setupForCallTest();
-
-        doReturn(false).when(mPhone0).isRadioOn();
-        ServiceState ss = new ServiceState();
-        ss.setState(ServiceState.STATE_POWER_OFF);
-        when(mPhone0.getServiceState()).thenReturn(ss);
-        when(mSST.getServiceState()).thenReturn(ss);
-
-        setupForDialForDomainSelection(mPhone0, DOMAIN_CS, false);
-
-        EmergencyNumber emergencyNumber = new EmergencyNumber(TEST_EMERGENCY_NUMBER, "", "",
-                EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
-                Collections.emptyList(),
-                EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE,
-                EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL);
-
-        doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
-        doReturn(emergencyNumber).when(mEmergencyNumberTracker).getEmergencyNumber(anyString());
-        doReturn(Arrays.asList(emergencyNumber)).when(mEmergencyNumberTracker).getEmergencyNumbers(
-                anyString());
-
         when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
-
-        mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
-                createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
-                        TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+        Phone testPhone = setupConnectionServiceInApmForDomainSelection(true);
 
         ArgumentCaptor<RadioOnStateListener.Callback> callback =
                 ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
         verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
-                any(), eq(false), eq(TIMEOUT_TO_DYNAMIC_ROUTING_MS));
+                eq(testPhone), eq(false), eq(TIMEOUT_TO_DYNAMIC_ROUTING_MS));
+
+        ServiceState ss = new ServiceState();
+        ss.setState(ServiceState.STATE_OUT_OF_SERVICE);
+        when(testPhone.getServiceState()).thenReturn(ss);
+        when(mSST.getServiceState()).thenReturn(ss);
 
         assertFalse(callback.getValue()
-                .isOkToCall(mPhone0, ServiceState.STATE_OUT_OF_SERVICE, false));
+                .isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE, false));
 
         when(mSST.isRadioOn()).thenReturn(true);
 
         assertFalse(callback.getValue()
-                .isOkToCall(mPhone0, ServiceState.STATE_OUT_OF_SERVICE, false));
+                .isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE, false));
+
+        Phone otherPhone = makeTestPhone(1, ServiceState.STATE_OUT_OF_SERVICE, false);
+        when(otherPhone.getServiceState()).thenReturn(ss);
+
+        // Radio on is OK for other phone
+        assertTrue(callback.getValue()
+                .isOkToCall(otherPhone, ServiceState.STATE_OUT_OF_SERVICE, false));
 
         ss.setState(ServiceState.STATE_IN_SERVICE);
 
         assertTrue(callback.getValue()
-                .isOkToCall(mPhone0, ServiceState.STATE_IN_SERVICE, false));
+                .isOkToCall(testPhone, ServiceState.STATE_IN_SERVICE, false));
+
+        mConnection.setDisconnected(null);
     }
 
     @Test
     public void testDomainSelectionNormalRoutingEmergencyNumber_exitingApm_Timeout()
             throws Exception {
-        setupForCallTest();
-
-        doReturn(false).when(mPhone0).isRadioOn();
-        ServiceState ss = new ServiceState();
-        ss.setState(ServiceState.STATE_POWER_OFF);
-        when(mPhone0.getServiceState()).thenReturn(ss);
-        when(mSST.getServiceState()).thenReturn(ss);
-
-        setupForDialForDomainSelection(mPhone0, DOMAIN_CS, false);
-
-        EmergencyNumber emergencyNumber = new EmergencyNumber(TEST_EMERGENCY_NUMBER, "", "",
-                EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
-                Collections.emptyList(),
-                EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE,
-                EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL);
-
-        doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
-        doReturn(emergencyNumber).when(mEmergencyNumberTracker).getEmergencyNumber(anyString());
-        doReturn(Arrays.asList(emergencyNumber)).when(mEmergencyNumberTracker).getEmergencyNumbers(
-                anyString());
-
         when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
-
-        mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
-                createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
-                        TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+        Phone testPhone = setupConnectionServiceInApmForDomainSelection(true);
 
         ArgumentCaptor<RadioOnStateListener.Callback> callback =
                 ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
         verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
-                any(), eq(false), eq(TIMEOUT_TO_DYNAMIC_ROUTING_MS));
+                eq(testPhone), eq(false), eq(TIMEOUT_TO_DYNAMIC_ROUTING_MS));
 
+        ServiceState ss = new ServiceState();
+        ss.setState(ServiceState.STATE_OUT_OF_SERVICE);
+        when(testPhone.getServiceState()).thenReturn(ss);
+        when(mSST.getServiceState()).thenReturn(ss);
         when(mSST.isRadioOn()).thenReturn(true);
 
         assertFalse(callback.getValue()
-                .isOkToCall(mPhone0, ServiceState.STATE_OUT_OF_SERVICE, false));
+                .isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE, false));
         assertTrue(callback.getValue()
-                .onTimeout(mPhone0, ServiceState.STATE_OUT_OF_SERVICE, false));
+                .onTimeout(testPhone, ServiceState.STATE_OUT_OF_SERVICE, false));
+
+        mConnection.setDisconnected(null);
     }
 
     @Test
     public void testDomainSelectionNormalRoutingEmergencyNumber_exitingApm_CombinedAttach()
             throws Exception {
-        setupForCallTest();
-
-        doReturn(false).when(mPhone0).isRadioOn();
-        ServiceState ss = new ServiceState();
-        ss.setState(ServiceState.STATE_POWER_OFF);
-        when(mPhone0.getServiceState()).thenReturn(ss);
-        when(mSST.getServiceState()).thenReturn(ss);
-
-        setupForDialForDomainSelection(mPhone0, DOMAIN_CS, false);
-
-        EmergencyNumber emergencyNumber = new EmergencyNumber(TEST_EMERGENCY_NUMBER, "", "",
-                EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
-                Collections.emptyList(),
-                EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE,
-                EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL);
-
-        doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
-        doReturn(emergencyNumber).when(mEmergencyNumberTracker).getEmergencyNumber(anyString());
-        doReturn(Arrays.asList(emergencyNumber)).when(mEmergencyNumberTracker).getEmergencyNumbers(
-                anyString());
-
         when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
-
-        mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
-                createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
-                        TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+        Phone testPhone = setupConnectionServiceInApmForDomainSelection(true);
 
         ArgumentCaptor<RadioOnStateListener.Callback> callback =
                 ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
         verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
-                any(), eq(false), eq(TIMEOUT_TO_DYNAMIC_ROUTING_MS));
+                eq(testPhone), eq(false), eq(TIMEOUT_TO_DYNAMIC_ROUTING_MS));
 
-        when(mSST.isRadioOn()).thenReturn(true);
+        ServiceState ss = new ServiceState();
         ss.setState(ServiceState.STATE_IN_SERVICE);
+        when(testPhone.getServiceState()).thenReturn(ss);
+        when(mSST.getServiceState()).thenReturn(ss);
+        when(mSST.isRadioOn()).thenReturn(true);
 
         DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(3)
                 .setLteAttachResultType(DataSpecificRegistrationInfo.LTE_ATTACH_TYPE_COMBINED)
@@ -2543,46 +2494,27 @@
         ss.addNetworkRegistrationInfo(nri);
 
         assertTrue(callback.getValue()
-                .isOkToCall(mPhone0, ServiceState.STATE_IN_SERVICE, false));
+                .isOkToCall(testPhone, ServiceState.STATE_IN_SERVICE, false));
+
+        mConnection.setDisconnected(null);
     }
 
     @Test
     public void testDomainSelectionNormalRoutingEmergencyNumber_exitingApm_PsOnly()
             throws Exception {
-        setupForCallTest();
-
-        doReturn(false).when(mPhone0).isRadioOn();
-        ServiceState ss = new ServiceState();
-        ss.setState(ServiceState.STATE_POWER_OFF);
-        when(mPhone0.getServiceState()).thenReturn(ss);
-        when(mSST.getServiceState()).thenReturn(ss);
-
-        setupForDialForDomainSelection(mPhone0, DOMAIN_CS, false);
-
-        EmergencyNumber emergencyNumber = new EmergencyNumber(TEST_EMERGENCY_NUMBER, "", "",
-                EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
-                Collections.emptyList(),
-                EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE,
-                EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL);
-
-        doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
-        doReturn(emergencyNumber).when(mEmergencyNumberTracker).getEmergencyNumber(anyString());
-        doReturn(Arrays.asList(emergencyNumber)).when(mEmergencyNumberTracker).getEmergencyNumbers(
-                anyString());
-
         when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
-
-        mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
-                createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
-                        TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+        Phone testPhone = setupConnectionServiceInApmForDomainSelection(true);
 
         ArgumentCaptor<RadioOnStateListener.Callback> callback =
                 ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
         verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
-                any(), eq(false), eq(TIMEOUT_TO_DYNAMIC_ROUTING_MS));
+                eq(testPhone), eq(false), eq(TIMEOUT_TO_DYNAMIC_ROUTING_MS));
 
-        when(mSST.isRadioOn()).thenReturn(true);
+        ServiceState ss = new ServiceState();
         ss.setState(ServiceState.STATE_IN_SERVICE);
+        when(testPhone.getServiceState()).thenReturn(ss);
+        when(mSST.getServiceState()).thenReturn(ss);
+        when(mSST.isRadioOn()).thenReturn(true);
 
         DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(3)
                 .build();
@@ -2597,48 +2529,29 @@
         ss.addNetworkRegistrationInfo(nri);
 
         assertFalse(callback.getValue()
-                .isOkToCall(mPhone0, ServiceState.STATE_IN_SERVICE, false));
+                .isOkToCall(testPhone, ServiceState.STATE_IN_SERVICE, false));
         assertTrue(callback.getValue()
-                .onTimeout(mPhone0, ServiceState.STATE_IN_SERVICE, false));
+                .onTimeout(testPhone, ServiceState.STATE_IN_SERVICE, false));
+
+        mConnection.setDisconnected(null);
     }
 
     @Test
     public void testDomainSelectionNormalRoutingEmergencyNumber_exitingApm_PsOnly_ImsRegistered()
             throws Exception {
-        setupForCallTest();
-
-        doReturn(false).when(mPhone0).isRadioOn();
-        ServiceState ss = new ServiceState();
-        ss.setState(ServiceState.STATE_POWER_OFF);
-        when(mPhone0.getServiceState()).thenReturn(ss);
-        when(mSST.getServiceState()).thenReturn(ss);
-
-        setupForDialForDomainSelection(mPhone0, DOMAIN_CS, false);
-
-        EmergencyNumber emergencyNumber = new EmergencyNumber(TEST_EMERGENCY_NUMBER, "", "",
-                EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
-                Collections.emptyList(),
-                EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE,
-                EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL);
-
-        doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
-        doReturn(emergencyNumber).when(mEmergencyNumberTracker).getEmergencyNumber(anyString());
-        doReturn(Arrays.asList(emergencyNumber)).when(mEmergencyNumberTracker).getEmergencyNumbers(
-                anyString());
-
         when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
-
-        mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
-                createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
-                        TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+        Phone testPhone = setupConnectionServiceInApmForDomainSelection(true);
 
         ArgumentCaptor<RadioOnStateListener.Callback> callback =
                 ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
         verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
-                any(), eq(false), eq(TIMEOUT_TO_DYNAMIC_ROUTING_MS));
+                eq(testPhone), eq(false), eq(TIMEOUT_TO_DYNAMIC_ROUTING_MS));
 
-        when(mSST.isRadioOn()).thenReturn(true);
+        ServiceState ss = new ServiceState();
         ss.setState(ServiceState.STATE_IN_SERVICE);
+        when(testPhone.getServiceState()).thenReturn(ss);
+        when(mSST.getServiceState()).thenReturn(ss);
+        when(mSST.isRadioOn()).thenReturn(true);
 
         DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(3)
                 .build();
@@ -2653,9 +2566,11 @@
         ss.addNetworkRegistrationInfo(nri);
 
         assertFalse(callback.getValue()
-                .isOkToCall(mPhone0, ServiceState.STATE_IN_SERVICE, false));
+                .isOkToCall(testPhone, ServiceState.STATE_IN_SERVICE, false));
         assertTrue(callback.getValue()
-                .isOkToCall(mPhone0, ServiceState.STATE_IN_SERVICE, true));
+                .isOkToCall(testPhone, ServiceState.STATE_IN_SERVICE, true));
+
+        mConnection.setDisconnected(null);
     }
 
     @Test
@@ -2783,7 +2698,7 @@
 
         DomainSelectionService.SelectionAttributes attr = attrCaptor.getValue();
 
-        assertEquals(mPhone1.getPhoneId(), attr.getSlotId());
+        assertEquals(mPhone1.getPhoneId(), attr.getSlotIndex());
     }
 
     @Test
@@ -2829,7 +2744,7 @@
 
         DomainSelectionService.SelectionAttributes attr = attrCaptor.getValue();
 
-        assertEquals(mPhone1.getPhoneId(), attr.getSlotId());
+        assertEquals(mPhone1.getPhoneId(), attr.getSlotIndex());
     }
 
     @Test
@@ -3293,6 +3208,7 @@
     public void testNormalCallSatelliteEnabled() {
         setupForCallTest();
         doReturn(true).when(mSatelliteController).isSatelliteEnabled();
+
         mConnection = mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
                 createConnectionRequest(PHONE_ACCOUNT_HANDLE_1, "1234", TELECOM_CALL_ID1));
         DisconnectCause disconnectCause = mConnection.getDisconnectCause();
@@ -3353,6 +3269,30 @@
     }
 
     @Test
+    public void testNormalCallUsingNonTerrestrialNetwork_canMakeWifiCall() throws Exception {
+        mSetFlagsRule.enableFlags(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG);
+
+        setupForCallTest();
+        // Call is not supported while using satellite
+        NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+                .setIsNonTerrestrialNetwork(true)
+                .setAvailableServices(List.of(NetworkRegistrationInfo.SERVICE_TYPE_DATA))
+                .build();
+        ServiceState ss = new ServiceState();
+        ss.addNetworkRegistrationInfo(nri);
+        when(mPhone0.getServiceState()).thenReturn(ss);
+        // Wi-Fi call is possible
+        doReturn(true).when(mImsPhone).canMakeWifiCall();
+        when(mPhone0.getImsPhone()).thenReturn(mImsPhone);
+
+        mConnection = mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
+                createConnectionRequest(PHONE_ACCOUNT_HANDLE_1, "1234", TELECOM_CALL_ID1));
+        DisconnectCause disconnectCause = mConnection.getDisconnectCause();
+        assertNotEquals(android.telephony.DisconnectCause.SATELLITE_ENABLED,
+                disconnectCause.getTelephonyDisconnectCause());
+    }
+
+    @Test
     public void testIsAvailableForEmergencyCallsNotForCrossSim() {
         Phone mockPhone = Mockito.mock(Phone.class);
         when(mockPhone.getImsRegistrationTech()).thenReturn(
@@ -3366,6 +3306,52 @@
     }
 
     @Test
+    public void testIsAvailableForEmergencyCallsUsingNonTerrestrialNetwork_enableFlag() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG);
+
+        Phone mockPhone = Mockito.mock(Phone.class);
+        NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+                .setIsNonTerrestrialNetwork(true)
+                .setAvailableServices(List.of(NetworkRegistrationInfo.SERVICE_TYPE_DATA))
+                .build();
+        ServiceState ss = new ServiceState();
+        ss.addNetworkRegistrationInfo(nri);
+        ss.setEmergencyOnly(true);
+        ss.setState(ServiceState.STATE_EMERGENCY_ONLY);
+        when(mockPhone.getServiceState()).thenReturn(ss);
+
+        assertFalse(mTestConnectionService.isAvailableForEmergencyCalls(mockPhone,
+                EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY));
+        assertFalse(mTestConnectionService.isAvailableForEmergencyCalls(mockPhone,
+                EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL));
+        assertFalse(mTestConnectionService.isAvailableForEmergencyCalls(mockPhone,
+                EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
+    }
+
+    @Test
+    public void testIsAvailableForEmergencyCallsUsingNonTerrestrialNetwork_disableFlag() {
+        mSetFlagsRule.disableFlags(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG);
+
+        Phone mockPhone = Mockito.mock(Phone.class);
+        NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+                .setIsNonTerrestrialNetwork(true)
+                .setAvailableServices(List.of(NetworkRegistrationInfo.SERVICE_TYPE_VOICE))
+                .build();
+        ServiceState ss = new ServiceState();
+        ss.addNetworkRegistrationInfo(nri);
+        ss.setEmergencyOnly(true);
+        ss.setState(ServiceState.STATE_EMERGENCY_ONLY);
+        when(mockPhone.getServiceState()).thenReturn(ss);
+
+        assertTrue(mTestConnectionService.isAvailableForEmergencyCalls(mockPhone,
+                EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY));
+        assertFalse(mTestConnectionService.isAvailableForEmergencyCalls(mockPhone,
+                EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL));
+        assertTrue(mTestConnectionService.isAvailableForEmergencyCalls(mockPhone,
+                EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
+    }
+
+    @Test
     public void testIsAvailableForEmergencyCallsForEmergencyRoutingInEmergencyOnly() {
         ServiceState mockService = Mockito.mock(ServiceState.class);
         when(mockService.isEmergencyOnly()).thenReturn(true);
@@ -3520,6 +3506,50 @@
         doReturn(mImsPhone).when(mockPhone).getImsPhone();
     }
 
+    private Phone setupConnectionServiceInApmForDomainSelection(boolean normalRouting) {
+        ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
+                .setAccountHandle(PHONE_ACCOUNT_HANDLE_1)
+                .setAddress(TEST_ADDRESS)
+                .build();
+        Phone testPhone0 = makeTestPhone(0 /*phoneId*/, ServiceState.STATE_POWER_OFF,
+                false /*isEmergencyOnly*/);
+        Phone testPhone1 = makeTestPhone(1 /*phoneId*/, ServiceState.STATE_POWER_OFF,
+                false /*isEmergencyOnly*/);
+        doReturn(GSM_PHONE).when(testPhone0).getPhoneType();
+        doReturn(GSM_PHONE).when(testPhone1).getPhoneType();
+        List<Phone> phones = new ArrayList<>(2);
+        doReturn(false).when(testPhone0).isRadioOn();
+        doReturn(false).when(testPhone1).isRadioOn();
+        phones.add(testPhone0);
+        phones.add(testPhone1);
+        setPhones(phones);
+        setupHandleToPhoneMap(PHONE_ACCOUNT_HANDLE_1, testPhone0);
+        setupDeviceConfig(testPhone0, testPhone1, 0);
+        setupForDialForDomainSelection(testPhone0, DOMAIN_CS, false);
+
+        EmergencyNumber emergencyNumber;
+        if (normalRouting) {
+            emergencyNumber = new EmergencyNumber(TEST_ADDRESS.getSchemeSpecificPart(), "", "",
+                    EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
+                    Collections.emptyList(),
+                    EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE,
+                    EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL);
+        } else {
+            emergencyNumber = setupEmergencyNumber(TEST_ADDRESS);
+        }
+        doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
+        doReturn(emergencyNumber).when(mEmergencyNumberTracker).getEmergencyNumber(anyString());
+        doReturn(Arrays.asList(emergencyNumber)).when(mEmergencyNumberTracker).getEmergencyNumbers(
+                anyString());
+        doReturn(2).when(mTelephonyManagerProxy).getPhoneCount();
+
+        mConnection = mTestConnectionService.onCreateOutgoingConnection(
+                PHONE_ACCOUNT_HANDLE_1, connectionRequest);
+        assertNotNull("test connection was not set up correctly.", mConnection);
+
+        return testPhone0;
+    }
+
     private TestTelephonyConnection setupForReDialForDomainSelection(
             Phone mockPhone, int domain, int preciseDisconnectCause,
             int disconnectCause, boolean fromEmergency) throws Exception {
diff --git a/tests/src/com/android/services/telephony/domainselection/CarrierConfigHelperTest.java b/tests/src/com/android/services/telephony/domainselection/CarrierConfigHelperTest.java
index 5d4fe17..8f51dab 100644
--- a/tests/src/com/android/services/telephony/domainselection/CarrierConfigHelperTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/CarrierConfigHelperTest.java
@@ -32,7 +32,6 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.SharedPreferences;
@@ -68,11 +67,11 @@
     private static final int SUB_1 = 1;
     private static final int TEST_SIM_CARRIER_ID = 1911;
 
-    @Mock private Context mContext;
     @Mock private SharedPreferences mSharedPreferences;
     @Mock private SharedPreferences.Editor mEditor;
     @Mock private Resources mResources;
 
+    private Context mContext;
     private HandlerThread mHandlerThread;
     private TestableLooper mLooper;
     private CarrierConfigHelper mCarrierConfigHelper;
diff --git a/tests/src/com/android/services/telephony/domainselection/DomainSelectorBaseTest.java b/tests/src/com/android/services/telephony/domainselection/DomainSelectorBaseTest.java
index 74c3311..a5d463d 100644
--- a/tests/src/com/android/services/telephony/domainselection/DomainSelectorBaseTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/DomainSelectorBaseTest.java
@@ -52,11 +52,6 @@
         }
 
         @Override
-        public void cancelSelection() {
-            // No operations.
-        }
-
-        @Override
         public void reselectDomain(@NonNull SelectionAttributes attr) {
             // No operations.
         }
diff --git a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
index c39fa36..0261c17 100644
--- a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
@@ -16,6 +16,8 @@
 
 package com.android.services.telephony.domainselection;
 
+import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WLAN;
+import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
 import static android.telephony.AccessNetworkConstants.AccessNetworkType.EUTRAN;
 import static android.telephony.AccessNetworkConstants.AccessNetworkType.GERAN;
 import static android.telephony.AccessNetworkConstants.AccessNetworkType.NGRAN;
@@ -52,8 +54,11 @@
 import static android.telephony.NetworkRegistrationInfo.DOMAIN_CS;
 import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS;
 import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME;
+import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING;
 import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN;
 import static android.telephony.PreciseDisconnectCause.SERVICE_OPTION_NOT_AVAILABLE;
+import static android.telephony.TelephonyManager.DATA_CONNECTED;
+import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_DEACTIVATED;
 
 import static com.android.services.telephony.domainselection.EmergencyCallDomainSelector.MSG_MAX_CELLULAR_TIMEOUT;
 import static com.android.services.telephony.domainselection.EmergencyCallDomainSelector.MSG_NETWORK_SCAN_TIMEOUT;
@@ -70,6 +75,7 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -80,6 +86,7 @@
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
 import android.net.NetworkRequest;
+import android.net.Uri;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IPowerManager;
@@ -87,6 +94,7 @@
 import android.os.Looper;
 import android.os.PersistableBundle;
 import android.os.PowerManager;
+import android.telecom.PhoneAccount;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.BarringInfo;
 import android.telephony.CarrierConfigManager;
@@ -101,7 +109,6 @@
 import android.telephony.TelephonyManager;
 import android.telephony.TransportSelectorCallback;
 import android.telephony.WwanSelectorCallback;
-import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.ImsManager;
 import android.telephony.ims.ImsMmTelManager;
 import android.telephony.ims.ProvisioningManager;
@@ -114,6 +121,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -121,10 +129,7 @@
 import org.mockito.stubbing.Answer;
 
 import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.function.Consumer;
 
 /**
@@ -135,7 +140,7 @@
 
     private static final int SLOT_0 = 0;
     private static final int SLOT_0_SUB_ID = 1;
-    private static final String TEST_EMERGENCY_NUMBER = "911";
+    private static final Uri TEST_URI = Uri.fromParts(PhoneAccount.SCHEME_TEL, "911", null);
 
     @Mock private CarrierConfigManager mCarrierConfigManager;
     @Mock private ConnectivityManager mConnectivityManager;
@@ -148,6 +153,7 @@
     @Mock private ProvisioningManager mProvisioningManager;
     @Mock private CrossSimRedialingController mCsrdCtrl;
     @Mock private CarrierConfigHelper mCarrierConfigHelper;
+    @Mock private EmergencyCallbackModeHelper mEcbmHelper;
     @Mock private Resources mResources;
 
     private Context mContext;
@@ -250,7 +256,6 @@
         doReturn(mProvisioningManager).when(imsManager).getProvisioningManager(anyInt());
         doReturn(null).when(mProvisioningManager).getProvisioningStringValue(anyInt());
 
-        when(mTransportSelectorCallback.onWwanSelected()).thenReturn(mWwanSelectorCallback);
         doAnswer(new Answer<Void>() {
             @Override
             public Void answer(InvocationOnMock invocation) throws Throwable {
@@ -265,11 +270,11 @@
             @Override
             public Void answer(InvocationOnMock invocation) throws Throwable {
                 mAccessNetwork = (List<Integer>) invocation.getArguments()[0];
-                mResultConsumer = (Consumer<EmergencyRegResult>) invocation.getArguments()[3];
+                mResultConsumer = (Consumer<EmergencyRegResult>) invocation.getArguments()[4];
                 return null;
             }
         }).when(mWwanSelectorCallback).onRequestEmergencyNetworkScan(
-                any(), anyInt(), any(), any());
+                any(), anyInt(), anyBoolean(), any(), any());
 
         when(mResources.getStringArray(anyInt())).thenReturn(null);
     }
@@ -293,11 +298,70 @@
         createSelector(SLOT_0_SUB_ID);
 
         verify(mWwanSelectorCallback, times(0)).onRequestEmergencyNetworkScan(
-                any(), anyInt(), any(), any());
+                any(), anyInt(), anyBoolean(), any(), any());
         verify(mWwanSelectorCallback, times(0)).onDomainSelected(anyInt(), eq(true));
     }
 
     @Test
+    public void testDestroyed() throws Exception {
+        createSelector(SLOT_0_SUB_ID);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(UTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_CS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+
+        mDomainSelector.destroy();
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(Integer.MAX_VALUE));
+        unsolBarringInfoChanged(false);
+
+        verify(mTransportSelectorCallback, never()).onWwanSelected(any());
+    }
+
+    @Test
+    public void testDomainPreferenceConfigurationError() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        int[] domainPreference = new int[] {
+                CarrierConfigManager.ImsEmergency.DOMAIN_PS_NON_3GPP,
+                };
+        bundle.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY, domainPreference);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(
+                UNKNOWN, REGISTRATION_STATE_UNKNOWN, 0, false, false, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+
+        verifyScanCsPreferred();
+    }
+
+    @Test
+    public void testNullEmergencyRegResult() throws Exception {
+        doReturn(2).when(mTelephonyManager).getActiveModemCount();
+
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, null);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+
+        verifyScanPsPreferred();
+    }
+
+    @Test
     public void testNoRedundantDomainSelectionFromInitialState() throws Exception {
         createSelector(SLOT_0_SUB_ID);
         unsolBarringInfoChanged(true);
@@ -366,7 +430,7 @@
 
         verify(mTransportSelectorCallback, times(1)).onWwanSelected(any());
         verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
-                any(), anyInt(), any(), any());
+                any(), anyInt(), anyBoolean(), any(), any());
     }
 
     @Test
@@ -474,6 +538,7 @@
         //Extended service request failed
         SelectionAttributes.Builder builder =
                 new SelectionAttributes.Builder(SLOT_0, SLOT_0_SUB_ID, SELECTOR_TYPE_CALLING)
+                .setAddress(TEST_URI)
                 .setCsDisconnectCause(SERVICE_OPTION_NOT_AVAILABLE)
                 .setEmergency(true)
                 .setEmergencyRegResult(regResult);
@@ -485,6 +550,57 @@
     }
 
     @Test
+    public void testDefaultCombinedImsRegisteredSelectPsThenNotExtendedServiceRequestFails()
+            throws Exception {
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_CS | NetworkRegistrationInfo.DOMAIN_PS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsService();
+
+        verifyPsDialed();
+
+        mDomainSelector.reselectDomain(attr);
+        processAllMessages();
+
+        verifyCsDialed();
+
+        SelectionAttributes.Builder builder =
+                new SelectionAttributes.Builder(SLOT_0, SLOT_0_SUB_ID, SELECTOR_TYPE_CALLING)
+                .setEmergency(true)
+                .setEmergencyRegResult(regResult);
+        attr = builder.build();
+        mDomainSelector.reselectDomain(attr);
+        processAllMessages();
+
+        verifyScanPsPreferred();
+    }
+
+    @Test
+    public void testDefaultCombinedImsNotRegisteredDeactivatedSimSelectPs() throws Exception {
+        doReturn(SIM_ACTIVATION_STATE_DEACTIVATED).when(mTelephonyManager).getDataActivationState();
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_CS | NetworkRegistrationInfo.DOMAIN_PS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+
+        verifyPsDialed();
+    }
+
+    @Test
     public void testDefaultCombinedImsNotRegisteredSelectCs() throws Exception {
         createSelector(SLOT_0_SUB_ID);
         unsolBarringInfoChanged(false);
@@ -502,6 +618,56 @@
     }
 
     @Test
+    public void testAirplaneDefaultCombinedImsNotRegisteredSelectPs() throws Exception {
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_CS | NetworkRegistrationInfo.DOMAIN_PS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = new SelectionAttributes.Builder(
+                        SLOT_0, SLOT_0_SUB_ID, SELECTOR_TYPE_CALLING)
+                .setAddress(TEST_URI)
+                .setEmergency(true)
+                .setEmergencyRegResult(regResult)
+                .setExitedFromAirplaneMode(true)
+                .build();
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+
+        verifyPsDialed();
+    }
+
+    @Test
+    public void testAirplaneRequiresRegCombinedImsNotRegisteredSelectPs() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putBoolean(KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL, true);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_CS | NetworkRegistrationInfo.DOMAIN_PS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = new SelectionAttributes.Builder(
+                        SLOT_0, SLOT_0_SUB_ID, SELECTOR_TYPE_CALLING)
+                .setAddress(TEST_URI)
+                .setEmergency(true)
+                .setEmergencyRegResult(regResult)
+                .setExitedFromAirplaneMode(true)
+                .build();
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+
+        verifyPsDialed();
+    }
+
+    @Test
     public void testNoCsCombinedImsNotRegisteredSelectPs() throws Exception {
         PersistableBundle bundle = getDefaultPersistableBundle();
         bundle.putIntArray(KEY_EMERGENCY_OVER_CS_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY,
@@ -762,6 +928,39 @@
     }
 
     @Test
+    public void testNotSupportPsEmergency() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        int[] domainPreference = new int[] {
+                CarrierConfigManager.ImsEmergency.DOMAIN_CS
+                };
+        bundle.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY, domainPreference);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(UTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_CS,
+                false, false, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+
+        verifyCsDialed();
+
+        mDomainSelector.reselectDomain(attr);
+        processAllMessages();
+
+        verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
+                any(), anyInt(), anyBoolean(), any(), any());
+        assertEquals(2, mAccessNetwork.size());
+        assertEquals(UTRAN, (int) mAccessNetwork.get(0));
+        assertEquals(GERAN, (int) mAccessNetwork.get(1));
+    }
+
+    @Test
     public void testDefaultEpsImsRegisteredBarredScanPsPreferred() throws Exception {
         createSelector(SLOT_0_SUB_ID);
         unsolBarringInfoChanged(true);
@@ -1118,11 +1317,57 @@
     }
 
     @Test
+    public void testRequiresRegEpsImsNotRegisteredDeactivatedSimSelectPs() throws Exception {
+        doReturn(SIM_ACTIVATION_STATE_DEACTIVATED).when(mTelephonyManager).getDataActivationState();
+
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putBoolean(KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL, true);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_PS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+
+        verifyPsDialed();
+    }
+
+    @Test
+    public void testRequiresRegEpsImsNotRegisteredEmcNotSupportedScanCsPreferred()
+            throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putBoolean(KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL, true);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_PS,
+                true, false, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+
+        verifyScanCsPreferred();
+    }
+
+    @Test
     public void testDefaultEpsImsRegisteredBarredScanTimeoutWifi() throws Exception {
         PersistableBundle bundle = getDefaultPersistableBundle();
         bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
         when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
 
+        mResultConsumer = null;
         createSelector(SLOT_0_SUB_ID);
         unsolBarringInfoChanged(true);
 
@@ -1147,6 +1392,14 @@
         mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
 
         verify(mTransportSelectorCallback, times(1)).onWlanSelected(eq(true));
+
+        assertNotNull(mResultConsumer);
+
+        mResultConsumer.accept(regResult);
+        processAllMessages();
+
+        // Ignore the stale result
+        verify(mWwanSelectorCallback, never()).onDomainSelected(anyInt(), anyBoolean());
     }
 
     @Test
@@ -1341,6 +1594,36 @@
     }
 
     @Test
+    public void testDualSimInvalidSubscriptionAfterScan() throws Exception {
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+        doReturn(2).when(mTelephonyManager).getActiveModemCount();
+        doReturn(TelephonyManager.SIM_STATE_PIN_REQUIRED)
+                .when(mTelephonyManager).getSimState(anyInt());
+        doReturn(true).when(mCsrdCtrl).isThereOtherSlot();
+        doReturn(new String[] {"jp"}).when(mResources).getStringArray(anyInt());
+
+        EmergencyRegResult regResult = getEmergencyRegResult(UNKNOWN, REGISTRATION_STATE_UNKNOWN,
+                0, false, false, 0, 0, "", "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+        processAllMessages();
+
+        assertNotNull(mResultConsumer);
+
+        regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_UNKNOWN,
+                0, false, false, 0, 0, "", "", "jp");
+        mResultConsumer.accept(regResult);
+        processAllMessages();
+
+        verify(mTransportSelectorCallback, times(1))
+                .onSelectionTerminated(eq(DisconnectCause.EMERGENCY_PERM_FAILURE));
+    }
+
+    @Test
     public void testDualSimInvalidSubscriptionButNoOtherSlot() throws Exception {
         createSelector(SLOT_0_SUB_ID);
         unsolBarringInfoChanged(false);
@@ -1377,6 +1660,30 @@
     }
 
     @Test
+    public void testEutranWithPsDomainOnly() throws Exception {
+        setupForHandleScanResult();
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+                DOMAIN_PS, false, false, 0, 0, "", "");
+        mResultConsumer.accept(regResult);
+        processAllMessages();
+
+        verifyPsDialed();
+    }
+
+    @Test
+    public void testUtran() throws Exception {
+        setupForHandleScanResult();
+
+        EmergencyRegResult regResult = getEmergencyRegResult(UTRAN, REGISTRATION_STATE_HOME,
+                DOMAIN_CS, false, false, 0, 0, "", "");
+        mResultConsumer.accept(regResult);
+        processAllMessages();
+
+        verifyCsDialed();
+    }
+
+    @Test
     public void testFullService() throws Exception {
         PersistableBundle bundle = getDefaultPersistableBundle();
         bundle.putInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT, SCAN_TYPE_FULL_SERVICE);
@@ -1396,18 +1703,41 @@
         processAllMessages();
 
         verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
-                any(), eq(DomainSelectionService.SCAN_TYPE_FULL_SERVICE), any(), any());
+                any(), eq(DomainSelectionService.SCAN_TYPE_FULL_SERVICE), eq(false), any(), any());
         assertNotNull(mResultConsumer);
 
         mResultConsumer.accept(regResult);
         processAllMessages();
 
         verify(mWwanSelectorCallback, times(2)).onRequestEmergencyNetworkScan(
-                any(), eq(DomainSelectionService.SCAN_TYPE_FULL_SERVICE), any(), any());
+                any(), eq(DomainSelectionService.SCAN_TYPE_FULL_SERVICE), eq(false), any(), any());
     }
 
     @Test
-    public void testFullServiceThenLimtedService() throws Exception {
+    public void testFullServiceInRoaming() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT, SCAN_TYPE_FULL_SERVICE);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(true);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_ROAMING,
+                0, true, false, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+        processAllMessages();
+
+        verify(mWwanSelectorCallback).onRequestEmergencyNetworkScan(
+                any(), eq(DomainSelectionService.SCAN_TYPE_NO_PREFERENCE),
+                anyBoolean(), any(), any());
+    }
+
+    @Test
+    public void testFullServiceThenLimitedService() throws Exception {
         PersistableBundle bundle = getDefaultPersistableBundle();
         bundle.putInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT,
                 SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE);
@@ -1427,14 +1757,15 @@
         processAllMessages();
 
         verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
-                any(), eq(DomainSelectionService.SCAN_TYPE_FULL_SERVICE), any(), any());
+                any(), eq(DomainSelectionService.SCAN_TYPE_FULL_SERVICE), eq(false), any(), any());
         assertNotNull(mResultConsumer);
 
         mResultConsumer.accept(regResult);
         processAllMessages();
 
         verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
-                any(), eq(DomainSelectionService.SCAN_TYPE_LIMITED_SERVICE), any(), any());
+                any(), eq(DomainSelectionService.SCAN_TYPE_LIMITED_SERVICE),
+                eq(false), any(), any());
     }
 
     @Test
@@ -1735,16 +2066,6 @@
     }
 
     @Test
-    public void testStopCrossStackTimerOnCancel() throws Exception {
-        createSelector(SLOT_0_SUB_ID);
-        unsolBarringInfoChanged(false);
-
-        mDomainSelector.cancelSelection();
-
-        verify(mCsrdCtrl).stopTimer();
-    }
-
-    @Test
     public void testStopCrossStackTimerOnFinish() throws Exception {
         createSelector(SLOT_0_SUB_ID);
         unsolBarringInfoChanged(false);
@@ -1771,6 +2092,7 @@
         verifyCsDialed();
 
         attr = new SelectionAttributes.Builder(SLOT_0, SLOT_0_SUB_ID, SELECTOR_TYPE_CALLING)
+                .setAddress(TEST_URI)
                 .setEmergency(true)
                 .setEmergencyRegResult(regResult)
                 .setCsDisconnectCause(PreciseDisconnectCause.EMERGENCY_TEMP_FAILURE)
@@ -1799,6 +2121,7 @@
         verifyCsDialed();
 
         attr = new SelectionAttributes.Builder(SLOT_0, SLOT_0_SUB_ID, SELECTOR_TYPE_CALLING)
+                .setAddress(TEST_URI)
                 .setEmergency(true)
                 .setEmergencyRegResult(regResult)
                 .setCsDisconnectCause(PreciseDisconnectCause.EMERGENCY_PERM_FAILURE)
@@ -1885,6 +2208,28 @@
     }
 
     @Test
+    public void testMaxCellularTimeoutWifiNotAvailable() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
+        bundle.putInt(KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT, 20);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+        setupForHandleScanResult();
+
+        assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+        assertTrue(mDomainSelector.hasMessages(MSG_MAX_CELLULAR_TIMEOUT));
+
+        verify(mTransportSelectorCallback, never()).onWlanSelected(anyBoolean());
+
+        // Max cellular timer expired
+        mDomainSelector.removeMessages(MSG_MAX_CELLULAR_TIMEOUT);
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_MAX_CELLULAR_TIMEOUT));
+
+        assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+        verify(mTransportSelectorCallback, never()).onWlanSelected(anyBoolean());
+    }
+
+    @Test
     public void testSimLockNoMaxCellularTimeout() throws Exception {
         when(mTelephonyManager.getSimState(anyInt())).thenReturn(
                 TelephonyManager.SIM_STATE_PIN_REQUIRED);
@@ -1951,6 +2296,8 @@
         mDomainSelector.reselectDomain(attr);
         processAllMessages();
 
+        verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
+                any(), anyInt(), anyBoolean(), any(), any());
         assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
         assertTrue(mDomainSelector.hasMessages(MSG_MAX_CELLULAR_TIMEOUT));
 
@@ -1965,10 +2312,91 @@
         mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_MAX_CELLULAR_TIMEOUT));
         processAllMessages();
 
+        assertFalse(mDomainSelector.hasMessages(MSG_MAX_CELLULAR_TIMEOUT));
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected(anyBoolean());
+
         mDomainSelector.reselectDomain(attr);
         processAllMessages();
 
+        verify(mWwanSelectorCallback, times(2)).onRequestEmergencyNetworkScan(
+                any(), anyInt(), anyBoolean(), any(), any());
+    }
+
+    @Test
+    public void testMaxCellularTimeoutWhileDialingOnCellularWhileDialing() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
+        bundle.putInt(KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT, 5);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(UTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_CS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+
+        verifyCsDialed();
+
+        assertFalse(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
         assertFalse(mDomainSelector.hasMessages(MSG_MAX_CELLULAR_TIMEOUT));
+
+        mResultConsumer = null;
+        mDomainSelector.reselectDomain(attr);
+        processAllMessages();
+
+        verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
+                any(), anyInt(), anyBoolean(), any(), any());
+        assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+        assertTrue(mDomainSelector.hasMessages(MSG_MAX_CELLULAR_TIMEOUT));
+
+        assertNotNull(mResultConsumer);
+
+        // Scan result received and redialing on cellular
+        mResultConsumer.accept(regResult);
+        processAllMessages();
+
+        // Wi-Fi is connected.
+        mNetworkCallback.onAvailable(null);
+        processAllMessages();
+
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected(anyBoolean());
+
+        // Max cellular timer expired
+        mDomainSelector.removeMessages(MSG_MAX_CELLULAR_TIMEOUT);
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_MAX_CELLULAR_TIMEOUT));
+        processAllMessages();
+
+        assertFalse(mDomainSelector.hasMessages(MSG_MAX_CELLULAR_TIMEOUT));
+
+        // Waiting for reselectDomain since there is a dialing on going.
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected(anyBoolean());
+
+        // Wi-Fi is disconnected.
+        mNetworkCallback.onUnavailable();
+        processAllMessages();
+
+        mResultConsumer = null;
+        mDomainSelector.reselectDomain(attr);
+        processAllMessages();
+
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected(anyBoolean());
+        verify(mWwanSelectorCallback, times(2)).onRequestEmergencyNetworkScan(
+                any(), anyInt(), anyBoolean(), any(), any());
+
+        // Wi-Fi is re-connected.
+        mNetworkCallback.onAvailable(null);
+        processAllMessages();
+
+        mResultConsumer = null;
+        mDomainSelector.reselectDomain(attr);
+        processAllMessages();
+
         verify(mTransportSelectorCallback, times(1)).onWlanSelected(anyBoolean());
     }
 
@@ -2059,7 +2487,7 @@
         processAllMessages();
 
         verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
-                any(), anyInt(), any(), any());
+                any(), anyInt(), anyBoolean(), any(), any());
         assertEquals(4, mAccessNetwork.size());
         assertEquals(EUTRAN, (int) mAccessNetwork.get(0));
         assertEquals(NGRAN, (int) mAccessNetwork.get(1));
@@ -2085,7 +2513,7 @@
         processAllMessages();
 
         verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
-                any(), anyInt(), any(), any());
+                any(), anyInt(), anyBoolean(), any(), any());
         assertEquals(4, mAccessNetwork.size());
         assertEquals(EUTRAN, (int) mAccessNetwork.get(0));
         assertEquals(UTRAN, (int) mAccessNetwork.get(1));
@@ -2109,7 +2537,7 @@
         processAllMessages();
 
         verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
-                any(), anyInt(), any(), any());
+                any(), anyInt(), anyBoolean(), any(), any());
         assertEquals(4, mAccessNetwork.size());
         assertEquals(EUTRAN, (int) mAccessNetwork.get(0));
         assertEquals(UTRAN, (int) mAccessNetwork.get(1));
@@ -2136,7 +2564,7 @@
         processAllMessages();
 
         verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
-                any(), anyInt(), any(), any());
+                any(), anyInt(), anyBoolean(), any(), any());
         assertEquals(4, mAccessNetwork.size());
         assertEquals(EUTRAN, (int) mAccessNetwork.get(0));
         assertEquals(NGRAN, (int) mAccessNetwork.get(1));
@@ -2161,6 +2589,38 @@
     }
 
     @Test
+    public void testScanLtePreferredAfterNgranFailure() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putIntArray(KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY,
+                new int[] { NGRAN, EUTRAN });
+        bundle.putBoolean(KEY_EMERGENCY_LTE_PREFERRED_AFTER_NR_FAILED_BOOL, true);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(NGRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_PS, true, false, 1, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+
+        verifyPsDialed();
+
+        mDomainSelector.reselectDomain(attr);
+        processAllMessages();
+
+        verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
+                any(), anyInt(), anyBoolean(), any(), any());
+        assertEquals(3, mAccessNetwork.size());
+        assertEquals(EUTRAN, (int) mAccessNetwork.get(0));
+        assertEquals(UTRAN, (int) mAccessNetwork.get(1));
+        assertEquals(GERAN, (int) mAccessNetwork.get(2));
+    }
+
+    @Test
     public void testDefaultLimitedServiceNgran() throws Exception {
         createSelector(SLOT_0_SUB_ID);
         unsolBarringInfoChanged(false);
@@ -2176,26 +2636,16 @@
         verifyScanPsPreferred();
     }
 
+    @Ignore("Deprecated.")
     @Test
     public void testTestEmergencyNumberOverCs() throws Exception {
-        EmergencyNumber num = new EmergencyNumber(TEST_EMERGENCY_NUMBER, "us", "",
-                EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE, new ArrayList<String>(),
-                EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
-                EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN);
-
-        Map<Integer, List<EmergencyNumber>> lists = new HashMap<>();
-        List<EmergencyNumber> list = new ArrayList<>();
-        list.add(num);
-        lists.put(SLOT_0_SUB_ID, list);
-
-        doReturn(lists).when(mTelephonyManager).getEmergencyNumberList();
-
         createSelector(SLOT_0_SUB_ID);
         unsolBarringInfoChanged(false);
 
         EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_UNKNOWN,
                 0, false, true, 0, 0, "", "");
-        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID,
+                true /*isTestEmergencyNumber*/, regResult);
         mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
         processAllMessages();
 
@@ -2204,26 +2654,16 @@
         verifyCsDialed();
     }
 
+    @Ignore("Deprecated.")
     @Test
     public void testTestEmergencyNumberOverPs() throws Exception {
-        EmergencyNumber num = new EmergencyNumber(TEST_EMERGENCY_NUMBER, "us", "",
-                EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE, new ArrayList<String>(),
-                EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
-                EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN);
-
-        Map<Integer, List<EmergencyNumber>> lists = new HashMap<>();
-        List<EmergencyNumber> list = new ArrayList<>();
-        list.add(num);
-        lists.put(SLOT_0_SUB_ID, list);
-
-        doReturn(lists).when(mTelephonyManager).getEmergencyNumberList();
-
         createSelector(SLOT_0_SUB_ID);
         unsolBarringInfoChanged(false);
 
         EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_UNKNOWN,
                 0, false, true, 0, 0, "", "");
-        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID,
+                true /*isTestEmergencyNumber*/, regResult);
         mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
         processAllMessages();
 
@@ -2232,26 +2672,16 @@
         verifyPsDialed();
     }
 
+    @Ignore("Deprecated.")
     @Test
     public void testTestEmergencyNumberOverWifi() throws Exception {
-        EmergencyNumber num = new EmergencyNumber(TEST_EMERGENCY_NUMBER, "us", "",
-                EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE, new ArrayList<String>(),
-                EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
-                EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN);
-
-        Map<Integer, List<EmergencyNumber>> lists = new HashMap<>();
-        List<EmergencyNumber> list = new ArrayList<>();
-        list.add(num);
-        lists.put(SLOT_0_SUB_ID, list);
-
-        doReturn(lists).when(mTelephonyManager).getEmergencyNumberList();
-
         createSelector(SLOT_0_SUB_ID);
         unsolBarringInfoChanged(false);
 
         EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_UNKNOWN,
                 0, false, true, 0, 0, "", "");
-        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID,
+                true /*isTestEmergencyNumber*/, regResult);
         mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
         processAllMessages();
 
@@ -2277,6 +2707,93 @@
         verifyCsDialed();
     }
 
+    @Test
+    public void testWhileInEcbmOnWwan() throws Exception {
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        doReturn(true).when(mEcbmHelper).isInEmergencyCallbackMode(anyInt());
+        doReturn(TRANSPORT_TYPE_WWAN).when(mEcbmHelper).getTransportType(anyInt());
+        doReturn(DATA_CONNECTED).when(mEcbmHelper).getDataConnectionState(anyInt());
+
+        EmergencyRegResult regResult = getEmergencyRegResult(UNKNOWN, REGISTRATION_STATE_UNKNOWN,
+                0, false, false, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+        processAllMessages();
+
+        verify(mTransportSelectorCallback, never()).onWlanSelected(anyBoolean());
+        verify(mTransportSelectorCallback).onWwanSelected(any());
+    }
+
+    @Test
+    public void testWhileInEcbmOnWlanConnected() throws Exception {
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        doReturn(true).when(mEcbmHelper).isInEmergencyCallbackMode(anyInt());
+        doReturn(TRANSPORT_TYPE_WLAN).when(mEcbmHelper).getTransportType(anyInt());
+        doReturn(DATA_CONNECTED).when(mEcbmHelper).getDataConnectionState(anyInt());
+
+        EmergencyRegResult regResult = getEmergencyRegResult(UNKNOWN, REGISTRATION_STATE_UNKNOWN,
+                0, false, false, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+        processAllMessages();
+
+        verify(mTransportSelectorCallback).onWlanSelected(anyBoolean());
+        verify(mTransportSelectorCallback, never()).onWwanSelected(any());
+    }
+
+    @Test
+    public void testWhileInEcbmOnWlanNotConnected() throws Exception {
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        doReturn(true).when(mEcbmHelper).isInEmergencyCallbackMode(anyInt());
+        doReturn(TRANSPORT_TYPE_WLAN).when(mEcbmHelper).getTransportType(anyInt());
+
+        EmergencyRegResult regResult = getEmergencyRegResult(UNKNOWN, REGISTRATION_STATE_UNKNOWN,
+                0, false, false, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+        processAllMessages();
+
+        verify(mTransportSelectorCallback, never()).onWlanSelected(anyBoolean());
+        verify(mTransportSelectorCallback).onWwanSelected(any());
+    }
+
+    @Test
+    public void testNotInEcbmOnWlanConnected() throws Exception {
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        doReturn(false).when(mEcbmHelper).isInEmergencyCallbackMode(anyInt());
+        doReturn(TRANSPORT_TYPE_WLAN).when(mEcbmHelper).getTransportType(anyInt());
+        doReturn(DATA_CONNECTED).when(mEcbmHelper).getDataConnectionState(anyInt());
+
+        EmergencyRegResult regResult = getEmergencyRegResult(UNKNOWN, REGISTRATION_STATE_UNKNOWN,
+                0, false, false, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+        processAllMessages();
+
+        verify(mTransportSelectorCallback, never()).onWlanSelected(anyBoolean());
+        verify(mTransportSelectorCallback).onWwanSelected(any());
+    }
+
     private void setupForScanListTest(PersistableBundle bundle) throws Exception {
         setupForScanListTest(bundle, false);
     }
@@ -2343,14 +2860,14 @@
         processAllMessages();
 
         verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
-                any(), anyInt(), any(), any());
+                any(), anyInt(), anyBoolean(), any(), any());
         assertNotNull(mResultConsumer);
     }
 
     private void createSelector(int subId) throws Exception {
         mDomainSelector = new EmergencyCallDomainSelector(
                 mContext, SLOT_0, subId, mHandlerThread.getLooper(),
-                mImsStateTracker, mDestroyListener, mCsrdCtrl, mCarrierConfigHelper);
+                mImsStateTracker, mDestroyListener, mCsrdCtrl, mCarrierConfigHelper, mEcbmHelper);
         mDomainSelector.clearResourceConfiguration();
         replaceInstance(DomainSelectorBase.class,
                 "mWwanSelectorCallback", mDomainSelector, mWwanSelectorCallback);
@@ -2377,7 +2894,7 @@
     private void verifyScanPreferred(int scanType, int expectedPreferredAccessNetwork) {
         processAllMessages();
         verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
-                any(), eq(scanType), any(), any());
+                any(), eq(scanType), anyBoolean(), any(), any());
         assertEquals(expectedPreferredAccessNetwork, (int) mAccessNetwork.get(0));
     }
 
@@ -2519,12 +3036,18 @@
         return bundle;
     }
 
-    public static SelectionAttributes getSelectionAttributes(int slotId, int subId,
+    private static SelectionAttributes getSelectionAttributes(int slotId, int subId,
             EmergencyRegResult regResult) {
+        return getSelectionAttributes(slotId, subId, false, regResult);
+    }
+
+    private static SelectionAttributes getSelectionAttributes(int slotId, int subId,
+            boolean isTestEmergencyNumber, EmergencyRegResult regResult) {
         SelectionAttributes.Builder builder =
                 new SelectionAttributes.Builder(slotId, subId, SELECTOR_TYPE_CALLING)
-                .setNumber(TEST_EMERGENCY_NUMBER)
+                .setAddress(TEST_URI)
                 .setEmergency(true)
+                .setTestEmergencyNumber(isTestEmergencyNumber)
                 .setEmergencyRegResult(regResult);
         return builder.build();
     }
diff --git a/tests/src/com/android/services/telephony/domainselection/EmergencyCallbackModeHelperTest.java b/tests/src/com/android/services/telephony/domainselection/EmergencyCallbackModeHelperTest.java
new file mode 100644
index 0000000..9a4e0d8
--- /dev/null
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencyCallbackModeHelperTest.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2024 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.services.telephony.domainselection;
+
+import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.assertNotNull;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
+import android.telephony.TelephonyManager;
+import android.testing.TestableLooper;
+import android.util.Log;
+
+import com.android.TestContext;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Unit tests for EmergencyCallbackModeHelper
+ */
+public class EmergencyCallbackModeHelperTest {
+    private static final String TAG = "EmergencyCallbackModeHelperTest";
+
+    private static final int SLOT_0 = 0;
+    private static final int SLOT_1 = 1;
+    private static final int SUB_1 = 1;
+    private static final int SUB_2 = 2;
+
+    private Context mContext;
+    private HandlerThread mHandlerThread;
+    private TestableLooper mLooper;
+    private EmergencyCallbackModeHelper mEcbmHelper;
+    private CarrierConfigManager mCarrierConfigManager;
+    private TelephonyManager mTelephonyManager;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mContext = new TestContext() {
+            private Intent mIntent;
+
+            @Override
+            public String getSystemServiceName(Class<?> serviceClass) {
+                if (serviceClass == TelephonyManager.class) {
+                    return Context.TELEPHONY_SERVICE;
+                } else if (serviceClass == CarrierConfigManager.class) {
+                    return Context.CARRIER_CONFIG_SERVICE;
+                }
+                return super.getSystemServiceName(serviceClass);
+            }
+
+            @Override
+            public String getOpPackageName() {
+                return "";
+            }
+
+            @Override
+            public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+                return mIntent;
+            }
+
+            @Override
+            public void sendStickyBroadcast(Intent intent) {
+                mIntent = intent;
+            }
+        };
+
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+
+        mHandlerThread = new HandlerThread("EmergencyCallbackModeHelperTest");
+        mHandlerThread.start();
+
+        try {
+            mLooper = new TestableLooper(mHandlerThread.getLooper());
+        } catch (Exception e) {
+            logd("Unable to create looper from handler.");
+        }
+
+        mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
+        mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+        doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
+
+        mEcbmHelper = new EmergencyCallbackModeHelper(mContext, mHandlerThread.getLooper());
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (mEcbmHelper != null) {
+            mEcbmHelper.destroy();
+            mEcbmHelper = null;
+        }
+
+        if (mLooper != null) {
+            mLooper.destroy();
+            mLooper = null;
+        }
+    }
+
+    @Test
+    public void testInit() throws Exception {
+        ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> callbackCaptor =
+                ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
+        ArgumentCaptor<Executor> executorCaptor = ArgumentCaptor.forClass(Executor.class);
+
+        verify(mCarrierConfigManager).registerCarrierConfigChangeListener(executorCaptor.capture(),
+                callbackCaptor.capture());
+        assertNotNull(executorCaptor.getValue());
+        assertNotNull(callbackCaptor.getValue());
+    }
+
+    @Test
+    public void testEmergencyCallbackModeNotSupported() throws Exception {
+        ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> callbackCaptor =
+                ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
+
+        verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(),
+                callbackCaptor.capture());
+
+        CarrierConfigManager.CarrierConfigChangeListener callback = callbackCaptor.getValue();
+
+        assertNotNull(callback);
+
+        // ECBM not supported
+        PersistableBundle b = getPersistableBundle(false);
+        doReturn(b).when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyString());
+        callback.onCarrierConfigChanged(SLOT_0, SUB_1, 0, 0);
+
+        // No TelephonyCallback registered
+        verify(mTelephonyManager, never()).registerTelephonyCallback(any(), any());
+    }
+
+    @Test
+    public void testEmergencyCallbackModeSupported() throws Exception {
+        ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> callbackCaptor =
+                ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
+
+        verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(),
+                callbackCaptor.capture());
+
+        CarrierConfigManager.CarrierConfigChangeListener callback = callbackCaptor.getValue();
+
+        assertNotNull(callback);
+
+        // ECBM supported
+        PersistableBundle b = getPersistableBundle(true);
+        doReturn(b).when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyString());
+        callback.onCarrierConfigChanged(SLOT_0, SUB_1, 0, 0);
+
+        verify(mTelephonyManager).createForSubscriptionId(eq(SUB_1));
+
+        ArgumentCaptor<TelephonyCallback> telephonyCallbackCaptor =
+                ArgumentCaptor.forClass(TelephonyCallback.class);
+
+        // TelephonyCallback registered
+        verify(mTelephonyManager).registerTelephonyCallback(any(),
+                telephonyCallbackCaptor.capture());
+
+        assertNotNull(telephonyCallbackCaptor.getValue());
+    }
+
+    @Test
+    public void testEmergencyCallbackModeChanged() throws Exception {
+        ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> callbackCaptor =
+                ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
+
+        verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(),
+                callbackCaptor.capture());
+
+        CarrierConfigManager.CarrierConfigChangeListener callback = callbackCaptor.getValue();
+
+        assertNotNull(callback);
+
+        // ECBM supported
+        PersistableBundle b = getPersistableBundle(true);
+        doReturn(b).when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyString());
+        callback.onCarrierConfigChanged(SLOT_0, SUB_1, 0, 0);
+
+        verify(mTelephonyManager).createForSubscriptionId(eq(SUB_1));
+
+        ArgumentCaptor<TelephonyCallback> telephonyCallbackCaptor =
+                ArgumentCaptor.forClass(TelephonyCallback.class);
+
+        // TelephonyCallback registered
+        verify(mTelephonyManager).registerTelephonyCallback(any(),
+                telephonyCallbackCaptor.capture());
+
+        TelephonyCallback telephonyCallback = telephonyCallbackCaptor.getValue();
+
+        assertNotNull(telephonyCallback);
+
+        // Carrier config changes, ECBM not supported
+        b = getPersistableBundle(false);
+        doReturn(b).when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyString());
+        callback.onCarrierConfigChanged(SLOT_0, SUB_1, 0, 0);
+
+        // TelephonyCallback unregistered
+        verify(mTelephonyManager).unregisterTelephonyCallback(eq(telephonyCallback));
+    }
+
+    @Test
+    public void testEmergencyCallbackModeEnter() throws Exception {
+        ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> callbackCaptor =
+                ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
+
+        verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(),
+                callbackCaptor.capture());
+
+        CarrierConfigManager.CarrierConfigChangeListener callback = callbackCaptor.getValue();
+
+        assertNotNull(callback);
+
+        // ECBM supported
+        PersistableBundle b = getPersistableBundle(true);
+        doReturn(b).when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyString());
+        callback.onCarrierConfigChanged(SLOT_0, SUB_1, 0, 0);
+        callback.onCarrierConfigChanged(SLOT_1, SUB_2, 0, 0);
+
+        // Enter ECBM on slot 1
+        mContext.sendStickyBroadcast(getIntent(true, SLOT_1));
+
+        assertFalse(mEcbmHelper.isInEmergencyCallbackMode(SLOT_0));
+        assertTrue(mEcbmHelper.isInEmergencyCallbackMode(SLOT_1));
+    }
+
+    @Test
+    public void testEmergencyCallbackModeExit() throws Exception {
+        ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> callbackCaptor =
+                ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
+
+        verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(),
+                callbackCaptor.capture());
+
+        CarrierConfigManager.CarrierConfigChangeListener callback = callbackCaptor.getValue();
+
+        assertNotNull(callback);
+
+        // ECBM supported
+        PersistableBundle b = getPersistableBundle(true);
+        doReturn(b).when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyString());
+        callback.onCarrierConfigChanged(SLOT_0, SUB_1, 0, 0);
+
+        // Exit ECBM
+        mContext.sendStickyBroadcast(getIntent(false, SLOT_0));
+
+        assertFalse(mEcbmHelper.isInEmergencyCallbackMode(SLOT_0));
+    }
+
+    private static Intent getIntent(boolean inEcm, int slotIndex) {
+        Intent intent = new Intent(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
+        intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, inEcm);
+        intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, slotIndex);
+        return intent;
+    }
+
+    private static PersistableBundle getPersistableBundle(boolean supported) {
+        PersistableBundle bundle  = new PersistableBundle();
+        bundle.putBoolean(KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL, supported);
+        return bundle;
+    }
+
+    private static void logd(String str) {
+        Log.d(TAG, str);
+    }
+}
diff --git a/tests/src/com/android/services/telephony/domainselection/EmergencySmsDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/EmergencySmsDomainSelectorTest.java
index ed064cb..e10e9bd 100644
--- a/tests/src/com/android/services/telephony/domainselection/EmergencySmsDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencySmsDomainSelectorTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
@@ -39,6 +40,7 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.DataSpecificRegistrationInfo;
 import android.telephony.DomainSelectionService.SelectionAttributes;
+import android.telephony.EmergencyRegResult;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
@@ -92,6 +94,7 @@
     private ImsStateTracker.BarringInfoListener mBarringInfoListener;
     private ImsStateTracker.ServiceStateListener mServiceStateListener;
     private EmergencySmsDomainSelector mDomainSelector;
+    private EmergencyRegResult mEmergencyRegResult;
 
     @Before
     public void setUp() throws Exception {
@@ -151,6 +154,7 @@
             mLooper = null;
         }
 
+        mEmergencyRegResult = null;
         mDomainSelector = null;
         mNetworkRegistrationInfo = null;
         mVopsSupportInfo = null;
@@ -246,6 +250,26 @@
 
     @Test
     @SmallTest
+    public void testIsSmsOverImsAvailableWhenImsRegisteredAndConfigEnabledAndNrAvailable() {
+        setUpImsStateTracker(AccessNetworkType.NGRAN);
+        setUpCarrierConfig(true);
+        setUpNrInService(false, false, true, false);
+
+        assertTrue(mDomainSelector.isSmsOverImsAvailable());
+    }
+
+    @Test
+    @SmallTest
+    public void testIsSmsOverImsAvailableWhenImsRegisteredAndConfigEnabledAndNrNotAvailable() {
+        setUpImsStateTracker(AccessNetworkType.NGRAN);
+        setUpCarrierConfig(true);
+        setUpNrInService(false, false, false, false);
+
+        assertFalse(mDomainSelector.isSmsOverImsAvailable());
+    }
+
+    @Test
+    @SmallTest
     public void testIsSmsOverImsAvailableWhenCarrierConfigManagerIsNull() {
         setUpImsStateTracker(AccessNetworkType.UNKNOWN);
         mCarrierConfigManagerNullTest = true;
@@ -291,7 +315,7 @@
 
     @Test
     @SmallTest
-    public void testIsSmsOverImsAvailableWhenNoLte() {
+    public void testIsSmsOverImsAvailableWhenNoLteOrNr() {
         setUpImsStateTracker(AccessNetworkType.UNKNOWN);
         setUpCarrierConfig(true);
         mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
@@ -395,6 +419,56 @@
 
     @Test
     @SmallTest
+    public void testIsSmsOverImsAvailableWhenNrNotRegisteredOrEmergencyNotEnabled() {
+        setUpImsStateTracker(AccessNetworkType.UNKNOWN);
+        setUpCarrierConfig(true);
+        setUpNrInService(false, false, false, false);
+
+        assertFalse(mDomainSelector.isSmsOverImsAvailable());
+    }
+
+    @Test
+    @SmallTest
+    public void testIsSmsOverImsAvailableWhenNrInServiceAndNoDataSpecificRegistrationInfo() {
+        setUpImsStateTracker(AccessNetworkType.UNKNOWN);
+        setUpCarrierConfig(true);
+        setUpNrInService(true, true, false, false);
+
+        assertFalse(mDomainSelector.isSmsOverImsAvailable());
+    }
+
+    @Test
+    @SmallTest
+    public void testIsSmsOverImsAvailableWhenNrInServiceAndNoVopsSupportInfo() {
+        setUpImsStateTracker(AccessNetworkType.UNKNOWN);
+        setUpCarrierConfig(true);
+        setUpNrInService(false, true, false, false);
+
+        assertFalse(mDomainSelector.isSmsOverImsAvailable());
+    }
+
+    @Test
+    @SmallTest
+    public void testIsSmsOverImsAvailableWhenNrInServiceAndEmergencyServiceSupported() {
+        setUpImsStateTracker(AccessNetworkType.UNKNOWN);
+        setUpCarrierConfig(true);
+        setUpNrInService(false, false, true, false);
+
+        assertTrue(mDomainSelector.isSmsOverImsAvailable());
+    }
+
+    @Test
+    @SmallTest
+    public void testIsSmsOverImsAvailableWhenNrInServiceAndEmergencyServiceFallbackSupported() {
+        setUpImsStateTracker(AccessNetworkType.UNKNOWN);
+        setUpCarrierConfig(true);
+        setUpNrInService(false, false, false, true);
+
+        assertTrue(mDomainSelector.isSmsOverImsAvailable());
+    }
+
+    @Test
+    @SmallTest
     public void testSelectDomainWhilePreviousRequestInProgress() {
         setUpImsStateTracker(AccessNetworkType.EUTRAN);
         setUpWwanSelectorCallback();
@@ -675,6 +749,116 @@
                 eq(true));
     }
 
+    @Test
+    @SmallTest
+    public void testSelectDomainWhileEmergencyNetworkScanInProgress() {
+        setUpImsStateTracker(AccessNetworkType.NGRAN);
+        setUpEmergencyRegResult(AccessNetworkType.NGRAN, NetworkRegistrationInfo.DOMAIN_PS, 1, 0);
+        setUpWwanSelectorCallback();
+        setUpCarrierConfig(true);
+        setUpNrInService(false, false, false, true);
+        setUpImsStateListener(true, true, true);
+
+        mDomainSelector.selectDomain(mSelectionAttributes, mTransportSelectorCallback);
+        // Call the domain selection before completing the emergency network scan.
+        mDomainSelector.selectDomain(mSelectionAttributes, mTransportSelectorCallback);
+        processAllMessages();
+
+        // onRequestEmergencyNetworkScan is invoked only once.
+        verify(mWwanSelectorCallback).onRequestEmergencyNetworkScan(any(), anyInt(),
+                anyBoolean(), any(), any());
+    }
+
+    @Test
+    @SmallTest
+    public void testSelectDomainWhenNrEmergencyServiceSupported() {
+        setUpImsStateTracker(AccessNetworkType.NGRAN);
+        setUpEmergencyRegResult(AccessNetworkType.NGRAN, NetworkRegistrationInfo.DOMAIN_PS, 1, 0);
+        setUpWwanSelectorCallback();
+        setUpCarrierConfig(true);
+        setUpNrInService(false, false, true, false);
+        setUpImsStateListener(true, true, true);
+
+        mDomainSelector.selectDomain(mSelectionAttributes, mTransportSelectorCallback);
+        processAllMessages();
+
+        // Expected: PS network
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS),
+                eq(true));
+    }
+
+    @Test
+    @SmallTest
+    public void testSelectDomainWhenEmergencyRegistrationResultNgranAndPsDomain() {
+        setUpImsStateTracker(AccessNetworkType.NGRAN);
+        setUpEmergencyRegResult(AccessNetworkType.NGRAN, NetworkRegistrationInfo.DOMAIN_PS, 1, 0);
+        setUpWwanSelectorCallback();
+        setUpCarrierConfig(true);
+        setUpNrInService(false, false, false, true);
+        setUpImsStateListener(true, true, true);
+
+        mDomainSelector.selectDomain(mSelectionAttributes, mTransportSelectorCallback);
+        processAllMessages();
+
+        // Expected: PS network
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS),
+                eq(true));
+    }
+
+    @Test
+    @SmallTest
+    public void testSelectDomainWhenEmergencyRegistrationResultEutranAndPsDomain() {
+        setUpImsStateTracker(AccessNetworkType.NGRAN);
+        setUpEmergencyRegResult(AccessNetworkType.EUTRAN, NetworkRegistrationInfo.DOMAIN_PS, 0, 0);
+        setUpWwanSelectorCallback();
+        setUpCarrierConfig(true);
+        setUpNrInService(false, false, false, true);
+        setUpImsStateListener(true, true, true);
+
+        mDomainSelector.selectDomain(mSelectionAttributes, mTransportSelectorCallback);
+        processAllMessages();
+
+        // Expected: PS network
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS),
+                eq(true));
+    }
+
+    @Test
+    @SmallTest
+    public void testSelectDomainWhenEmergencyRegistrationResultEutranAndCsDomain() {
+        setUpImsStateTracker(AccessNetworkType.NGRAN);
+        setUpEmergencyRegResult(AccessNetworkType.EUTRAN, NetworkRegistrationInfo.DOMAIN_CS, 0, 0);
+        setUpWwanSelectorCallback();
+        setUpCarrierConfig(true);
+        setUpNrInService(false, false, false, true);
+        setUpImsStateListener(true, true, true);
+
+        mDomainSelector.selectDomain(mSelectionAttributes, mTransportSelectorCallback);
+        processAllMessages();
+
+        // Expected: CS network
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS),
+                eq(false));
+    }
+
+    @Test
+    @SmallTest
+    public void testSelectDomainWhenEmergencyRegistrationResultUtranAndCsDomain() {
+        setUpImsStateTracker(AccessNetworkType.NGRAN);
+        setUpEmergencyRegResult(AccessNetworkType.UTRAN, NetworkRegistrationInfo.DOMAIN_CS, 0, 0);
+        setUpWwanSelectorCallback();
+        setUpCarrierConfig(true);
+        setUpNrInService(false, false, false, true);
+        setUpImsStateListener(true, true, true);
+
+        mDomainSelector.selectDomain(mSelectionAttributes, mTransportSelectorCallback);
+        processAllMessages();
+
+        // Expected: CS network
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS),
+                eq(false));
+    }
+
     private void setUpCarrierConfig(boolean supported) {
         PersistableBundle b = new PersistableBundle();
         b.putBoolean(CarrierConfigManager.KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL, supported);
@@ -760,6 +944,29 @@
         mBarringInfoListener.onBarringInfoUpdated(barringInfo);
     }
 
+    private void setUpNrInService(boolean noDataSpecificRegistrationInfo,
+            boolean noVopsSupportInfo, boolean emergencyServiceSupported,
+            boolean emergencyServiceFallbackSupported) {
+        DataSpecificRegistrationInfo dsri = noDataSpecificRegistrationInfo
+                ? null : new DataSpecificRegistrationInfo(
+                        8, false, false, false, noVopsSupportInfo ? null : mVopsSupportInfo);
+
+        mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
+                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR)
+                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
+                .setDataSpecificInfo(dsri)
+                .build();
+        when(mServiceState.getNetworkRegistrationInfo(
+                anyInt(), eq(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)))
+                .thenReturn(mNetworkRegistrationInfo);
+        when(mVopsSupportInfo.isEmergencyServiceSupported()).thenReturn(emergencyServiceSupported);
+        when(mVopsSupportInfo.isEmergencyServiceFallbackSupported())
+                .thenReturn(emergencyServiceFallbackSupported);
+
+        mServiceStateListener.onServiceStateUpdated(mServiceState);
+        mBarringInfoListener.onBarringInfoUpdated(null);
+    }
+
     private void setUpImsStateTracker(@RadioAccessNetworkType int accessNetworkType) {
         setUpImsStateTracker(accessNetworkType, true, true);
     }
@@ -783,6 +990,22 @@
             callback.accept(mWwanSelectorCallback);
             return null;
         }).when(mTransportSelectorCallback).onWwanSelected(any(Consumer.class));
+
+        doAnswer((invocation) -> {
+            Object[] args = invocation.getArguments();
+            final Consumer<EmergencyRegResult> result = (Consumer<EmergencyRegResult>) args[4];
+            result.accept(mEmergencyRegResult);
+            return null;
+        }).when(mWwanSelectorCallback).onRequestEmergencyNetworkScan(
+                any(), anyInt(), anyBoolean(), any(), any());
+    }
+
+    private void setUpEmergencyRegResult(
+            @AccessNetworkConstants.RadioAccessNetworkType int accessNetwork,
+            @NetworkRegistrationInfo.Domain int domain, int nrEs, int nrEsfb) {
+        mEmergencyRegResult = new EmergencyRegResult(accessNetwork,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME,
+                domain, true, true, nrEs, nrEsfb, "001", "01", "");
     }
 
     private void setUpImsStateListener(boolean notifyMmTelFeatureAvailable,
diff --git a/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java
index 002c7d5..d6e701a 100644
--- a/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java
@@ -17,7 +17,6 @@
 package com.android.services.telephony.domainselection;
 
 import static android.telephony.DomainSelectionService.SELECTOR_TYPE_CALLING;
-import static android.telephony.DomainSelectionService.SELECTOR_TYPE_UT;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -28,10 +27,12 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.net.Uri;
 import android.os.CancellationSignal;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.PersistableBundle;
+import android.telecom.PhoneAccount;
 import android.telecom.TelecomManager;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.CarrierConfigManager;
@@ -69,10 +70,12 @@
 public class NormalCallDomainSelectorTest {
     private static final String TAG = "NormalCallDomainSelectorTest";
 
+    private static final int SELECTOR_TYPE_UT = 3;
     private static final int SLOT_ID = 0;
     private static final int SUB_ID_1 = 1;
     private static final int SUB_ID_2 = 2;
     private static final String TEST_CALLID = "01234";
+    private static final Uri TEST_URI = Uri.fromParts(PhoneAccount.SCHEME_TEL, "123456789", null);
 
     private HandlerThread mHandlerThread;
     private NormalCallDomainSelector mNormalCallDomainSelector;
@@ -157,6 +160,7 @@
         DomainSelectionService.SelectionAttributes attributes =
                 new DomainSelectionService.SelectionAttributes.Builder(
                         SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
+                        .setAddress(TEST_URI)
                         .setCallId(TEST_CALLID)
                         .setEmergency(false)
                         .setVideoCall(true)
@@ -193,6 +197,7 @@
         // Case 4: Invalid Subscription-id
         attributes = new DomainSelectionService.SelectionAttributes.Builder(
                 SLOT_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID, SELECTOR_TYPE_CALLING)
+                .setAddress(TEST_URI)
                 .setCallId(TEST_CALLID)
                 .setEmergency(false)
                 .setVideoCall(true)
@@ -211,6 +216,7 @@
         attributes =
                 new DomainSelectionService.SelectionAttributes.Builder(
                         SLOT_ID, SUB_ID_1, SELECTOR_TYPE_UT)
+                        .setAddress(TEST_URI)
                         .setCallId(TEST_CALLID)
                         .setEmergency(false)
                         .setVideoCall(true)
@@ -228,6 +234,7 @@
         // Case 6: Emergency Call
         attributes = new DomainSelectionService.SelectionAttributes.Builder(
                 SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
+                .setAddress(TEST_URI)
                 .setCallId(TEST_CALLID)
                 .setEmergency(true)
                 .setVideoCall(true)
@@ -250,6 +257,7 @@
         DomainSelectionService.SelectionAttributes attributes =
                 new DomainSelectionService.SelectionAttributes.Builder(
                         SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
+                        .setAddress(TEST_URI)
                         .setCallId(TEST_CALLID)
                         .setEmergency(false)
                         .setVideoCall(true)
@@ -270,6 +278,7 @@
         DomainSelectionService.SelectionAttributes attributes =
                 new DomainSelectionService.SelectionAttributes.Builder(
                         SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
+                        .setAddress(TEST_URI)
                         .setCallId(TEST_CALLID)
                         .setEmergency(false)
                         .setVideoCall(false)
@@ -296,6 +305,7 @@
         imsReasonInfo.mCode = ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED;
         attributes = new DomainSelectionService.SelectionAttributes.Builder(
                 SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
+                .setAddress(TEST_URI)
                 .setCallId(TEST_CALLID)
                 .setEmergency(false)
                 .setVideoCall(false)
@@ -334,7 +344,7 @@
         DomainSelectionService.SelectionAttributes attributes =
                 new DomainSelectionService.SelectionAttributes.Builder(
                         SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
-                        .setNumber("*272121")
+                        .setAddress(Uri.fromParts(PhoneAccount.SCHEME_TEL, "*272121", null))
                         .setCallId(TEST_CALLID)
                         .setEmergency(false)
                         .setVideoCall(false)
@@ -378,6 +388,7 @@
         DomainSelectionService.SelectionAttributes attributes =
                 new DomainSelectionService.SelectionAttributes.Builder(
                         SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
+                        .setAddress(TEST_URI)
                         .setCallId(TEST_CALLID)
                         .setEmergency(false)
                         .setVideoCall(false)
@@ -451,13 +462,6 @@
         }
 
         @Override
-        public synchronized WwanSelectorCallback onWwanSelected() {
-            mWwanSelected = true;
-            notifyAll();
-            return (WwanSelectorCallback) this;
-        }
-
-        @Override
         public void onWwanSelected(final Consumer<WwanSelectorCallback> consumer) {
             mWwanSelected = true;
             Executors.newSingleThreadExecutor().execute(() -> {
@@ -500,6 +504,7 @@
         @Override
         public void onRequestEmergencyNetworkScan(@NonNull List<Integer> preferredNetworks,
                                                   int scanType,
+                                                  boolean resetScan,
                                                   @NonNull CancellationSignal signal,
                                                   @NonNull Consumer<EmergencyRegResult> consumer) {
             Log.i(TAG, "onRequestEmergencyNetworkScan - called");
diff --git a/tests/src/com/android/services/telephony/domainselection/OWNERS b/tests/src/com/android/services/telephony/domainselection/OWNERS
index b9112be..2a76770 100644
--- a/tests/src/com/android/services/telephony/domainselection/OWNERS
+++ b/tests/src/com/android/services/telephony/domainselection/OWNERS
@@ -6,3 +6,4 @@
 mkoon@google.com
 seheele@google.com
 radhikaagrawal@google.com
+jdyou@google.com
diff --git a/tests/src/com/android/services/telephony/domainselection/SmsDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/SmsDomainSelectorTest.java
index 8f78a58..38e058b 100644
--- a/tests/src/com/android/services/telephony/domainselection/SmsDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/SmsDomainSelectorTest.java
@@ -190,21 +190,6 @@
 
     @Test
     @SmallTest
-    public void testCancelSelection() {
-        setUpImsStateTracker(AccessNetworkType.EUTRAN);
-
-        mDomainSelector.selectDomain(mSelectionAttributes, mTransportSelectorCallback);
-
-        assertTrue(mDomainSelector.isDomainSelectionRequested());
-
-        mDomainSelector.cancelSelection();
-
-        assertFalse(mDomainSelector.isDomainSelectionRequested());
-        verify(mDomainSelectorDestroyListener).onDomainSelectorDestroyed(eq(mDomainSelector));
-    }
-
-    @Test
-    @SmallTest
     public void testFinishSelection() {
         setUpImsStateTracker(AccessNetworkType.EUTRAN);
 
diff --git a/tests/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionServiceTest.java b/tests/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionServiceTest.java
index f4d2732..53bbce9 100644
--- a/tests/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionServiceTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.os.Handler;
 import android.os.Looper;
@@ -81,11 +82,11 @@
                         @NonNull Looper looper, @NonNull ImsStateTracker imsStateTracker,
                         @NonNull DomainSelectorBase.DestroyListener listener,
                         @NonNull CrossSimRedialingController crossSimRedialingController,
-                        @NonNull CarrierConfigHelper carrierConfigHelper) {
+                        @NonNull CarrierConfigHelper carrierConfigHelper,
+                        @NonNull EmergencyCallbackModeHelper ecbmHelper) {
                     switch (selectorType) {
                         case DomainSelectionService.SELECTOR_TYPE_CALLING: // fallthrough
-                        case DomainSelectionService.SELECTOR_TYPE_SMS: // fallthrough
-                        case DomainSelectionService.SELECTOR_TYPE_UT:
+                        case DomainSelectionService.SELECTOR_TYPE_SMS:
                             mDomainSelectorDestroyListener = listener;
                             if (subId == SUB_1) {
                                 return mDomainSelectorBase1;
@@ -97,6 +98,26 @@
                     }
                 }
             };
+    private static class TestTelephonyDomainSelectionService
+            extends TelephonyDomainSelectionService {
+        private final Context mContext;
+
+        TestTelephonyDomainSelectionService(Context context,
+                @NonNull ImsStateTrackerFactory imsStateTrackerFactory,
+                @NonNull DomainSelectorFactory domainSelectorFactory,
+                @Nullable CarrierConfigHelper carrierConfigHelper,
+                @Nullable EmergencyCallbackModeHelper ecbmHelper) {
+            super(imsStateTrackerFactory, domainSelectorFactory, carrierConfigHelper, ecbmHelper);
+            mContext = context;
+        }
+
+        @Override
+        public void onCreate() {
+            // attach test context.
+            attachBaseContext(mContext);
+            super.onCreate();
+        }
+    }
     private static final int SLOT_0 = 0;
     private static final int SUB_1 = 1;
     private static final int SUB_2 = 2;
@@ -111,6 +132,7 @@
     @Mock private TransportSelectorCallback mSelectorCallback2;
     @Mock private ImsStateTracker mImsStateTracker;
     @Mock private CarrierConfigHelper mCarrierConfigHelper;
+    @Mock private EmergencyCallbackModeHelper mEcbmHelper;
 
     private final ServiceState mServiceState = new ServiceState();
     private final BarringInfo mBarringInfo = new BarringInfo();
@@ -131,8 +153,9 @@
         }
 
         mContext = new TestContext();
-        mDomainSelectionService = new TelephonyDomainSelectionService(mContext,
-                mImsStateTrackerFactory, mDomainSelectorFactory, mCarrierConfigHelper);
+        mDomainSelectionService = new TestTelephonyDomainSelectionService(mContext,
+                mImsStateTrackerFactory, mDomainSelectorFactory, mCarrierConfigHelper, mEcbmHelper);
+        mDomainSelectionService.onCreate();
         mServiceHandler = new Handler(mDomainSelectionService.getLooper());
         mTestableLooper = new TestableLooper(mDomainSelectionService.getLooper());
 
@@ -184,9 +207,7 @@
                 .setCallId(CALL_ID)
                 .setEmergency(true)
                 .build();
-        mServiceHandler.post(() -> {
-            mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1);
-        });
+        mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1);
         processAllMessages();
 
         verify(mImsStateTracker).start(eq(SUB_1));
@@ -203,9 +224,7 @@
                 .setCallId(CALL_ID)
                 .setEmergency(true)
                 .build();
-        mServiceHandler.post(() -> {
-            mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1);
-        });
+        mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1);
         processAllMessages();
 
         verify(mImsStateTracker, never()).start(anyInt());
@@ -222,9 +241,7 @@
                 .setCallId(CALL_ID)
                 .setEmergency(true)
                 .build();
-        mServiceHandler.post(() -> {
-            mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1);
-        });
+        mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1);
         processAllMessages();
 
         verify(mImsStateTracker).start(eq(SUB_1));
@@ -240,9 +257,7 @@
                 .setCallId(CALL_ID)
                 .setEmergency(true)
                 .build();
-        mServiceHandler.post(() -> {
-            mDomainSelectionService.onDomainSelection(attr2, mSelectorCallback2);
-        });
+        mDomainSelectionService.onDomainSelection(attr2, mSelectorCallback2);
         processAllMessages();
 
         verify(mImsStateTracker).start(eq(SUB_2));
@@ -259,9 +274,7 @@
                 .setCallId(CALL_ID)
                 .setEmergency(true)
                 .build();
-        mServiceHandler.post(() -> {
-            mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1);
-        });
+        mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1);
         processAllMessages();
 
         verify(mImsStateTracker).start(eq(SUB_1));
@@ -274,9 +287,7 @@
                 .setCallId(CALL_ID)
                 .setEmergency(true)
                 .build();
-        mServiceHandler.post(() -> {
-            mDomainSelectionService.onDomainSelection(attr2, mSelectorCallback2);
-        });
+        mDomainSelectionService.onDomainSelection(attr2, mSelectorCallback2);
         processAllMessages();
 
         verify(mImsStateTracker).start(eq(SUB_2));
@@ -309,9 +320,7 @@
                 .setCallId(CALL_ID)
                 .setEmergency(true)
                 .build();
-        mServiceHandler.post(() -> {
-            mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1);
-        });
+        mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1);
         processAllMessages();
 
         mDomainSelectionService.onDestroy();