Snap for 9710098 from efb7333868de4e8240935a8fc6a091100354a9c9 to mainline-tzdata5-release

Change-Id: Ieaed81151df559ad84ba08eaa6a19791816087fe
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 461b18e..ecc4e0f 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -135,6 +135,7 @@
     <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
     <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
     <uses-permission android:name="android.permission.BIND_TELEPHONY_DATA_SERVICE" />
+    <uses-permission android:name="android.permission.BIND_SATELLITE_SERVICE" />
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
     <uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE" />
     <uses-permission android:name="android.permission.MANAGE_ROLE_HOLDERS" />
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 7a251d8..ac9bf5b 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Jou bluetooth-sein is swak. Probeer om na luidsprekerfoon oor te skakel."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Kennisgewing oor oproepgehalte"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Opgeskorte SIP-rekeninge"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Kan nie boodskap van hierdie profiel af stuur nie"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Jou werkbeleid laat jou toe om boodskappe slegs van die werkprofiel af te stuur"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Kanselleer"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Skakel oor na werkprofiel"</string>
 </resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index dcd184e..9b83d89 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"የእርስዎ የብሉቱዝ ሲግናል ደካማ ነው። ወደ የስልክ ድምፅ ማጉያ ለመቀየር ይሞክሩ።"</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"የጥሪ ጥራት ማሳወቂያ"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"የተቋረጡ የSIP መለያዎች"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"ከዚህ መገለጫ መልዕክት መላክ አይቻልም"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"የሥራ መመሪያዎ እርስዎ ከሥራ መገለጫው ብቻ መልዕክት እንዲልኩ ይፈቅድልዎታል"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"ይቅር"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"ወደ የሥራ መገለጫ ቀይር"</string>
 </resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index a755490..5870858 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"إشارة البلوتوث ضعيفة. حاوِل التبديل إلى مكبّر الصوت."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"إشعار بشأن جودة المكالمة"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"‏حسابات SIP المتوقّفة"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"لا يمكن إرسال رسالة من هذا الملف الشخصي"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"تسمح لك سياسة العمل بإرسال الرسائل من الملف الشخصي للعمل فقط."</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"إلغاء"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"التبديل إلى الملف الشخصي للعمل"</string>
 </resources>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 125539f..a250aca 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"আপোনাৰ ব্লুটুথৰ ছিগনেল দুৰ্বল। স্পীকাৰফ’নলৈ সলনি কৰি চাওক।"</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"কলৰ গুণগত মানৰ জাননী"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"বন্ধ হৈ যোৱা SIP একাউণ্ট"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"এই প্ৰ’ফাইলৰ পৰা বাৰ্তা পঠিয়াব নোৱাৰি"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"আপোনাৰ কৰ্মস্থানৰ নীতিয়ে আপোনাক কেৱল কৰ্মস্থানৰ প্ৰ’ফাইলৰ পৰা বাৰ্তা পঠিয়াবলৈ দিয়ে"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"বাতিল কৰক"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"কৰ্মস্থানৰ প্ৰ’ফাইললৈ সলনি কৰক"</string>
 </resources>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index a1e694b..783c6ca 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -281,7 +281,7 @@
     <string name="data_enabled" msgid="22525832097434368">"Data aktivdir"</string>
     <string name="data_enable_summary" msgid="696860063456536557">"Data istifadəsinə icazə verin"</string>
     <string name="dialog_alert_title" msgid="5260471806940268478">"Diqqət"</string>
-    <string name="roaming" msgid="1576180772877858949">"Rominq"</string>
+    <string name="roaming" msgid="1576180772877858949">"Rouminq"</string>
     <string name="roaming_enable" msgid="6853685214521494819">"Rominq zamanı data xidmətinə qoşulun"</string>
     <string name="roaming_disable" msgid="8856224638624592681">"Rominq zamanı data xidmətinə qoşulun"</string>
     <string name="roaming_reenable_message" msgid="1951802463885727915">"Data rominqi deaktivdir. Aktiv etmək üçün klikləyin."</string>
@@ -852,7 +852,7 @@
     <string name="radioInfo_service_out" msgid="287972405416142312">"Xidmətdən kənarda"</string>
     <string name="radioInfo_service_emergency" msgid="4763879891415016848">"Yalnız təcili zənglər"</string>
     <string name="radioInfo_service_off" msgid="3456583511226783064">"Radio Deaktivdir"</string>
-    <string name="radioInfo_roaming_in" msgid="3156335577793145965">"Rominq"</string>
+    <string name="radioInfo_roaming_in" msgid="3156335577793145965">"Rouminq"</string>
     <string name="radioInfo_roaming_not" msgid="1904547918725478110">"Rominq Deyil"</string>
     <string name="radioInfo_phone_idle" msgid="2191653783170757819">"Fəaliyyətsiz"</string>
     <string name="radioInfo_phone_ringing" msgid="8100354169567413370">"Zəng"</string>
@@ -877,7 +877,7 @@
     <string name="radio_info_cell_info_refresh_rate" msgid="670511448975997340">"Mobil məlumatın yenilənmə göstəricisi:"</string>
     <string name="radio_info_cellinfo_label" msgid="8199062974670377659">"Operatorun bütün mobil ölçü məlumatı:"</string>
     <string name="radio_info_gprs_service_label" msgid="6819204246355412952">"Data Xidməti:"</string>
-    <string name="radio_info_roaming_label" msgid="6636932886446857120">"Rominq:"</string>
+    <string name="radio_info_roaming_label" msgid="6636932886446857120">"Rouminq:"</string>
     <string name="radio_info_imei_label" msgid="8947899706930120368">"IMEI:"</string>
     <string name="radio_info_call_redirect_label" msgid="4526480903023362276">"Zəng Yönləndirməsi:"</string>
     <string name="radio_info_ppp_resets_label" msgid="9131901102339077661">"Yükləmədən bəri sıfırlanan PPP sayı:"</string>
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Bluetooth siqnalı zəifdir. Telefon spikerinə keçin."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Zəng keyfiyyəti bildirişi"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Ləğv edilmiş SIP hesabları"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Bu profildən mesaj göndərmək mümkün deyil"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"İş siyasətiniz yalnız iş profilindən mesaj göndərməyə icazə verir"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Ləğv edin"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"İş profilinə keçin"</string>
 </resources>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 0f72816..7d900e4 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Bluetooth signal je slab. Probajte da pređete na spikerfon."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Obaveštenje o kvalitetu poziva"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Zastareli SIP nalozi"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Ne možete da pošaljete poruku sa ovog profila"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Smernice za posao vam omogućavaju da šaljete poruke samo sa poslovnog profila"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Otkaži"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Pređi na poslovni profil"</string>
 </resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index c3f1678..a2353ad 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Сігнал Bluetooth слабы. Паспрабуйце пераключыцца на гучную сувязь."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Апавяшчэнне пра якасць выкліку"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Састарэлыя ўліковыя запісы SIP"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Адпраўляць паведамленні з гэтага профілю нельга"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Згодна з палітыкай вашай арганізацыі адпраўляць паведамленні дазваляецца толькі з працоўнага профілю"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Скасаваць"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Пераключыцца на працоўны профіль"</string>
 </resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 168d749..0e989f2 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Сигналът ви за Bluetooth е слаб. Опитайте да превключите на високоговорител."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Известия за качеството на обаждането"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Оттеглени профили за SIP"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Съобщението не може да се изпрати от този потребителски профил"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Служебните ви правила позволяват да изпращате съобщения само от служебния потребителски профил"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Отказ"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Превключване към служебния потребителски профил"</string>
 </resources>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 93685f0..a5e5757 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"আপনার ডিভাইসের ব্লুটুথ সিগনাল ভাল না। বদল করে স্পিকারফোন বেছে নিন।"</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"ফোন কলের কোয়ালিটি সংক্রান্ত বিজ্ঞপ্তি"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"পুরনো SIP অ্যাকাউন্ট"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"এই প্রোফাইল থেকে মেসেজ পাঠানো যাচ্ছে না"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"কাজ সংক্রান্ত নীতি, আপনাকে শুধুমাত্র অফিস প্রোফাইল থেকে মেসেজ করার অনুমতি দেয়"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"বাতিল করুন"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"অফিস প্রোফাইলে পাল্টে নিন"</string>
 </resources>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 7f0c408..d682d7a 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Vaš Bluetooth signal je slab. Pokušajte prebaciti na zvučnik."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Obavještenje o kvalitetu poziva"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Zastarjeli SIP računi"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Slanje poruke s ovog profila nije moguće"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Vaša poslovna pravila dopuštaju vam da šaljete poruke samo s poslovnog profila"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Odustani"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Prelazak na poslovni profil"</string>
 </resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index be5be33..ec85f7e 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"El senyal del Bluetooth és feble. Fes servir l\'altaveu."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Notificació sobre la qualitat de la trucada"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Comptes SIP obsolets"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"No es pot enviar el missatge des d\'aquest perfil"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"La teva política de treball et permet enviar missatges només des del perfil de treball"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Cancel·la"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Canvia al perfil de treball"</string>
 </resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index b0cde9a..3ac8634 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Signál sítě Bluetooth je slabý. Zkuste přepnout na hlasitý odposlech."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Oznámení o kvalitě hovoru"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Zastaralé účty SIP"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Z tohoto profilu nemůžete odeslat zprávu"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Vaše pracovní zásady vám umožňují odesílat zprávy jen z pracovního profilu"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Zrušit"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Přepnout na pracovní profil"</string>
 </resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index e55fa8e..ac4d257 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Dit Bluetooth-signal er svagt. Prøv at skifte til medhør."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Notifikation om opkaldskvalitet"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Udfasede SIP-konti"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Du kan ikke sende beskeder fra denne profil"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Din arbejdspolitik giver dig mulighed for kun at sende beskeder fra arbejdsprofilen"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Annuller"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Skift til arbejdsprofil"</string>
 </resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 45875d1..9bb7b23 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Das Bluetooth-Signal ist schwach. Verwende die Freisprechfunktion."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Benachrichtigung zu Anrufqualität"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Eingestellte SIP-Konten"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Du kannst über dieses Profil keine Nachrichten senden"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Gemäß den Arbeitsrichtlinien darfst du nur über dein Arbeitsprofil Nachrichten senden"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Abbrechen"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Zum Arbeitsprofil wechseln"</string>
 </resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 8400f09..cd38afb 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Το σήμα bluetooth είναι ασθενές. Δοκιμάστε να αλλάξετε σε ανοιχτή ακρόαση."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Ειδοποίηση ποιότητας κλήσης"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Καταργημένοι λογαριασμοί SIP"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Δεν είναι δυνατή η αποστολή μηνύματος από αυτό το προφίλ"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Η πολιτική εργασίας σας επιτρέπει την αποστολή μηνυμάτων μόνο από το προφίλ εργασίας"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Ακύρωση"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Εναλλαγή σε προφίλ εργασίας"</string>
 </resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 8451cc7..dd8cb49 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Your Bluetooth signal is weak. Try switching to speakerphone."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Call quality notification"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Deprecated SIP accounts"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Can\'t send message from this profile"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Your work policy allows you to send messages only from the work profile"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Cancel"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Switch to work profile"</string>
 </resources>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 67cb90d..b8c32d9 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Your bluetooth signal is weak. Try switching to speakerphone."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Call Quality Notification"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Deprecated SIP accounts"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Can\'t send message from this profile"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Your work policy allows you to send message only from the work profile"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Cancel"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Switch to work profile"</string>
 </resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 8451cc7..dd8cb49 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Your Bluetooth signal is weak. Try switching to speakerphone."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Call quality notification"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Deprecated SIP accounts"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Can\'t send message from this profile"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Your work policy allows you to send messages only from the work profile"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Cancel"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Switch to work profile"</string>
 </resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 8451cc7..dd8cb49 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Your Bluetooth signal is weak. Try switching to speakerphone."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Call quality notification"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Deprecated SIP accounts"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Can\'t send message from this profile"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Your work policy allows you to send messages only from the work profile"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Cancel"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Switch to work profile"</string>
 </resources>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 8a26155..f8b0898 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‎‎‏‎‎‎‎‏‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‎Your bluetooth signal is weak. Try switching to speakerphone.‎‏‎‎‏‎"</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‎‎‎‎‎‎‎‏‎‏‏‎‎‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‎‎‎‏‎‎‏‏‏‏‎‎Call Quality Notification‎‏‎‎‏‎"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‎‎‏‏‎‎‎‎‎‏‎‏‏‎‏‏‏‏‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‎‏‎‏‏‎‏‎‏‎Deprecated SIP accounts‎‏‎‎‏‎"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‎‏‎‏‏‎‏‏‏‎‏‎‎‎‎‎‏‏‏‎‎‎‏‏‏‎‏‏‎‏‎‎‎‏‎‏‎‏‎‏‏‎‎‏‎Can\'t send message from this profile‎‏‎‎‏‎"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‎‏‎‎‏‎‏‎‏‎‏‏‎‏‎‎‎‏‏‏‎‏‏‏‎‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‏‎‎‎‏‎‎‎Your work policy allows you to send message only from the work profile‎‏‎‎‏‎"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‏‎‏‏‏‎‏‏‏‏‎‏‏‏‎‎‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‏‏‏‎Cancel‎‏‎‎‏‎"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‎‎‏‏‏‎‏‏‎‏‏‎‏‎‏‏‏‎‎‎‎‏‎‎‏‏‎‎‎‎‎‏‎‏‎‎‎‎‎‎‎‎‏‎‎‏‎Switch to work profile‎‏‎‎‏‎"</string>
 </resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 97f7985..82b4422 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Tu señal de Bluetooth es débil. Intenta cambiar a la bocina."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Notificación de calidad de llamada"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Cuentas SIP obsoletas"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"No se puede enviar un mensaje desde este perfil"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Tu política de trabajo te permite enviar mensajes solo desde el perfil de trabajo."</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Cancelar"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Cambiar al perfil de trabajo"</string>
 </resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index af2c4d8..d87b856 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Tu señal de Bluetooth es débil. Prueba a cambiar al altavoz."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Notificación de calidad de la llamada"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Cuentas SIP obsoletas"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"No se puede enviar el mensaje desde este perfil"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Tu política de trabajo te permite enviar mensajes solo desde el perfil de trabajo"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Cancelar"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Cambiar al perfil de trabajo"</string>
 </resources>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 84566b5..e19f66a 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Teie Bluetoothi signaal on nõrk. Lülitage valjuhääldile."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Kõnekvaliteedi märguanne"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Katkestatud toega SIP-kontod"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Te ei saa sellelt profiililt sõnumeid saata"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Teie töökoja eeskirjad lubavad teil ainult tööprofiililt sõnumeid saata"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Tühista"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Lülitu tööprofiilile"</string>
 </resources>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index b205fc8..f912f4e 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Bluetooth seinalea ahula da. Erabili telefonoko bozgorailua."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Deien kalitateari buruzko jakinarazpena"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"SIP-eko kontu zaharkituak"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Ezin duzu bidali mezurik profil honetatik"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Mezuak laneko profiletik soilik bidaltzeko baimena ematen dizute laneko gidalerroek"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Utzi"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Aldatu laneko profilera"</string>
 </resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 5d6a5ce..707a214 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -191,7 +191,7 @@
     <string name="preferred_network_mode_dialogtitle" msgid="2781447433514459696">"نوع شبکه ترجیحی"</string>
     <string name="forbidden_network" msgid="5081729819561333023">"(ممنوع است)"</string>
     <string name="choose_network_title" msgid="5335832663422653082">"انتخاب شبکه"</string>
-    <string name="network_disconnected" msgid="8844141106841160825">"قطع اتصال"</string>
+    <string name="network_disconnected" msgid="8844141106841160825">"متصل نیست"</string>
     <string name="network_connected" msgid="2760235679963580224">"متصل"</string>
     <string name="network_connecting" msgid="160901383582774987">"درحال اتصال…"</string>
     <string name="network_could_not_connect" msgid="6547460848093727998">"متصل نشد"</string>
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"سیگنال بلوتوث شما ضعیف است. از بلندگوی تلفن استفاده کنید."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"اعلان کیفیت تماس"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"‏حساب‌های SIP منسوخ‌شده"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"نمی‌توانید ازطریق این نمایه پیام ارسال کنید"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"طبق خط‌مشی کاری‌تان فقط می‌توانید ازطریق نمایه کاری پیام ارسال کنید"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"لغو کردن"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"رفتن به نمایه کاری"</string>
 </resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index a4c9836..d20b004 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Bluetooth-signaali on heikko. Kokeile vaihtaa kaiutinpuhelimeen."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Puhelun laatua koskeva ilmoitus"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Käytöstä poistetut SIP-tilit"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Viestiä ei voi lähettää tästä profiilista"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Työkäytäntö sallii sinun lähettää viestejä vain työprofiilista"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Peru"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Vaihda työprofiiliin"</string>
 </resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 0483dd6..21eab1f 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Votre signal Bluetooth est faible. Essayez de passer au haut-parleur mains libres."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Notification de qualité d\'appel"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Comptes SIP obsolètes"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Impossible d\'envoyer un message à partir de ce profil"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Votre politique de l\'entreprise vous autorise à envoyer des messages uniquement à partir de votre profil professionnel"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Annuler"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Passer au profil professionnel"</string>
 </resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index e3662ec..71b2a9a 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Votre signal Bluetooth est faible. Essayez d\'utiliser le haut-parleur."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Notification concernant la qualité de l\'appel"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Comptes SIP obsolètes"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Impossible d\'envoyer un message depuis ce profil"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Votre règle professionnelle ne vous permet d\'envoyer des messages que depuis le profil professionnel"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Annuler"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Passer au profil professionnel"</string>
 </resources>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 9890857..5d98c38 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"O teu sinal de Bluetooth é feble. Proba a cambiar ao altofalante."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Notificación sobre a calidade da chamada"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Contas SIP obsoletas"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Non se poden enviar mensaxes desde este perfil"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"A política do teu traballo só che permite enviar mensaxes desde o perfil de traballo"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Cancelar"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Cambiar ao perfil de traballo"</string>
 </resources>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index bafa321..f5e57bb 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"તમારા બ્લૂટૂથનું સિગ્નલ નબળું છે. સ્પીકરફોન પર સ્વિચ કરવાનો પ્રયાસ કરો."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"કૉલની ક્વૉલિટી માટે નોટિફિકેશન"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"ટાળવામાં આવેલા SIP એકાઉન્ટ"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"આ પ્રોફાઇલ પરથી મેસેજ મોકલી શકતા નથી"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"તમારી ઑફિસની પૉલિસી તમને માત્ર ઑફિસની પ્રોફાઇલ પરથી જ મેસેજ મોકલવાની મંજૂરી આપે છે"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"રદ કરો"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"ઑફિસની પ્રોફાઇલ પર સ્વિચ કરો"</string>
 </resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index d2be9dd..c48332a 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"आपका ब्लूटूथ सिग्नल कमज़ोर है. स्पीकरफ़ोन की सुविधा का इस्तेमाल करें."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"कॉल की क्वालिटी की सूचना"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"ऐसे SIP खाते जिनका समर्थन रोक दिया गया है"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"इस प्रोफ़ाइल से मैसेज नहीं भेजा जा सकता"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"ऑफ़िस की नीति के तहत, वर्क प्रोफ़ाइल से ही मैसेज भेजा जा सकता है"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"रद्द करें"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"वर्क प्रोफ़ाइल पर स्विच करें"</string>
 </resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index c7d0607..3055b25 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Signal Bluetootha je slab. Pokušajte se prebaciti na zvučnik."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Obavijest o kvaliteti poziva"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Obustavljeni SIP računi"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Slanje poruke s ovog profila nije moguće"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Vaša poslovna pravila dopuštaju vam da šaljete poruke samo s poslovnog profila"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Odustani"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Prelazak na poslovni profil"</string>
 </resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 872abe1..5d6d22d 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Gyenge a Bluetooth-jel. Próbáljon kihangosítóra váltani."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Értesítés a hívás minőségéről"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Elavult SIP-fiókok"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Nem lehet üzenetet küldeni ebből a profilból"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"A munkahelyi házirend csak az üzenetek munkaprofilból való küldését engedélyezi"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Mégse"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Váltás munkaprofilra"</string>
 </resources>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 26b2648..1038d8d 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Ձեր Bluetooth-ի ազդանշանը թույլ է։ Փորձեք միացնել բարձրախոսը։"</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Զանգի որակի մասին ծանուցում"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Հնացած SIP հաշիվներ"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Հնարավոր չէ հաղորդագրություն ուղարկել այս պրոֆիլից"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Ձեր աշխատանքային կանոնների համաձայն՝ դուք կարող եք հաղորդագրություն ուղարկել միայն աշխատանքային պրոֆիլից"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Չեղարկել"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Անցնել աշխատանքային պրոֆիլ"</string>
 </resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 4551592..8e9653f 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Sinyal bluetooth Anda lemah. Coba beralih ke speaker ponsel."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Notifikasi Kualitas Panggilan"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Akun SIP yang tidak digunakan lagi"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Tidak dapat mengirim pesan dari profil ini"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Kebijakan kantor mengizinkan Anda mengirim pesan hanya dari profil kerja"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Batal"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Beralih ke profil kerja"</string>
 </resources>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 0ccd715..437585a 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Bluetooth-tengingin er léleg. Prófaðu að nota hátalara í staðinn."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Tilkynning um símtalsgæði"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Úreldir SIP-reikningar"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Ekki er hægt að senda skilaboð úr þessu sniði"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Vinnureglur gera þér aðeins kleift að senda skilaboð úr vinnusniði"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Hætta við"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Skipta yfir í vinnusnið"</string>
 </resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index be494db..8189edf 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Il segnale del Bluetooth è debole. Prova a passare al vivavoce."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Notifica sulla qualità della chiamata"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Account SIP deprecati"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Impossibile inviare messaggi da questo profilo"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Le norme di lavoro ti consentono di inviare messaggi solo dal profilo di lavoro"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Annulla"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Passa a profilo di lavoro"</string>
 </resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index c8f246e..d70bf85 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"‏הקליטה של ה-Bluetooth חלשה. כדאי לעבור לדיבורית."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"התראה על איכות השיחה"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"‏חשבונות SIP שהוצאו משימוש"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"אי אפשר לשלוח הודעות מהפרופיל הזה"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"המדיניות של מקום העבודה מאפשרת לך לשלוח הודעות רק מפרופיל העבודה"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"ביטול"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"החלפה לפרופיל עבודה"</string>
 </resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 0679d84..96d564a 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -662,7 +662,7 @@
     <string name="voicemail_visual_voicemail_switch_title" msgid="6610414098912832120">"ビジュアル留守番電話"</string>
     <string name="voicemail_set_pin_dialog_title" msgid="7005128605986960003">"PIN の設定"</string>
     <string name="voicemail_change_pin_dialog_title" msgid="4633077715231764435">"PIN の変更"</string>
-    <string name="preference_category_ringtone" msgid="8787281191375434976">"サウンドとバイブレーション"</string>
+    <string name="preference_category_ringtone" msgid="8787281191375434976">"音とバイブレーション"</string>
     <string name="pstn_connection_service_label" msgid="9200102709997537069">"内蔵のSIMカード"</string>
     <string name="enable_video_calling_title" msgid="7246600931634161830">"ビデオハングアウトを有効にする"</string>
     <string name="enable_video_calling_dialog_msg" msgid="7141478720386203540">"ビデオハングアウトをONにするには、ネットワーク設定で4G LTE拡張モードを有効にする必要があります。"</string>
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Bluetooth の信号強度が十分ではありません。スピーカーフォンに切り替えてみてください。"</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"通話品質に関するお知らせ"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"サポートが終了した SIP アカウント"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"このプロファイルからはメッセージを送信できません"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"仕事用ポリシーでは、メッセージの送信を仕事用プロファイルからのみに制限できます"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"キャンセル"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"仕事用プロファイルに切り替える"</string>
 </resources>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index f5d6045..c6bcd58 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"თქვენი Bluetooth სიგნალი სუსტია. სცადეთ სპიკერფონზე გადართვა."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"შეტყობინება ზარის ხარისხის შესახებ"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"მოძველებული SIP ანგარიშები"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"ამ პროფილიდან შეტყობინებების გაგზავნა შეუძლებელია"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"თქვენი სამსახურის წესები საშუალებას გაძლევთ, შეტყობინებები გაგზავნოთ მხოლოდ სამუშაო პროფილიდან"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"გაუქმება"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"სამსახურის პროფილზე გადართვა"</string>
 </resources>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 0d13867..878f59d 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Bluetooth сигналы нашар. Спикерфонға ауысып көріңіз."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Қоңырау сапасы туралы хабарландыру"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Қолданыстан шыққан SIP аккаунттары"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Бұл профильден хабар жіберу мүмкін емес"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Жұмыс саясатыңызға сәйкес тек жұмыс профилінен хабар жіберуге болады."</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Бас тарту"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Жұмыс профиліне ауысу"</string>
 </resources>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 38177be..9fc200d 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"រលកសញ្ញាប៊្លូធូសរបស់អ្នក​មានកម្រិតខ្សោយ។ សូមសាកល្បងប្ដូរ​ទៅឧបករណ៍បំពងសំឡេងទូរសព្ទ។"</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"ការជូនដំណឹង​អំពីគុណភាព​ហៅទូរសព្ទ"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"គណនី SIP ដែលបានបញ្ឈប់"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"មិនអាច​ផ្ញើសារ​ពី​កម្រងព័ត៌មាន​នេះ​បានទេ"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"គោលការណ៍ការងារ​របស់អ្នក​អនុញ្ញាត​ឱ្យ​អ្នក​ផ្ញើសារ​បានតែពី​កម្រងព័ត៌មាន​ការងារ​ប៉ុណ្ណោះ"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"បោះបង់"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"ប្ដូរ​ទៅ​កម្រង​ព័ត៌មាន​ការងារ"</string>
 </resources>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 8b7b574..c0117f5 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"ನಿಮ್ಮ ಬ್ಲೂಟೂತ್ ಸಿಗ್ನಲ್ ದುರ್ಬಲವಾಗಿದೆ. ಸ್ಪೀಕರ್‌ಫೋನ್‌ಗೆ ಬದಲಾಯಿಸಲು ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"ಕರೆ ಗುಣಮಟ್ಟದ ಅಧಿಸೂಚನೆ"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"ತಡೆಹಿಡಿಯಲಾಗಿರುವ SIP ಖಾತೆಗಳು"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"ಈ ಪ್ರೊಫೈಲ್‌ನಿಂದ ಸಂದೇಶವನ್ನು ಕಳುಹಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"ನಿಮ್ಮ ಉದ್ಯೋಗದ ನೀತಿಯು ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್‌ನಿಂದ ಮಾತ್ರ ಸಂದೇಶವನ್ನು ಕಳುಹಿಸಲು ನಿಮಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"ರದ್ದುಮಾಡಿ"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್‌ಗೆ ಬದಲಿಸಿ"</string>
 </resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 2e64555..c80c6c3 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"블루투스 신호 강도가 약합니다. 스피커폰으로 전환해 보세요."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"통화 품질 알림"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"지원 중단된 SIP 계정"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"이 프로필에서 메시지를 보낼 수 없음"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"직장 정책을 사용하면 직장 프로필에서만 메시지를 보낼 수 있습니다."</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"취소"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"직장 프로필로 전환"</string>
 </resources>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index f3f9884..0e9f986 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Bluetooth сигналыңыз начар. Спикерфонго которулуп көрүңүз."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Чалуунун сапаты тууралуу билдирме"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Колдонуудан чыккан SIP аккаунттары"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Билдирүүлөрдү бул профилден жөнөтүүгө болбойт"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Жумуш саясатыңызга ылайык, билдирүүлөрдү жумуш профилинен гана жөнөтө аласыз"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Жокко чыгаруу"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Жумуш профилине которулуу"</string>
 </resources>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 9dbd694..4bbe66e 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"ສັນຍານ Bluetooth ຂອງທ່ານອ່ອນ. ລອງສະຫຼັບລຳໂພງໂທລະສັບ."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"ການແຈ້ງເຕືອນຄຸນນະພາບການໂທ"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"ບັນຊີ SIP ທີ່ເຊົາສະໜັບສະໜູນ"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"ບໍ່ສາມາດສົ່ງຂໍ້ຄວາມຈາກໂປຣໄຟລ໌ນີ້ໄດ້"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"ນະໂຍບາຍບ່ອນເຮັດວຽກຂອງທ່ານອະນຸຍາດໃຫ້ທ່ານສົ່ງຂໍ້ຄວາມໄດ້ຈາກໂປຣໄຟລ໌ບ່ອນເຮັດວຽກເທົ່ານັ້ນ"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"ຍົກເລີກ"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"ສະຫຼັບໄປໃຊ້ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string>
 </resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index ef02da0..9c2d2ea 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Silpnas „Bluetooth“ signalas. Pabandykite perjungti garsiakalbį."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Pranešimas apie skambučio kokybę"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Nebenaudojamos SIP paskyros"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Nepavyko išsiųsti pranešimo iš šio profilio"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Pagal jūsų darbo politiką galite siųsti pranešimus tik iš darbo profilio"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Atšaukti"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Perjungti į darbo profilį"</string>
 </resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 890dc79..a60d560 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Bluetooth signāls ir vājš. Mēģiniet pārslēgties uz skaļruni."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Paziņojums par zvana kvalitāti"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"SIP konti, kuru darbība ir pārtraukta"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Nevar nosūtīt ziņojumu no šī profila"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Saskaņā ar darbavietas politiku drīkstat sūtīt ziņojumus tikai no darba profila."</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Atcelt"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Pārslēgties uz darba profilu"</string>
 </resources>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 70a9d6e..487d996 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Вашиот сигнал на Bluetooth е слаб. Обидете се со префрлање на интерфон."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Известување за квалитет на повик"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Неподдржани сметки на SIP"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Не може да се испрати порака од профилов"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Вашето работно правило ви дозволува да испраќате пораки само од работниот профил"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Откажи"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Префрли на работен профил"</string>
 </resources>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 3d01a16..2de21b3 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"നിങ്ങളുടെ Bluetooth സിഗ്നൽ ദുർബലമാണ്. സ്‌പീക്കർഫോണിലേക്ക് മാറ്റി നോക്കൂ."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"കോൾ നിലവാര അറിയിപ്പ്"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"അവസാനിപ്പിച്ച SIP അക്കൗണ്ടുകൾ"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"ഈ പ്രൊഫൈലിൽ നിന്ന് സന്ദേശം അയയ്ക്കാനാകില്ല"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"ഔദ്യോഗിക പ്രൊഫൈലിൽ നിന്ന് മാത്രം സന്ദേശം അയയ്ക്കാനാണ് നിങ്ങളുടെ ഔദ്യോഗിക നയം അനുവദിക്കുന്നത്"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"റദ്ദാക്കുക"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"ഔദ്യോഗിക പ്രൊഫൈലിലേക്ക് മാറുക"</string>
 </resources>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index bdf8df1..81d5a12 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Таны Bluetooth-н дохио сул байна. Чанга яригчтай утас руу сэлгэж үзнэ үү."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Дуудлагын чанарын мэдэгдэл"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"SIP-н зогсоосон бүртгэлүүд"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Энэ профайлаас мессеж илгээх боломжгүй"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Таны ажлын бодлого танд зөвхөн ажлын профайлаас мессеж илгээхийг зөвшөөрдөг"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Цуцлах"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Ажлын профайл руу сэлгэх"</string>
 </resources>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 719297a..800020e 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"तुमचा ब्लूटूथ सिग्नल कमकुवत आहे. स्पीकरफोनवर स्विच करून पहा."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"कॉल गुणवत्ता सूचना"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"कालबाह्य झालेली SIP खाती"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"या प्रोफाइलवरून मेसेज पाठवू शकत नाही"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"तुमचे कामाशी संबंधित धोरण हे तुम्हाला फक्त तुमच्या कार्य प्रोफाइलवरून मेसेज पाठवण्याची अनुमती देते"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"रद्द करा"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"कार्य प्रोफाइलवर स्विच करा"</string>
 </resources>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 2240b6f..75e93a6 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Isyarat bluetooth anda lemah. Cuba beralih kepada fon pembesar suara."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Pemberitahuan Kualiti Panggilan"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Akaun SIP ditamatkan"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Tidak dapat menghantar mesej daripada profil ini"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Dasar kerja anda membenarkan anda menghantar mesej hanya daripada profil kerja"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Batal"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Beralih kepada profil kerja"</string>
 </resources>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 6114e94..7f45ddc 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"သင်၏ ဘလူးတုသ်လိုင်းဆွဲအား မကောင်းပါ။ စပီကာဖုန်းသို့ ပြောင်းကြည့်ပါ။"</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"ခေါ်ဆိုမှုအရည်အသွေး အကြောင်းကြားချက်"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"ရပ်ဆိုင်းထားသော SIP အကောင့်များ"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"ဤပရိုဖိုင်မှ မက်ဆေ့ဂျ်ပို့၍ မရပါ"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"သင့်အလုပ်ခွင်မူဝါဒသည် အလုပ်ပရိုဖိုင်မှသာ မက်ဆေ့ဂျ်ပို့ခွင့်ပြုသည်"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"မလုပ်တော့"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"အလုပ်ပရိုဖိုင်သို့ ပြောင်းရန်"</string>
 </resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 2957043..d60ed3b 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Bluetooth-signalet er svakt. Prøv å bytte til høyttaleren."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Varsel om anropskvalitet"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Avviklede SIP-kontoer"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Kan ikke sende meldingen fra denne profilen"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"I henhold til jobbreglene dine kan du bare sende meldinger fra jobbprofilen"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Avbryt"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Bytt til jobbprofilen"</string>
 </resources>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index f21bb2a..0e3e439 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"ब्लुटुथको सिग्नल कमजोर छ। स्पिकरफोन प्रयोग गरी हेर्नुहोस्।"</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"कलको गुणस्तरसम्बन्धी सूचना"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"चल्तीबाट हटाइएका SIP खाताहरू"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"यो प्रोफाइलबाट म्यासेज पठाउन सकिँदैन"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"तपाईंको कामसम्बन्धी नीतिअनुसार कार्य प्रोफाइलबाट मात्र म्यासेज पठाउन सकिन्छ"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"रद्द गर्नुहोस्"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"कार्य प्रोफाइल प्रयोग गर्नुहोस्"</string>
 </resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 3820e52..bece75e 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -921,4 +921,12 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Het bluetooth-signaal is zwak. Schakel over naar bellen op luidspreker."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Melding over gesprekskwaliteit"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Beëindigde SIP-accounts"</string>
+    <!-- no translation found for send_from_work_profile_title (9201528838448432473) -->
+    <skip />
+    <!-- no translation found for send_from_work_profile_description (5002701841936861636) -->
+    <skip />
+    <!-- no translation found for send_from_work_profile_cancel (177746511030381711) -->
+    <skip />
+    <!-- no translation found for send_from_work_profile_action_str (6892775562934243337) -->
+    <skip />
 </resources>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 5db4c61..4dfd1b0 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"ଆପଣଙ୍କ ବ୍ଲୁଟୁଥ୍ ସିଗନାଲ୍ ଦୁର୍ବଳ ଅଛି। ସ୍ପିକରଫୋନକୁ ସ୍ୱିଚ୍ କରିବା ପାଇଁ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"କଲ୍ ଗୁଣବତ୍ତା ବିଜ୍ଞପ୍ତି"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"ଅସମର୍ଥିତ SIP ଆକାଉଣ୍ଟଗୁଡ଼ିକ"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"ଏହି ପ୍ରୋଫାଇଲରୁ ମେସେଜ ପଠାଯାଇପାରିବ ନାହିଁ"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"ଆପଣଙ୍କ ୱାର୍କ ନୀତି ଆପଣଙ୍କୁ କେବଳ ୱାର୍କ ପ୍ରୋଫାଇଲରୁ ମେସେଜ ପଠାଇବାକୁ ଅନୁମତି ଦିଏ"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"ବାତିଲ କରନ୍ତୁ"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"ୱାର୍କ ପ୍ରୋଫାଇଲକୁ ସ୍ୱିଚ କରନ୍ତୁ"</string>
 </resources>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 8a44ab8..1e35145 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"ਤੁਹਾਡਾ ਬਲੂਟੁੱਥ ਸਿਗਨਲ ਕਮਜ਼ੋਰ ਹੈ। ਸਪੀਕਰਫ਼ੋਨ \'ਤੇ ਲਿਜਾ ਕੇ ਦੇਖੋ।"</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"ਕਾਲ ਦੀ ਕੁਆਲਿਟੀ ਸੰਬੰਧੀ ਸੂਚਨਾ"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"ਨਾਪਸੰਦ ਕੀਤੇ SIP ਖਾਤੇ"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"ਇਸ ਪ੍ਰੋਫਾਈਲ ਤੋਂ ਸੁਨੇਹਾ ਨਹੀਂ ਭੇਜਿਆ ਜਾ ਸਕਦਾ"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"ਤੁਹਾਡੀ ਕਾਰਜ ਨੀਤੀ ਤੁਹਾਨੂੰ ਸਿਰਫ਼ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਤੋਂ ਹੀ ਸੁਨੇਹਾ ਭੇਜਣ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"ਰੱਦ ਕਰੋ"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ \'ਤੇ ਜਾਓ"</string>
 </resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index cd9e7a6..9569634 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Twój sygnał Bluetooth jest słaby. Spróbuj przełączyć na głośnik."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Powiadomienie o jakości połączenia"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Wycofane konta SIP"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Nie możesz wysłać wiadomości z tego profilu"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Zasady obowiązujące w firmie zezwalają na wysyłanie wiadomości tylko z profilu służbowego"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Anuluj"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Przełącz na profil służbowy"</string>
 </resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 4e19fc0..f65c8b7 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"O seu sinal Bluetooth é fraco. Tente mudar para o altifalante."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Notificação de qualidade da chamada"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Contas SIP descontinuadas"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Não é possível enviar mensagens a partir deste perfil"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"A sua Política de Trabalho permite-lhe enviar mensagens apenas a partir do perfil de trabalho"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Cancelar"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Mudar para perfil de trabalho"</string>
 </resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 38109a8..a72babd 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"O sinal do Bluetooth está fraco. Mude para o viva-voz."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Notificação sobre a qualidade da chamada"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Contas SIP suspensas"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Não é possível enviar mensagens deste perfil"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Sua política de trabalho só permite o envio de mensagens pelo perfil de trabalho"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Cancelar"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Mudar para o perfil de trabalho"</string>
 </resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index df11b3f..2260b62 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Semnalul Bluetooth este slab. Încearcă să folosești difuzorul."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Notificare privind calitatea apelului"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Conturi SIP învechite"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Nu se poate trimite un mesaj de pe acest profil"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Politica privind activitatea îți permite să trimiți mesaje numai din profilul de serviciu"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Anulează"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Comută la profilul de serviciu"</string>
 </resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 88059d8..3fd7d03 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Слабый сигнал Bluetooth. Попробуйте переключиться на громкую связь."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Уведомление о качестве связи"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Неподдерживаемые SIP-аккаунты"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Нельзя отправить сообщение из этого профиля"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Согласно правилам вашей организации вы можете отправлять сообщения только из рабочего профиля."</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Отмена"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Перейти в рабочий профиль"</string>
 </resources>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index f04a45f..735a538 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"ඔබේ බ්ලූටූත් සංඥාව දුර්වලයි. ස්පීකර් දුරකථනයට මාරු වීමට උත්සාහ කරන්න."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"ඇමතුම් ගුණත්ව දැනුම්දීම"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"අතහැර දැමූ SIP ගිණුම්"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"මෙම පැතිකඩෙන් පණිවිඩ යැවිය නොහැක"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"ඔබේ වැඩ ප්‍රතිපත්තිය ඔබට කාර්යාල පැතිකඩෙන් පමණක් පණිවිඩ යැවීමට ඉඩ දෙයි"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"අවලංගු කරන්න"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"කාර්යාල පැතිකඩ වෙත මාරු වන්න"</string>
 </resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index faf16d4..68a873f 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Signál Bluetooth je slabý. Skúste prepnúť na reproduktor."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Upozornenie o kvalite hovoru"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Účty SIP s ukončenou podporou"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Z tohto profilu nemôžete odosielať správy"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Pracovné pravidlá vám umožňujú odosielať správy iba v pracovnom profile"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Zrušiť"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Prepnúť na pracovný profil"</string>
 </resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 71e47d8..2fdbf8e 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Signal povezave Bluetooth je šibek. Poskusite preklopiti na zvočnik."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Obvestilo o kakovosti klica"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Opuščeni računi SIP"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Sporočila ni mogoče poslati iz tega profila"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Službeni pravilnik dovoljuje pošiljanje sporočil le iz delovnega profila."</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Prekliči"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Preklopi na delovni profil"</string>
 </resources>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index ce593ed..7b3be3a 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Sinjali i Bluetooth-it është i dobët. Provo të kalosh te altoparlanti."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Njoftim për cilësinë e telefonatës"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Llogaritë e zhvlerësuara SIP"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Mesazhi nuk mund të dërgohet nga ky profil"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Politika jote e punës të lejon të dërgosh mesazhe vetëm nga profili i punës"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Anulo"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Kalo te profili i punës"</string>
 </resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 34892f3..e8376b6 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Bluetooth сигнал је слаб. Пробајте да пређете на спикерфон."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Обавештење о квалитету позива"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Застарели SIP налози"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Не можете да пошаљете поруку са овог профила"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Смернице за посао вам омогућавају да шаљете поруке само са пословног профила"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Откажи"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Пређи на пословни профил"</string>
 </resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index cf5ba2a..a3c6e2c 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Svag Bluetooth-signal. Försök med att växla till högtalartelefon."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Avisering om samtalskvalitet"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Utfasade SIP-konton"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Det går inte att skicka meddelanden från den här profilen"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Jobbprincipen tillåter endast att skicka meddelanden från jobbprofilen"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Avbryt"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Byt till jobbprofilen"</string>
 </resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 285f910..f276570 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Muunganisho wako wa bluetooth ni dhaifu. Jaribu kubadilisha ili utumie spika ya simu."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Arifa ya Ubora wa Simu"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Akaunti za SIP ambazo zimefungwa"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Huwezi kutuma ujumbe kutoka kwenye wasifu huu"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Sera ya mahali pako pa kazi inakuruhusu utume ujumbe kutoka kwenye wasifu wa kazini pekee"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Ghairi"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Tumia wasifu wa kazini"</string>
 </resources>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 4919c99..b1e7e29 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"புளூடூத் சிக்னல் வலுவற்றதாக உள்ளது. ஸ்பீக்கர் ஃபோனிற்கு மாற்றவும்."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"அழைப்பின் தரம் தொடர்பான அறிவிப்பு"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"நிறுத்தப்பட்ட SIP கணக்குகள்"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"இந்தச் சுயவிவரத்தில் இருந்து மெசேஜ் அனுப்ப முடியாது"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"உங்கள் பணிக் கொள்கையின்படி நீங்கள் பணிக் கணக்கில் இருந்து மட்டுமே மெசேஜ் அனுப்ப முடியும்"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"ரத்துசெய்"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"பணிக் கணக்கிற்கு மாறு"</string>
 </resources>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 80e077a..20589c1 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"మీ బ్లూటూత్ సిగ్నల్ బలహీనంగా ఉంది. స్పీకర్‌ఫోన్‌కు స్విచ్ అవ్వడానికి ట్రై చేయండి."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"కాల్ క్వాలిటీ నోటిఫికేషన్"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"తీసివేయబడిన SIP ఖాతాలు"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"ఈ ప్రొఫైల్ నుండి మెసేజ్ పంపడం సాధ్యపడలేదు"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"మీ వర్క్ పాలసీ మిమ్మల్ని వర్క్ ప్రొఫైల్ నుండి మాత్రమే మెసేజ్ పంపడానికి అనుమతిస్తుంది"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"రద్దు చేయండి"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"వర్క్ ప్రొఫైల్‌కు స్విచ్ అవ్వండి"</string>
 </resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 0f990bf..176dea6 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -559,7 +559,7 @@
     <string name="emergency_information_hint" msgid="9208897544917793012">"ข้อมูลสำหรับกรณีฉุกเฉิน"</string>
     <string name="emergency_information_owner_hint" msgid="6256909888049185316">"เจ้าของ"</string>
     <string name="emergency_information_confirm_hint" msgid="5109017615894918914">"แตะอีกครั้งเพื่อดูข้อมูล"</string>
-    <string name="emergency_enable_radio_dialog_title" msgid="2667568200755388829">"หมายเลขฉุกเฉิน"</string>
+    <string name="emergency_enable_radio_dialog_title" msgid="2667568200755388829">"โทรฉุกเฉิน"</string>
     <string name="single_emergency_number_title" msgid="8413371079579067196">"หมายเลขฉุกเฉิน"</string>
     <string name="numerous_emergency_numbers_title" msgid="8972398932506755510">"หมายเลขฉุกเฉิน"</string>
     <string name="emergency_call_shortcut_hint" msgid="1290485125107779500">"แตะอีกครั้งเพื่อโทรหา <xliff:g id="EMERGENCY_NUMBER">%s</xliff:g>"</string>
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"สัญญาณบลูทูธอ่อน ลองเปลี่ยนไปใช้ลำโพงแทน"</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"การแจ้งเตือนคุณภาพการโทร"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"บัญชี SIP ที่เลิกใช้งาน"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"ส่งข้อความจากโปรไฟล์นี้ไม่ได้"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"นโยบายการทำงานอนุญาตให้คุณส่งข้อความได้จากโปรไฟล์งานเท่านั้น"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"ยกเลิก"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"สลับไปใช้โปรไฟล์งาน"</string>
 </resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index eae12df..433d247 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Mahina ang signal ng iyong bluetooth. Subukang lumipat sa speakerphone."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Notification sa Kalidad ng Tawag"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Mga hindi na ginagamit na SIP account"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Hindi makakapagpadala ng mensahe mula sa profile na ito"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Pinapayagan ka ng iyong patakaran sa trabaho na magpadala ng mensahe mula lang sa profile sa trabaho"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Kanselahin"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Lumipat sa profile sa trabaho"</string>
 </resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 1afe088..db8e1ca 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Bluetooth sinyaliniz zayıf. Hoparlöre geçmeyi deneyin."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Arama Kalitesiyle İlgili Bildirim"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Kullanımdan kaldırılan SIP hesapları"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Bu profilden mesaj gönderilemiyor"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"İşletme politikanız yalnızca iş profilinden mesaj göndermenize izin veriyor"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"İptal"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"İş profiline geç"</string>
 </resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index c2626c7..c9f26c8 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Сигнал Bluetooth заслабкий. Спробуйте переключитися на гучний зв\'язок."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Сповіщення про якість виклику"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Облікові записи SIP, що не підтримуються"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Надіслати повідомлення з цього профілю не можна"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Відповідно до правил організації ви можете надсилати повідомлення лише з робочого профілю"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Скасувати"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Перейти в робочий профіль"</string>
 </resources>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 0250039..9ed0675 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"آپ کا بلوٹوتھ سگنل کمزور ہے۔ اسپیکر فون پر سوئچ کر کے آزمائیں۔"</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"کال کی کوالٹی کی اطلاع"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"‏فرسودہ SIP اکاؤنٹس"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"اس پروفائل سے پیغام نہیں بھیج سکتے"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"آپ کے کام سے متعلق پالیسی آپ کو صرف دفتری پروفائل سے پیغام بھیجنے کی اجازت دیتی ہے"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"منسوخ کریں"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"دفتری پروفائل پر سوئچ کریں"</string>
 </resources>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 1577a55..e9de41e 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Bluetooth signali kuchsiz. Baland ovoz rejimini yoqish tavsiya etiladi."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Chaqiruv sifati haqida bildirishnoma"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"To‘xtatilgan SIP hisoblar"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Bu profildan xabar yuborish imkonsiz"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Ishga oid siyosatingiz faqat ish profilidan xabar yuborish imkonini beradi"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Bekor qilish"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Ish profiliga almashish"</string>
 </resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index caafd7a..d573c69 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Tín hiệu Bluetooth của bạn đang yếu. Hãy thử chuyển sang loa ngoài."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Thông báo về chất lượng cuộc gọi"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Tài khoản SIP không dùng nữa"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Không gửi được tin nhắn từ hồ sơ này"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Chính sách của nơi làm việc chỉ cho phép bạn gửi tin nhắn từ hồ sơ công việc"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Huỷ"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Chuyển sang hồ sơ công việc"</string>
 </resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 58d0344..456fef4 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"您的蓝牙信号较弱。请尝试切换为扬声器模式。"</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"通话质量通知"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"已弃用的 SIP 帐号"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"无法通过此资料发送消息"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"根据您的工作政策,您只能通过工作资料发送消息"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"取消"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"切换到工作资料"</string>
 </resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 208d7d3..b0e8797 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"您的藍牙訊號微弱。請改用擴音器。"</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"通話品質通知"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"已停用的 SIP 帳戶"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"無法從此個人檔案傳送訊息"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"您的工作政策只允許透過工作設定檔傳送訊息"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"取消"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"切換至工作設定檔"</string>
 </resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 7bcd733..3789f8a 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"你的藍牙訊號微弱,建議你改用擴音模式。"</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"通話品質通知"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"不適用的 SIP 帳戶"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"無法透過這個資料夾傳送訊息"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"貴公司政策僅允許透過工作資料夾傳送訊息"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"取消"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"切換至工作資料夾"</string>
 </resources>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 1fb675f..8838b04 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -921,4 +921,8 @@
     <string name="call_quality_notification_bluetooth_details" msgid="8348950331707346711">"Isignali yakho ye-bluetooth ayiqinile. Zama ukushintshela kusipikhasefoni."</string>
     <string name="call_quality_notification_name" msgid="3476828289553948830">"Isaziso Sekhwalithi"</string>
     <string name="notification_channel_sip_account" msgid="1261816025156179637">"Ama-akhawunti we-SIP ehlisiwe"</string>
+    <string name="send_from_work_profile_title" msgid="9201528838448432473">"Ayikwazi ukuthumela umyalezo kusukela kule phrofayela"</string>
+    <string name="send_from_work_profile_description" msgid="5002701841936861636">"Inqubomgomo yakho yomsebenzi ikuvumela ukuthi uthumele umyalezo kuphela usuka kuphrofayela yomsebenzi"</string>
+    <string name="send_from_work_profile_cancel" msgid="177746511030381711">"Khansela"</string>
+    <string name="send_from_work_profile_action_str" msgid="6892775562934243337">"Shintshela kuphrofayela yomsebenzi"</string>
 </resources>
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 5ba148d..9d11dfc 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -62,6 +62,7 @@
 import com.android.internal.telephony.ICarrierConfigLoader;
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneConfigurationManager;
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.SubscriptionInfoUpdater;
 import com.android.internal.telephony.TelephonyPermissions;
@@ -128,7 +129,7 @@
 
     // SubscriptionInfoUpdater
     @NonNull private final SubscriptionInfoUpdater mSubscriptionInfoUpdater;
-    // Broadcast receiver for system events (BootCompleted, MultiSimConfigChanged etc.)
+    // Broadcast receiver for system events
     @NonNull
     private final BroadcastReceiver mSystemBroadcastReceiver = new ConfigLoaderBroadcastReceiver();
     @NonNull private final LocalLog mCarrierConfigLoadingLog = new LocalLog(100);
@@ -706,7 +707,6 @@
 
         IntentFilter systemEventsFilter = new IntentFilter();
         systemEventsFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
-        systemEventsFilter.addAction(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED);
         context.registerReceiver(mSystemBroadcastReceiver, systemEventsFilter);
 
         mNumPhones = TelephonyManager.from(context).getActiveModemCount();
@@ -729,6 +729,10 @@
         }
         logd("CarrierConfigLoader has started");
         mSubscriptionInfoUpdater = subscriptionInfoUpdater;
+
+        PhoneConfigurationManager.registerForMultiSimConfigChange(
+                mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED, null);
+
         mHandler.sendEmptyMessage(EVENT_CHECK_SYSTEM_UPDATE);
     }
 
@@ -763,6 +767,11 @@
             }
         }
 
+        if (mConfigFromDefaultApp.length <= phoneId) {
+            Log.wtf(LOG_TAG, "Invalid phone id " + phoneId);
+            return;
+        }
+
         mConfigFromDefaultApp[phoneId] = null;
         mConfigFromCarrierApp[phoneId] = null;
         mServiceConnection[phoneId] = null;
@@ -1824,10 +1833,6 @@
                 case Intent.ACTION_BOOT_COMPLETED:
                     mHandler.sendMessage(mHandler.obtainMessage(EVENT_SYSTEM_UNLOCKED, null));
                     break;
-
-                case TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED:
-                    mHandler.sendEmptyMessage(EVENT_MULTI_SIM_CONFIG_CHANGED);
-                    break;
             }
         }
     }
diff --git a/src/com/android/phone/ImsProvisioningController.java b/src/com/android/phone/ImsProvisioningController.java
index 6a6b155..a62980e 100644
--- a/src/com/android/phone/ImsProvisioningController.java
+++ b/src/com/android/phone/ImsProvisioningController.java
@@ -1564,13 +1564,7 @@
     }
 
     protected int getSubId(int slotId) {
-        final int[] subIds = mSubscriptionManager.getSubscriptionIds(slotId);
-        int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-        if (subIds != null && subIds.length >= 1) {
-            subId = subIds[0];
-        }
-
-        return subId;
+        return SubscriptionManager.getSubscriptionId(slotId);
     }
 
     protected int getSlotId(int subId) {
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 200dc75..7a61dd1 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -74,6 +74,7 @@
 import com.android.internal.telephony.ims.ImsResolver;
 import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
+import com.android.internal.telephony.satellite.SatelliteController;
 import com.android.internal.telephony.uicc.UiccPort;
 import com.android.internal.telephony.uicc.UiccProfile;
 import com.android.internal.util.IndentingPrintWriter;
@@ -510,6 +511,10 @@
             // status bar icons and control other status bar behavior.
             notificationMgr = NotificationMgr.init(this);
 
+            // Create the SatelliteController singleton, which acts as a backend service for
+            // {@link android.telephony.satellite.SatelliteManager}.
+            SatelliteController.make(this);
+
             // Create an instance of CdmaPhoneCallState and initialize it to IDLE
             cdmaPhoneCallState = new CdmaPhoneCallState();
             cdmaPhoneCallState.CdmaPhoneCallStateInit();
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index e90f37c..b541c17 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -53,6 +53,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.ICancellationSignal;
 import android.os.LocaleList;
 import android.os.Looper;
 import android.os.Message;
@@ -143,9 +144,15 @@
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.stub.ImsConfigImplBase;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.telephony.satellite.ISatelliteDatagramCallback;
 import android.telephony.satellite.ISatellitePositionUpdateCallback;
-import android.telephony.satellite.PointingInfo;
+import android.telephony.satellite.ISatelliteProvisionStateCallback;
+import android.telephony.satellite.ISatelliteStateCallback;
+import android.telephony.satellite.SatelliteCapabilities;
+import android.telephony.satellite.SatelliteDatagram;
+import android.telephony.satellite.SatelliteDatagramCallback;
 import android.telephony.satellite.SatelliteManager;
+import android.telephony.satellite.SatelliteProvisionStateCallback;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.EventLog;
@@ -172,6 +179,7 @@
 import com.android.internal.telephony.ICallForwardingInfoCallback;
 import com.android.internal.telephony.IImsStateCallback;
 import com.android.internal.telephony.IIntegerConsumer;
+import com.android.internal.telephony.ILongConsumer;
 import com.android.internal.telephony.INumberVerificationCallback;
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.IccCard;
@@ -188,7 +196,6 @@
 import com.android.internal.telephony.ProxyController;
 import com.android.internal.telephony.RIL;
 import com.android.internal.telephony.RILConstants;
-import com.android.internal.telephony.RILUtils;
 import com.android.internal.telephony.RadioInterfaceCapabilityController;
 import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.SmsApplication;
@@ -206,6 +213,7 @@
 import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
 import com.android.internal.telephony.metrics.RcsStats;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
+import com.android.internal.telephony.satellite.SatelliteController;
 import com.android.internal.telephony.subscription.SubscriptionInfoInternal;
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
@@ -255,7 +263,6 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executors;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Consumer;
@@ -381,12 +388,7 @@
     private static final int EVENT_IS_VONR_ENABLED_DONE = 116;
     private static final int CMD_PURCHASE_PREMIUM_CAPABILITY = 117;
     private static final int EVENT_PURCHASE_PREMIUM_CAPABILITY_DONE = 118;
-    private static final int CMD_START_SATELLITE_POSITION_UPDATES = 119;
-    private static final int EVENT_START_SATELLITE_POSITION_UPDATES_DONE = 120;
-    private static final int CMD_STOP_SATELLITE_POSITION_UPDATES = 121;
-    private static final int EVENT_STOP_SATELLITE_POSITION_UPDATES_DONE = 122;
-    private static final int CMD_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG = 123;
-    private static final int EVENT_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG_DONE = 124;
+
     // Parameters of select command.
     private static final int SELECT_COMMAND = 0xA4;
     private static final int SELECT_P1 = 0x04;
@@ -400,25 +402,24 @@
     private static PhoneInterfaceManager sInstance;
     private static List<String> sThermalMitigationAllowlistedPackages = new ArrayList<>();
 
-    private PhoneGlobals mApp;
-    private CallManager mCM;
-    private ImsResolver mImsResolver;
-    private UserManager mUserManager;
-    private AppOpsManager mAppOps;
-    private PackageManager mPm;
-    private MainThreadHandler mMainThreadHandler;
+    private final PhoneGlobals mApp;
+    private final CallManager mCM;
+    private final ImsResolver mImsResolver;
+
+    private final SatelliteController mSatelliteController;
+    private final UserManager mUserManager;
+    private final AppOpsManager mAppOps;
+    private final MainThreadHandler mMainThreadHandler;
     private final SubscriptionController mSubscriptionController;
-    private SharedPreferences mTelephonySharedPreferences;
-    private PhoneConfigurationManager mPhoneConfigurationManager;
+    private final SharedPreferences mTelephonySharedPreferences;
+    private final PhoneConfigurationManager mPhoneConfigurationManager;
     private final RadioInterfaceCapabilityController mRadioInterfaceCapabilities;
 
     /** User Activity */
-    private AtomicBoolean mNotifyUserActivity;
+    private final AtomicBoolean mNotifyUserActivity;
     private static final int USER_ACTIVITY_NOTIFICATION_DELAY = 200;
 
-    private Set<Integer> mCarrierPrivilegeTestOverrideSubIds = new ArraySet<>();
-    private Map<Integer, SatellitePositionUpdateHandler> mSatellitePositionUpdateHandlers =
-            new ConcurrentHashMap<>();
+    private final Set<Integer> mCarrierPrivilegeTestOverrideSubIds = new ArraySet<>();
 
     private static final String PREF_CARRIERS_ALPHATAG_PREFIX = "carrier_alphtag_";
     private static final String PREF_CARRIERS_NUMBER_PREFIX = "carrier_number_";
@@ -514,46 +515,6 @@
         }
     }
 
-    private static final class SatellitePositionUpdateHandler extends Handler {
-        public static final int EVENT_POSITION_UPDATE = 1;
-        public static final int EVENT_MESSAGE_TRANSFER_STATE_UPDATE = 2;
-
-        private final ISatellitePositionUpdateCallback mCallback;
-
-        SatellitePositionUpdateHandler(ISatellitePositionUpdateCallback callback, Looper looper) {
-            super(looper);
-            mCallback = callback;
-        }
-
-        @Override
-        public void handleMessage(@NonNull Message msg) {
-            switch (msg.what) {
-                case EVENT_POSITION_UPDATE: {
-                    AsyncResult ar = (AsyncResult) msg.obj;
-                    PointingInfo pointingInfo = (PointingInfo) ar.result;
-                    try {
-                        mCallback.onSatellitePositionUpdate(pointingInfo);
-                    } catch (RemoteException e) {
-                        loge("EVENT_POSITION_UPDATE RemoteException: " + e);
-                    }
-                    break;
-                }
-                case EVENT_MESSAGE_TRANSFER_STATE_UPDATE: {
-                    AsyncResult ar = (AsyncResult) msg.obj;
-                    int state = (int) ar.result;
-                    try {
-                        mCallback.onMessageTransferStateUpdate(state);
-                    } catch (RemoteException e) {
-                        loge("EVENT_MESSAGE_TRANSFER_STATE_UPDATE RemoteException: " + e);
-                    }
-                    break;
-                }
-                default:
-                    loge("SatellitePositionUpdateHandler unknown event: " + msg.what);
-            }
-        }
-    }
-
     /**
      * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
      * request after sending. The main thread will notify the request when it is complete.
@@ -879,7 +840,7 @@
                     if (uiccPort == null) {
                         loge("iccCloseLogicalChannel: No UICC");
                         request.result = new IllegalArgumentException(
-                                    "iccCloseLogicalChannel: No UICC");
+                                "iccCloseLogicalChannel: No UICC");
                         notifyRequester(request);
                     } else {
                         onCompleted = obtainMessage(EVENT_CLOSE_CHANNEL_DONE, request);
@@ -1447,7 +1408,7 @@
                         int errorCode = CellNetworkScanResult.STATUS_UNKNOWN_ERROR;
                         if (ar.exception instanceof CommandException) {
                             CommandException.Error error =
-                                ((CommandException) (ar.exception)).getCommandError();
+                                    ((CommandException) (ar.exception)).getCommandError();
                             if (error == CommandException.Error.RADIO_NOT_AVAILABLE) {
                                 errorCode = CellNetworkScanResult.STATUS_RADIO_NOT_AVAILABLE;
                             } else if (error == CommandException.Error.GENERIC_FAILURE) {
@@ -1561,13 +1522,14 @@
                     break;
                 }
 
-                case CMD_SET_ALLOWED_CARRIERS:
+                case CMD_SET_ALLOWED_CARRIERS: {
                     request = (MainThreadRequest) msg.obj;
                     CarrierRestrictionRules argument =
                             (CarrierRestrictionRules) request.argument;
                     onCompleted = obtainMessage(EVENT_SET_ALLOWED_CARRIERS_DONE, request);
                     defaultPhone.setAllowedCarriers(argument, onCompleted, request.workSource);
                     break;
+                }
 
                 case EVENT_SET_ALLOWED_CARRIERS_DONE:
                     ar = (AsyncResult) msg.obj;
@@ -1604,7 +1566,7 @@
                         request.result = ar.result;
                     } else {
                         request.result = new IllegalStateException(
-                            "Failed to get carrier restrictions");
+                                "Failed to get carrier restrictions");
                         if (ar.result == null) {
                             loge("getAllowedCarriers: Empty response");
                         } else if (ar.exception instanceof CommandException) {
@@ -1635,8 +1597,8 @@
                             lockStatus = carrierRestrictionRules.getCarrierRestrictionStatus();
                             if (carrierId != -1 && callerCarrierId == carrierId && lockStatus
                                     == TelephonyManager.CARRIER_RESTRICTION_STATUS_RESTRICTED) {
-                                lockStatus =
-                                 TelephonyManager.CARRIER_RESTRICTION_STATUS_RESTRICTED_TO_CALLER;
+                                lockStatus = TelephonyManager
+                                        .CARRIER_RESTRICTION_STATUS_RESTRICTED_TO_CALLER;
                             }
                         } else {
                             Rlog.e(LOG_TAG,
@@ -1690,7 +1652,7 @@
                     }
                     onCompleted = obtainMessage(EVENT_GET_FORBIDDEN_PLMNS_DONE, request);
                     ((SIMRecords) uiccApp.getIccRecords()).getForbiddenPlmns(
-                              onCompleted);
+                            onCompleted);
                     break;
 
                 case CMD_SWITCH_SLOTS:
@@ -1855,7 +1817,7 @@
                 case EVENT_CMD_MODEM_REBOOT_DONE:
                     handleNullReturnEvent(msg, "rebootModem");
                     break;
-                case CMD_REQUEST_ENABLE_MODEM:
+                case CMD_REQUEST_ENABLE_MODEM: {
                     request = (MainThreadRequest) msg.obj;
                     boolean enable = (boolean) request.argument;
                     onCompleted = obtainMessage(EVENT_ENABLE_MODEM_DONE, request);
@@ -1863,6 +1825,7 @@
                     PhoneConfigurationManager.getInstance()
                             .enablePhone(request.phone, enable, onCompleted);
                     break;
+                }
                 case EVENT_ENABLE_MODEM_DONE: {
                     ar = (AsyncResult) msg.obj;
                     request = (MainThreadRequest) ar.userObj;
@@ -2104,7 +2067,7 @@
 
                         if (error == CommandException.Error.RADIO_NOT_AVAILABLE) {
                             request.result = TelephonyManager
-                                .THERMAL_MITIGATION_RESULT_MODEM_NOT_AVAILABLE;
+                                    .THERMAL_MITIGATION_RESULT_MODEM_NOT_AVAILABLE;
                         } else if (error == CommandException.Error.INVALID_ARGUMENTS) {
                             request.result = SET_DATA_THROTTLING_MODEM_THREW_INVALID_PARAMS;
                         } else if (error == CommandException.Error.REQUEST_NOT_SUPPORTED) {
@@ -2183,8 +2146,8 @@
                     onCompleted = obtainMessage(EVENT_SET_SIGNAL_STRENGTH_UPDATE_REQUEST_DONE,
                             request);
                     phone.getSignalStrengthController().setSignalStrengthUpdateRequest(
-                                    request.subId, pair.first /*callingUid*/,
-                                    pair.second /*request*/, onCompleted);
+                            request.subId, pair.first /*callingUid*/,
+                            pair.second /*request*/, onCompleted);
                     break;
                 }
                 case EVENT_SET_SIGNAL_STRENGTH_UPDATE_REQUEST_DONE: {
@@ -2211,8 +2174,8 @@
                     onCompleted = obtainMessage(EVENT_CLEAR_SIGNAL_STRENGTH_UPDATE_REQUEST_DONE,
                             request);
                     phone.getSignalStrengthController().clearSignalStrengthUpdateRequest(
-                                    request.subId, pair.first /*callingUid*/,
-                                    pair.second /*request*/, onCompleted);
+                            request.subId, pair.first /*callingUid*/,
+                            pair.second /*request*/, onCompleted);
                     break;
                 }
                 case EVENT_CLEAR_SIGNAL_STRENGTH_UPDATE_REQUEST_DONE: {
@@ -2296,127 +2259,10 @@
                     request = (MainThreadRequest) msg.obj;
                     request.result =
                             UiccController.getInstance().getPinStorage()
-                                .prepareUnattendedReboot(request.workSource);
+                                    .prepareUnattendedReboot(request.workSource);
                     notifyRequester(request);
                     break;
 
-                case CMD_START_SATELLITE_POSITION_UPDATES: {
-                    request = (MainThreadRequest) msg.obj;
-                    onCompleted =
-                            obtainMessage(EVENT_START_SATELLITE_POSITION_UPDATES_DONE, request);
-                    Phone phone = getPhoneFromRequest(request);
-                    if (phone != null) {
-                        phone.startSatellitePositionUpdates(onCompleted);
-                    } else {
-                        loge("startSatellitePositionUpdates: No phone object");
-                        request.result = SatelliteManager.SATELLITE_SERVICE_REQUEST_FAILED;
-                        notifyRequester(request);
-                    }
-                    break;
-                }
-
-                case EVENT_START_SATELLITE_POSITION_UPDATES_DONE: {
-                    ar = (AsyncResult) msg.obj;
-                    request = (MainThreadRequest) ar.userObj;
-                    if (ar.exception == null) {
-                        request.result = SatelliteManager.SATELLITE_SERVICE_SUCCESS;
-                    } else {
-                        request.result = SatelliteManager.SATELLITE_SERVICE_ERROR;
-                        if (ar.exception instanceof CommandException) {
-                            CommandException.Error error =
-                                    ((CommandException) (ar.exception)).getCommandError();
-                            request.result = RILUtils.convertToSatelliteError(error);
-                            loge("startSatellitePositionUpdates CommandException: " + ar.exception);
-                        } else {
-                            loge("startSatellitePositionUpdates unknown exception:" + ar.exception);
-                        }
-                    }
-                    notifyRequester(request);
-                    break;
-                }
-
-                case CMD_STOP_SATELLITE_POSITION_UPDATES: {
-                    request = (MainThreadRequest) msg.obj;
-                    onCompleted =
-                            obtainMessage(EVENT_STOP_SATELLITE_POSITION_UPDATES_DONE, request);
-                    Phone phone = getPhoneFromRequest(request);
-                    if (phone != null) {
-                        phone.stopSatellitePositionUpdates(onCompleted);
-                    } else {
-                        loge("stopSatellitePositionUpdates: No phone object");
-                        request.result = SatelliteManager.SATELLITE_SERVICE_REQUEST_FAILED;
-                        notifyRequester(request);
-                    }
-                    break;
-                }
-
-                case EVENT_STOP_SATELLITE_POSITION_UPDATES_DONE: {
-                    ar = (AsyncResult) msg.obj;
-                    request = (MainThreadRequest) ar.userObj;
-                    if (ar.exception == null) {
-                        request.result = SatelliteManager.SATELLITE_SERVICE_SUCCESS;
-                    } else {
-                        request.result = SatelliteManager.SATELLITE_SERVICE_ERROR;
-                        if (ar.exception instanceof CommandException) {
-                            CommandException.Error error =
-                                    ((CommandException) (ar.exception)).getCommandError();
-                            request.result = RILUtils.convertToSatelliteError(error);
-                            loge("stopSatellitePositionUpdates CommandException: " + ar.exception);
-                        } else {
-                            loge("stopSatellitePositionUpdates unknown exception:" + ar.exception);
-                        }
-                    }
-                    notifyRequester(request);
-                    break;
-                }
-
-                case CMD_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG: {
-                    request = (MainThreadRequest) msg.obj;
-                    onCompleted = obtainMessage(EVENT_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG_DONE,
-                            request);
-                    Phone phone = getPhoneFromRequest(request);
-                    if (phone != null) {
-                        phone.getMaxCharactersPerSatelliteTextMessage(onCompleted);
-                    } else {
-                        loge("getMaxCharactersPerSatelliteTextMessage: No phone object");
-                        request.result = SatelliteManager
-                                .SATELLITE_SERVICE_TELEPHONY_INTERNAL_ERROR;
-                        notifyRequester(request);
-                    }
-                    break;
-                }
-
-                case EVENT_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG_DONE: {
-                    ar = (AsyncResult) msg.obj;
-                    request = (MainThreadRequest) ar.userObj;
-                    Consumer<Integer> callback = (Consumer<Integer>) request.argument;
-                    if (ar.exception != null) {
-                        request.result = SatelliteManager.SATELLITE_SERVICE_ERROR;
-                        if (ar.exception instanceof CommandException) {
-                            CommandException.Error error =
-                                    ((CommandException) (ar.exception)).getCommandError();
-                            request.result = RILUtils.convertToSatelliteError(error);
-                            loge("getMaxCharactersPerSatelliteTextMessage: "
-                                    + "CommandException: " + ar.exception);
-                        } else {
-                            loge("getMaxCharactersPerSatelliteTextMessage: "
-                                    + "unknown exception:" + ar.exception);
-                        }
-                    } else if (ar.result == null) {
-                        request.result = SatelliteManager
-                                .SATELLITE_SERVICE_TELEPHONY_INTERNAL_ERROR;
-                        loge("getMaxCharactersPerSatelliteTextMessage: result is null");
-                    } else {
-                        request.result = SatelliteManager.SATELLITE_SERVICE_SUCCESS;
-                        int maxCharLimit = ((int[]) ar.result)[0];
-                        if(DBG) log("getMaxCharactersPerSatelliteTextMessage "
-                                + "maxCharLimit:" + maxCharLimit);
-                        callback.accept(maxCharLimit);
-                    }
-                    notifyRequester(request);
-                    break;
-                }
-
                 default:
                     Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
                     break;
@@ -2611,17 +2457,16 @@
         mApp = app;
         mCM = PhoneGlobals.getInstance().mCM;
         mImsResolver = ImsResolver.getInstance();
+        mSatelliteController = SatelliteController.getInstance();
         mUserManager = (UserManager) app.getSystemService(Context.USER_SERVICE);
         mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
-        mPm = app.getSystemService(PackageManager.class);
         mMainThreadHandler = new MainThreadHandler();
         if (!PhoneFactory.isSubscriptionManagerServiceEnabled()) {
             mSubscriptionController = SubscriptionController.getInstance();
         } else {
             mSubscriptionController = null;
         }
-        mTelephonySharedPreferences =
-                PreferenceManager.getDefaultSharedPreferences(mApp);
+        mTelephonySharedPreferences = PreferenceManager.getDefaultSharedPreferences(mApp);
         mNetworkScanRequestTracker = new NetworkScanRequestTracker();
         mPhoneConfigurationManager = PhoneConfigurationManager.getInstance();
         mRadioInterfaceCapabilities = RadioInterfaceCapabilityController.getInstance();
@@ -2865,14 +2710,16 @@
                                 synchronized (UnlockSim.this) {
                                     mRetryCount = msg.arg1;
                                     if (ar.exception != null) {
-                                        if (ar.exception instanceof CommandException &&
-                                                ((CommandException)(ar.exception)).getCommandError()
-                                                == CommandException.Error.PASSWORD_INCORRECT) {
+                                        CommandException.Error error = null;
+                                        if (ar.exception instanceof CommandException) {
+                                            error = ((CommandException) (ar.exception))
+                                                    .getCommandError();
+                                        }
+                                        if (error == CommandException.Error.PASSWORD_INCORRECT) {
                                             mResult = PhoneConstants.PIN_PASSWORD_INCORRECT;
-                                        } //When UiccCardApp dispose,handle message and return exception
-                                          else if (ar.exception instanceof CommandException &&
-                                                ((CommandException) (ar.exception)).getCommandError()
-                                                        == CommandException.Error.ABORTED) {
+                                        } else if (error == CommandException.Error.ABORTED) {
+                                            /* When UiccCardApp dispose, handle message and return
+                                             exception */
                                             mResult = PhoneConstants.PIN_OPERATION_ABORTED;
                                         } else {
                                             mResult = PhoneConstants.PIN_GENERAL_FAILURE;
@@ -3969,11 +3816,11 @@
     }
 
     private static void logv(String msg) {
-        Log.v(LOG_TAG, "[PhoneIntfMgr] " + msg);
+        Log.v(LOG_TAG, msg);
     }
 
     private static void loge(String msg) {
-        Log.e(LOG_TAG, "[PhoneIntfMgr] " + msg);
+        Log.e(LOG_TAG, msg);
     }
 
     @Override
@@ -4402,8 +4249,8 @@
     }
 
     /**
-      * returns true, if the device is in a state where both voice and data
-      * are supported simultaneously. This can change based on location or network condition.
+     * returns true, if the device is in a state where both voice and data
+     * are supported simultaneously. This can change based on location or network condition.
      */
     @Override
     public boolean isConcurrentVoiceAndDataAllowed(int subId) {
@@ -4443,8 +4290,8 @@
     @Override
     public int getNetworkSelectionMode(int subId) {
         TelephonyPermissions
-                    .enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
-                    mApp, subId, "getNetworkSelectionMode");
+                .enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                        mApp, subId, "getNetworkSelectionMode");
         final long identity = Binder.clearCallingIdentity();
         try {
             if (!isActiveSubscription(subId)) {
@@ -5482,7 +5329,7 @@
             return getDataNetworkTypeForSubscriber(subId, callingPackage, callingFeatureId);
         } else if (targetSdk == android.os.Build.VERSION_CODES.Q
                 && !TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow(
-                        mApp, subId, callingPackage, callingFeatureId,
+                mApp, subId, callingPackage, callingFeatureId,
                 "getNetworkTypeForSubscriber")) {
             return TelephonyManager.NETWORK_TYPE_UNKNOWN;
         }
@@ -5648,7 +5495,7 @@
 
     private boolean isActiveSubscription(int subId) {
         if (PhoneFactory.isSubscriptionManagerServiceEnabled()) {
-            return SubscriptionManagerService.getInstance().isActiveSubId(subId,
+            return getSubscriptionManagerService().isActiveSubId(subId,
                     mApp.getOpPackageName(), mApp.getFeatureId());
         }
         return mSubscriptionController.isActiveSubId(subId);
@@ -5692,7 +5539,7 @@
                 portIndex);
         if (phoneId == -1) {
             throw new IllegalArgumentException("Given slot index: " + slotIndex + " port index: "
-                     + portIndex + " does not correspond to an active phone");
+                    + portIndex + " does not correspond to an active phone");
         }
         return PhoneFactory.getPhone(phoneId);
     }
@@ -5811,12 +5658,12 @@
 
     @Override
     public String iccTransmitApduLogicalChannelByPort(int slotIndex, int portIndex, int channel,
-             int cla, int command, int p1, int p2, int p3, String data) {
+            int cla, int command, int p1, int p2, int p3, String data) {
         enforceModifyPermission();
         if (DBG) {
             log("iccTransmitApduLogicalChannelByPort: slotIndex=" + slotIndex + " portIndex="
-                     + portIndex + " chnl=" + channel + " cla=" + cla + " cmd=" + command + " p1="
-                     + p1 + " p2=" + p2 + " p3=" + p3 + " data=" + data);
+                    + portIndex + " chnl=" + channel + " cla=" + cla + " cmd=" + command + " p1="
+                    + p1 + " p2=" + p2 + " p3=" + p3 + " data=" + data);
         }
         return iccTransmitApduLogicalChannelWithPermission(
                 getPhoneFromSlotPortIndexOrThrowException(slotIndex, portIndex), channel, cla,
@@ -5864,13 +5711,13 @@
 
     @Override
     public String iccTransmitApduBasicChannelByPort(int slotIndex, int portIndex,
-             String callingPackage, int cla, int command, int p1, int p2, int p3, String data) {
+            String callingPackage, int cla, int command, int p1, int p2, int p3, String data) {
         enforceModifyPermission();
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
         if (DBG) {
             log("iccTransmitApduBasicChannelByPort: slotIndex=" + slotIndex + " portIndex="
-                     + portIndex + " cla=" + cla + " cmd=" + command + " p1=" + p1 + " p2="
-                     + p2 + " p3=" + p3 + " data=" + data);
+                    + portIndex + " cla=" + cla + " cmd=" + command + " p1=" + p1 + " p2="
+                    + p2 + " p3=" + p3 + " data=" + data);
         }
 
         return iccTransmitApduBasicChannelWithPermission(
@@ -6506,7 +6353,7 @@
             Binder.restoreCallingIdentity(identity);
         }
     }
-     /**
+    /**
      * Get the manual network selection
      *
      * @param subId the id of the subscription.
@@ -6516,8 +6363,8 @@
     @Override
     public String getManualNetworkSelectionPlmn(int subId) {
         TelephonyPermissions
-                    .enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
-                    mApp, subId, "getManualNetworkSelectionPlmn");
+                .enforceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+                        mApp, subId, "getManualNetworkSelectionPlmn");
 
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -6531,7 +6378,7 @@
             }
             OperatorInfo networkSelection = phone.getSavedNetworkSelection();
             return TextUtils.isEmpty(networkSelection.getOperatorNumeric())
-                ? phone.getManualNetworkSelectionPlmn() : networkSelection.getOperatorNumeric();
+                    ? phone.getManualNetworkSelectionPlmn() : networkSelection.getOperatorNumeric();
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -6689,7 +6536,7 @@
                 String newUssdCommand = "";
                 try {
                     newUssdCommand = carrierXmlParser.getFeature(
-                            CarrierXmlParser.FEATURE_CALL_WAITING)
+                                    CarrierXmlParser.FEATURE_CALL_WAITING)
                             .makeCommand(CarrierXmlParser.SsEntry.SSAction.QUERY, null);
                 } catch (NullPointerException e) {
                     loge("Failed to generate USSD number" + e);
@@ -6746,7 +6593,7 @@
                 String newUssdCommand = "";
                 try {
                     newUssdCommand = carrierXmlParser.getFeature(
-                            CarrierXmlParser.FEATURE_CALL_WAITING)
+                                    CarrierXmlParser.FEATURE_CALL_WAITING)
                             .makeCommand(ssAction, null);
                 } catch (NullPointerException e) {
                     loge("Failed to generate USSD number" + e);
@@ -6790,16 +6637,16 @@
                 LocationAccessPolicy.LocationPermissionResult.DENIED_HARD;
         if (!renounceFineLocationAccess) {
             locationResult = LocationAccessPolicy.checkLocationPermission(mApp,
-                            new LocationAccessPolicy.LocationPermissionQuery.Builder()
-                                    .setCallingPackage(callingPackage)
-                                    .setCallingFeatureId(callingFeatureId)
-                                    .setCallingPid(Binder.getCallingPid())
-                                    .setCallingUid(Binder.getCallingUid())
-                                    .setMethod("requestNetworkScan")
-                                    .setMinSdkVersionForFine(Build.VERSION_CODES.Q)
-                                    .setMinSdkVersionForCoarse(Build.VERSION_CODES.Q)
-                                    .setMinSdkVersionForEnforcement(Build.VERSION_CODES.Q)
-                                    .build());
+                    new LocationAccessPolicy.LocationPermissionQuery.Builder()
+                            .setCallingPackage(callingPackage)
+                            .setCallingFeatureId(callingFeatureId)
+                            .setCallingPid(Binder.getCallingPid())
+                            .setCallingUid(Binder.getCallingUid())
+                            .setMethod("requestNetworkScan")
+                            .setMinSdkVersionForFine(Build.VERSION_CODES.Q)
+                            .setMinSdkVersionForCoarse(Build.VERSION_CODES.Q)
+                            .setMinSdkVersionForEnforcement(Build.VERSION_CODES.Q)
+                            .build());
         }
         if (locationResult != LocationAccessPolicy.LocationPermissionResult.ALLOWED) {
             SecurityException e = checkNetworkRequestForSanitizedLocationAccess(
@@ -6837,7 +6684,7 @@
         }
         boolean hasNetworkScanPermission =
                 mApp.checkCallingOrSelfPermission(android.Manifest.permission.NETWORK_SCAN)
-                == PERMISSION_GRANTED;
+                        == PERMISSION_GRANTED;
 
         if (!hasCarrierPriv && !hasNetworkScanPermission) {
             return new SecurityException("permission.NETWORK_SCAN or carrier privileges is needed"
@@ -6913,7 +6760,7 @@
                 mApp, subId, "getAllowedNetworkTypesForReason");
         final long identity = Binder.clearCallingIdentity();
         try {
-            return getPhoneFromSubId(subId).getAllowedNetworkTypes(reason);
+            return getPhoneFromSubIdOrDefault(subId).getAllowedNetworkTypes(reason);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -7614,7 +7461,7 @@
 
             ParcelUuid groupUuid;
             if (PhoneFactory.isSubscriptionManagerServiceEnabled()) {
-                final SubscriptionInfo info = SubscriptionManagerService.getInstance()
+                final SubscriptionInfo info = getSubscriptionManagerService()
                         .getSubscriptionInfo(subId);
                 groupUuid = info.getGroupUuid();
             } else {
@@ -7631,7 +7478,7 @@
             final List<String> mergedSubscriberIds = new ArrayList<>();
             List<SubscriptionInfo> groupInfos;
             if (PhoneFactory.isSubscriptionManagerServiceEnabled()) {
-                groupInfos = SubscriptionManagerService.getInstance()
+                groupInfos = getSubscriptionManagerService()
                         .getSubscriptionsInGroup(groupUuid, mApp.getOpPackageName(),
                                 mApp.getAttributionTag());
             } else {
@@ -8049,9 +7896,10 @@
     public @Nullable PhoneAccountHandle getPhoneAccountHandleForSubscriptionId(int subscriptionId) {
         TelephonyPermissions
                 .enforceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
-                mApp,
-                subscriptionId,
-                "getPhoneAccountHandleForSubscriptionId, " + "subscriptionId: " + subscriptionId);
+                        mApp,
+                        subscriptionId,
+                        "getPhoneAccountHandleForSubscriptionId, " + "subscriptionId: "
+                                + subscriptionId);
         final long identity = Binder.clearCallingIdentity();
         try {
             Phone phone = getPhone(subscriptionId);
@@ -8200,7 +8048,7 @@
         try {
             SubscriptionInfo info;
             if (PhoneFactory.isSubscriptionManagerServiceEnabled()) {
-                info = SubscriptionManagerService.getInstance().getActiveSubscriptionInfo(subId,
+                info = getSubscriptionManagerService().getActiveSubscriptionInfo(subId,
                         phone.getContext().getOpPackageName(),
                         phone.getContext().getAttributionTag());
                 if (info == null) {
@@ -8267,7 +8115,7 @@
      */
     private List<SubscriptionInfo> getActiveSubscriptionInfoListPrivileged() {
         if (PhoneFactory.isSubscriptionManagerServiceEnabled()) {
-            return SubscriptionManagerService.getInstance().getActiveSubscriptionInfoList(
+            return getSubscriptionManagerService().getActiveSubscriptionInfoList(
                     mApp.getOpPackageName(), mApp.getAttributionTag());
         }
         return mSubscriptionController.getActiveSubscriptionInfoList(mApp.getOpPackageName(),
@@ -8311,8 +8159,8 @@
         int totalTxTimeMs = Arrays.stream(info.getTransmitTimeMillis()).sum();
 
         return (info.isValid()
-            && (info.getSleepTimeMillis() <= activityDurationMs)
-            && (info.getIdleTimeMillis() <= activityDurationMs));
+                && (info.getSleepTimeMillis() <= activityDurationMs)
+                && (info.getIdleTimeMillis() <= activityDurationMs));
     }
 
     private void updateLastModemActivityInfo(ModemActivityInfo info, int rat, int freq) {
@@ -8346,10 +8194,10 @@
                 info.getReceiveTimeMillis(rat) + mLastModemActivityInfo.getReceiveTimeMillis(rat));
     }
 
-   /**
-    * Merge this ModemActivityInfo with mLastModemActivitySpecificInfo
-    * @param info recent ModemActivityInfo
-    */
+    /**
+     * Merge this ModemActivityInfo with mLastModemActivitySpecificInfo
+     * @param info recent ModemActivityInfo
+     */
     private void mergeModemActivityInfo(ModemActivityInfo info) {
         List<ActivityStatsTechSpecificInfo> merged = new ArrayList<>();
         ActivityStatsTechSpecificInfo deltaSpecificInfo;
@@ -8394,17 +8242,17 @@
         mLastModemActivityInfo.setTimestamp(info.getTimestampMillis());
         mLastModemActivityInfo.setSleepTimeMillis(
                 info.getSleepTimeMillis()
-                + mLastModemActivityInfo.getSleepTimeMillis());
+                        + mLastModemActivityInfo.getSleepTimeMillis());
         mLastModemActivityInfo.setIdleTimeMillis(
                 info.getIdleTimeMillis()
-                + mLastModemActivityInfo.getIdleTimeMillis());
+                        + mLastModemActivityInfo.getIdleTimeMillis());
 
         mLastModemActivityInfo =
-                 new ModemActivityInfo(
-                         mLastModemActivityInfo.getTimestampMillis(),
-                         mLastModemActivityInfo.getSleepTimeMillis(),
-                         mLastModemActivityInfo.getIdleTimeMillis(),
-                         mLastModemActivitySpecificInfo);
+                new ModemActivityInfo(
+                        mLastModemActivityInfo.getTimestampMillis(),
+                        mLastModemActivityInfo.getSleepTimeMillis(),
+                        mLastModemActivityInfo.getIdleTimeMillis(),
+                        mLastModemActivitySpecificInfo);
     }
 
     private ActivityStatsTechSpecificInfo[] deepCopyModemActivitySpecificInfo(
@@ -8482,7 +8330,7 @@
         try {
             // isActiveSubId requires READ_PHONE_STATE, which we already check for above
             if (PhoneFactory.isSubscriptionManagerServiceEnabled()) {
-                SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance()
+                SubscriptionInfoInternal subInfo = getSubscriptionManagerService()
                         .getSubscriptionInfoInternal(subId);
                 if (subInfo == null || !subInfo.isActive()) {
                     Rlog.d(LOG_TAG, "getServiceStateForSubscriber returning null for inactive "
@@ -9026,7 +8874,7 @@
             @NonNull String[] args) {
         return new TelephonyShellCommand(this, getDefaultPhone().getContext()).exec(
                 this, in.getFileDescriptor(), out.getFileDescriptor(),
-                        err.getFileDescriptor(), args);
+                err.getFileDescriptor(), args);
     }
 
     /**
@@ -9322,7 +9170,7 @@
     public boolean isManualNetworkSelectionAllowed(int subId) {
         TelephonyPermissions
                 .enforceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
-                mApp, subId, "isManualNetworkSelectionAllowed");
+                        mApp, subId, "isManualNetworkSelectionAllowed");
 
         boolean isAllowed = true;
         final long identity = Binder.clearCallingIdentity();
@@ -9366,7 +9214,7 @@
             // even without READ_PRIVILEGED_PHONE_STATE, we allow the call to continue if the caller
             // has carrier privileges on an active UICC
             if (checkCarrierPrivilegesForPackageAnyPhoneWithPermission(callingPackage)
-                        != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+                    != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
                 throw new SecurityException("Caller does not have permission.");
             }
         }
@@ -9751,7 +9599,7 @@
     public int getCdmaRoamingMode(int subId) {
         TelephonyPermissions
                 .enforceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
-                mApp, subId, "getCdmaRoamingMode");
+                        mApp, subId, "getCdmaRoamingMode");
 
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -9841,7 +9689,7 @@
                 // TelephonyManager#isPotentialEmergencyNumber is removed completely
                 if (phone.getEmergencyNumberTracker() != null
                         && phone.getEmergencyNumberTracker()
-                                .isEmergencyNumber(number)) {
+                        .isEmergencyNumber(number)) {
                     return true;
                 }
             }
@@ -10715,7 +10563,7 @@
         try {
             getGbaManager(subId).bootstrapAuthenticationRequest(
                     new GbaAuthRequest(subId, appType, nafUrl, securityProtocol.toByteArray(),
-                    forceBootStrapping, callback));
+                            forceBootStrapping, callback));
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -10766,7 +10614,7 @@
 
         if (isDataThrottlingSupported) {
             int thermalMitigationResult =
-                (int) sendRequest(CMD_SET_DATA_THROTTLING, dataThrottlingRequest, subId);
+                    (int) sendRequest(CMD_SET_DATA_THROTTLING, dataThrottlingRequest, subId);
             if (thermalMitigationResult == SET_DATA_THROTTLING_MODEM_THREW_INVALID_PARAMS) {
                 throw new IllegalArgumentException("modem returned INVALID_ARGUMENTS");
             } else if (thermalMitigationResult
@@ -10801,8 +10649,8 @@
         for (Phone phone : PhoneFactory.getPhones()) {
             if (phone.isInEmergencySmsMode() || phone.isInEcm()) {
                 Log.e(LOG_TAG, "Phone state is not valid. isInEmergencySmsMode = "
-                    + phone.isInEmergencySmsMode() + " isInEmergencyCallbackMode = "
-                    + phone.isInEcm());
+                        + phone.isInEmergencySmsMode() + " isInEmergencyCallbackMode = "
+                        + phone.isInEcm());
                 return true;
             }
         }
@@ -10863,9 +10711,9 @@
             switch (thermalMitigationAction) {
                 case ThermalMitigationRequest.THERMAL_MITIGATION_ACTION_DATA_THROTTLING:
                     thermalMitigationResult =
-                        handleDataThrottlingRequest(subId,
-                                thermalMitigationRequest.getDataThrottlingRequest(),
-                                callingPackage);
+                            handleDataThrottlingRequest(subId,
+                                    thermalMitigationRequest.getDataThrottlingRequest(),
+                                    callingPackage);
                     break;
                 case ThermalMitigationRequest.THERMAL_MITIGATION_ACTION_VOICE_ONLY:
                     if (thermalMitigationRequest.getDataThrottlingRequest() != null) {
@@ -10896,7 +10744,7 @@
                         Phone phone = getPhone(subId);
                         if (phone == null) {
                             thermalMitigationResult =
-                                TelephonyManager.THERMAL_MITIGATION_RESULT_MODEM_NOT_AVAILABLE;
+                                    TelephonyManager.THERMAL_MITIGATION_RESULT_MODEM_NOT_AVAILABLE;
                             break;
                         }
 
@@ -10909,7 +10757,7 @@
                             break;
                         } else if (isAnyPhoneInEmergencyState()) {
                             thermalMitigationResult =
-                                TelephonyManager.THERMAL_MITIGATION_RESULT_INVALID_STATE;
+                                    TelephonyManager.THERMAL_MITIGATION_RESULT_INVALID_STATE;
                             break;
                         }
                     } else {
@@ -10926,7 +10774,7 @@
                         break;
                     }
                     thermalMitigationResult =
-                        TelephonyManager.THERMAL_MITIGATION_RESULT_SUCCESS;
+                            TelephonyManager.THERMAL_MITIGATION_RESULT_SUCCESS;
                     break;
                 default:
                     throw new IllegalArgumentException("the requested thermalMitigationAction does "
@@ -11967,8 +11815,8 @@
         Log.d(LOG_TAG, "setModemService - " + serviceName);
         TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(), "setModemService");
         TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp,
-                        SubscriptionManager.INVALID_SUBSCRIPTION_ID,
-                        "setModemService");
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+                "setModemService");
         return mPhoneConfigurationManager.setModemService(serviceName);
     }
 
@@ -11982,7 +11830,7 @@
         Log.d(LOG_TAG, "getModemService");
         TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(), "getModemService");
         TelephonyPermissions
-                        .enforceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
+                .enforceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
                         mApp, SubscriptionManager.INVALID_SUBSCRIPTION_ID,
                         "getModemService");
         result = mPhoneConfigurationManager.getModemService();
@@ -12225,125 +12073,403 @@
     }
 
     /**
+     * Request to enable or disable the satellite modem. If the satellite modem is enabled, this
+     * will also disable the cellular modem, and if the satellite modem is disabled, this will also
+     * re-enable the cellular modem.
+     *
+     * @param subId The subId of the subscription to set satellite enabled for.
+     * @param enable {@code true} to enable the satellite modem and {@code false} to disable.
+     * @param callback The callback to get the error code of the request.
+     *
+     * @throws SecurityException if the caller doesn't have the required permission.
+     */
+    @Override
+    public void requestSatelliteEnabled(
+            int subId, boolean enable, @NonNull IIntegerConsumer callback) {
+        enforceSatelliteCommunicationPermission("requestSatelliteEnabled");
+        mSatelliteController.requestSatelliteEnabled(subId, enable, callback);
+    }
+
+    /**
+     * Request to get whether the satellite modem is enabled.
+     *
+     * @param subId The subId of the subscription to check whether satellite is enabled for.
+     * @param result The result receiver that returns whether the satellite modem is enabled
+     *               if the request is successful or an error code if the request failed.
+     *
+     * @throws SecurityException if the caller doesn't have the required permission.
+     */
+    @Override
+    public void requestIsSatelliteEnabled(int subId, @NonNull ResultReceiver result) {
+        enforceSatelliteCommunicationPermission("requestIsSatelliteEnabled");
+        mSatelliteController.requestIsSatelliteEnabled(subId, result);
+    }
+
+    /**
+     * Request to enable or disable the satellite service demo mode.
+     *
+     * @param subId The subId of the subscription to set the satellite demo mode enabled for.
+     * @param enable {@code true} to enable the satellite demo mode and {@code false} to disable.
+     * @param callback The callback to get the error code of the request.
+     *
+     * @throws SecurityException if the caller doesn't have the required permission.
+     */
+    @Override
+    public void requestSatelliteDemoModeEnabled(
+            int subId, boolean enable, @NonNull IIntegerConsumer callback) {
+        enforceSatelliteCommunicationPermission("requestSatelliteDemoModeEnabled");
+        mSatelliteController.requestSatelliteDemoModeEnabled(subId, enable, callback);
+    }
+
+    /**
+     * Request to get whether the satellite service demo mode is enabled.
+     *
+     * @param subId The subId of the subscription to check whether the satellite demo mode
+     *              is enabled for.
+     * @param result The result receiver that returns whether the satellite demo mode is enabled
+     *               if the request is successful or an error code if the request failed.
+     *
+     * @throws SecurityException if the caller doesn't have the required permission.
+     */
+    @Override
+    public void requestIsSatelliteDemoModeEnabled(int subId, @NonNull ResultReceiver result) {
+        enforceSatelliteCommunicationPermission("requestIsSatelliteDemoModeEnabled");
+        mSatelliteController.requestIsSatelliteDemoModeEnabled(subId, result);
+    }
+
+    /**
+     * Request to get whether the satellite service is supported on the device.
+     *
+     * @param subId The subId of the subscription to check satellite service support for.
+     * @param result The result receiver that returns whether the satellite service is supported on
+     *               the device if the request is successful or an error code if the request failed.
+     */
+    @Override
+    public void requestIsSatelliteSupported(int subId, @NonNull ResultReceiver result) {
+        mSatelliteController.requestIsSatelliteSupported(subId, result);
+    }
+
+    /**
+     * Request to get the {@link SatelliteCapabilities} of the satellite service.
+     *
+     * @param subId The subId of the subscription to get the satellite capabilities for.
+     * @param result The result receiver that returns the {@link SatelliteCapabilities}
+     *               if the request is successful or an error code if the request failed.
+     *
+     * @throws SecurityException if the caller doesn't have required permission.
+     */
+    @Override
+    public void requestSatelliteCapabilities(int subId, @NonNull ResultReceiver result) {
+        enforceSatelliteCommunicationPermission("requestSatelliteCapabilities");
+        mSatelliteController.requestSatelliteCapabilities(subId, result);
+    }
+
+    /**
      * Start receiving satellite position updates.
      * This can be called by the pointing UI when the user starts pointing to the satellite.
      * Modem should continue to report the pointing input as the device or satellite moves.
      *
-     * @param subId The subId to start satellite position updates for.
-     * @param callbackId The callback ID associating the public SatellitePositionUpdateCallback to
-     *                   the internal ISatellitePositionUpdateCallback below.
+     * @param subId The subId of the subscription to start satellite position updates for.
+     * @param errorCallback The callback to get the error code of the request.
      * @param callback The callback to notify of changes in satellite position.
-     * @return The result of the operation.
+     *
+     * @throws SecurityException if the caller doesn't have the required permission.
      */
     @Override
-    @SatelliteManager.SatelliteServiceResult public int startSatellitePositionUpdates(int subId,
-            int callbackId, @NonNull ISatellitePositionUpdateCallback callback) {
-        // TODO: check for SATELLITE_COMMUNICATION permission
-        Phone phone = getPhone(subId);
-        if (phone == null) {
-            loge("startSatellitePositionUpdates called with invalid subId: " + subId
-                    + ". Retrying with default phone.");
-            phone = getDefaultPhone();
-            if (phone == null) {
-                loge("startSatellitePositionUpdates failed with no phone object.");
-                return SatelliteManager.SATELLITE_SERVICE_REQUEST_FAILED;
-            }
-        }
-
-        if (mSatellitePositionUpdateHandlers.containsKey(callbackId)) {
-            log("startSatellitePositionUpdates: callback already registered: " + callbackId);
-            return SatelliteManager.SATELLITE_SERVICE_SUCCESS;
-        }
-
-        SatellitePositionUpdateHandler handler =
-                new SatellitePositionUpdateHandler(callback, Looper.getMainLooper());
-        phone.registerForSatellitePointingInfoChanged(handler,
-                SatellitePositionUpdateHandler.EVENT_POSITION_UPDATE, null);
-        phone.registerForSatelliteMessagesTransferComplete(handler,
-                SatellitePositionUpdateHandler.EVENT_MESSAGE_TRANSFER_STATE_UPDATE, null);
-        mSatellitePositionUpdateHandlers.put(callbackId, handler);
-
-        int result = (int) sendRequest(CMD_START_SATELLITE_POSITION_UPDATES, null, subId);
-        if (DBG) log("startSatellitePositionUpdates result: " + result);
-        return result;
+    public void startSatellitePositionUpdates(int subId, @NonNull IIntegerConsumer errorCallback,
+            @NonNull ISatellitePositionUpdateCallback callback) {
+        enforceSatelliteCommunicationPermission("startSatellitePositionUpdates");
+        mSatelliteController.startSatellitePositionUpdates(subId, errorCallback, callback);
     }
 
     /**
      * Stop receiving satellite position updates.
      * This can be called by the pointing UI when the user stops pointing to the satellite.
      *
-     * @param subId The subId to stop satellite position updates for.
-     * @param callbackId The ID of the callback that was passed in {@link
-     *                   #startSatellitePositionUpdates(int, int, ISatellitePositionUpdateCallback)}
-     * @return The result of the operation.
-     */
-    @Override
-    @SatelliteManager.SatelliteServiceResult public int stopSatellitePositionUpdates(int subId,
-            int callbackId) {
-        // TODO: check for SATELLITE_COMMUNICATION permission
-        Phone phone = getPhone(subId);
-        if (phone == null) {
-            loge("stopSatellitePositionUpdates called with invalid subId: " + subId
-                    + ". Retrying with default phone.");
-            phone = getDefaultPhone();
-            if (phone == null) {
-                loge("stopSatellitePositionUpdates failed with no phone object.");
-                return SatelliteManager.SATELLITE_SERVICE_REQUEST_FAILED;
-            }
-        }
-
-        SatellitePositionUpdateHandler handler =
-                mSatellitePositionUpdateHandlers.remove(callbackId);
-        if (handler == null) {
-            loge("stopSatellitePositionUpdates: No SatellitePositionArgument");
-            return SatelliteManager.SATELLITE_SERVICE_REQUEST_FAILED;
-        } else {
-            phone.unregisterForSatellitePointingInfoChanged(handler);
-            phone.unregisterForSatelliteMessagesTransferComplete(handler);
-        }
-
-        if (!mSatellitePositionUpdateHandlers.isEmpty()) {
-            log("stopSatellitePositionUpdates: other listeners still exist.");
-            return SatelliteManager.SATELLITE_SERVICE_SUCCESS;
-        }
-
-        int result = (int) sendRequest(CMD_STOP_SATELLITE_POSITION_UPDATES, null, subId);
-        if (DBG) log("stopSatellitePositionUpdates result: " + result);
-        return result;
-    }
-
-    /**
-     * Get maximum number of characters per text message on satellite.
-     * @param subId - The subId of the subscription.
-     * @param callback - The callback that will be used to send maximum characters limit
-     *                 if operation is successful.
-     * @return The result of the operation.
+     * @param subId The subId of the subscription to stop satellite position updates for.
+     * @param errorCallback The callback to get the error code of the request.
+     * @param callback The callback that was passed to {@link
+     * #startSatellitePositionUpdates(int, IIntegerConsumer, ISatellitePositionUpdateCallback)}
      *
      * @throws SecurityException if the caller doesn't have the required permission.
      */
     @Override
-    public int getMaxCharactersPerSatelliteTextMessage(int subId, IIntegerConsumer callback) {
-        enforceSatelliteCommunicationPermission("getMaxCharactersPerSatelliteTextMessage");
+    public void stopSatellitePositionUpdates(int subId, @NonNull IIntegerConsumer errorCallback,
+            @NonNull ISatellitePositionUpdateCallback callback) {
+        enforceSatelliteCommunicationPermission("stopSatellitePositionUpdates");
+        mSatelliteController.stopSatellitePositionUpdates(subId, errorCallback, callback);
+    }
 
-        if (!isSatelliteEnabled(subId)) {
-            return SatelliteManager.SATELLITE_SERVICE_DISABLED;
-        }
+    /**
+     * Request to get the maximum number of bytes per datagram that can be sent to satellite.
+     *
+     * @param subId The subId of the subscription to get the maximum number of characters for.
+     * @param result The result receiver that returns the maximum number of bytes per datagram
+     *               message on satellite if the request is successful or an error code
+     *               if the request failed.
+     *
+     * @throws SecurityException if the caller doesn't have the required permission.
+     */
+    @Override
+    public void requestMaxSizePerSendingDatagram(int subId,
+            @NonNull ResultReceiver result) {
+        enforceSatelliteCommunicationPermission("requestMaxSizePerSendingDatagram");
+        mSatelliteController.requestMaxSizePerSendingDatagram(subId, result);
+    }
 
+    /**
+     * Register the subscription with a satellite provider.
+     * This is needed to register the subscription if the provider allows dynamic registration.
+     *
+     * @param subId The subId of the subscription to be provisioned.
+     * @param token The token to be used as a unique identifier for provisioning with satellite
+     *              gateway.
+     * @param callback The callback to get the error code of the request.
+     *
+     * @return The signal transport used by the caller to cancel the provision request,
+     *         or {@code null} if the request failed.
+     *
+     * @throws SecurityException if the caller doesn't have the required permission.
+     */
+    @Override
+    @Nullable public ICancellationSignal provisionSatelliteService(int subId,
+            @NonNull String token, @NonNull IIntegerConsumer callback) {
+        enforceSatelliteCommunicationPermission("provisionSatelliteService");
+        return mSatelliteController.provisionSatelliteService(subId, token, callback);
+    }
+
+    /**
+     * Unregister the device/subscription with the satellite provider.
+     * This is needed if the provider allows dynamic registration. Once deprovisioned,
+     * {@link SatelliteProvisionStateCallback#onSatelliteProvisionStateChanged(boolean)}
+     * should report as deprovisioned.
+     *
+     * @param subId The subId of the subscription to be deprovisioned.
+     * @param token The token of the device/subscription to be deprovisioned.
+     * @param callback The callback to get the error code of the request.
+     *
+     * @throws SecurityException if the caller doesn't have the required permission.
+     */
+    @Override
+    public void deprovisionSatelliteService(int subId,
+            @NonNull String token, @NonNull IIntegerConsumer callback) {
+        enforceSatelliteCommunicationPermission("deprovisionSatelliteService");
+        mSatelliteController.deprovisionSatelliteService(subId, token, callback);
+    }
+
+    /**
+     * Registers for the satellite provision state changed.
+     *
+     * @param subId The subId of the subscription to register for provision state changed.
+     * @param callback The callback to handle the satellite provision state changed event.
+     *
+     * @return The {@link SatelliteManager.SatelliteError} result of the operation.
+     *
+     * @throws SecurityException if the caller doesn't have the required permission.
+     */
+    @Override
+    @SatelliteManager.SatelliteError public int registerForSatelliteProvisionStateChanged(int subId,
+            @NonNull ISatelliteProvisionStateCallback callback) {
+        enforceSatelliteCommunicationPermission("registerForSatelliteProvisionStateChanged");
+        return mSatelliteController.registerForSatelliteProvisionStateChanged(subId, callback);
+    }
+
+    /**
+     * Unregisters for the satellite provision state changed.
+     * If callback was not registered before, the request will be ignored.
+     *
+     * @param subId The subId of the subscription to unregister for provision state changed.
+     * @param callback The callback that was passed to
+     * {@link #registerForSatelliteProvisionStateChanged(int, ISatelliteProvisionStateCallback)}.
+     *
+     * @throws SecurityException if the caller doesn't have the required permission.
+     */
+    @Override
+    public void unregisterForSatelliteProvisionStateChanged(
+            int subId, @NonNull ISatelliteProvisionStateCallback callback) {
+        enforceSatelliteCommunicationPermission("unregisterForSatelliteProvisionStateChanged");
+        mSatelliteController.unregisterForSatelliteProvisionStateChanged(subId, callback);
+    }
+
+    /**
+     * Request to get whether the device is provisioned with a satellite provider.
+     *
+     * @param subId The subId of the subscription to get whether the device is provisioned for.
+     * @param result The result receiver that returns whether the device is provisioned with a
+     *               satellite provider if the request is successful or an error code if the
+     *               request failed.
+     *
+     * @throws SecurityException if the caller doesn't have the required permission.
+     */
+    @Override
+    public void requestIsSatelliteProvisioned(int subId, @NonNull ResultReceiver result) {
+        enforceSatelliteCommunicationPermission("requestIsSatelliteProvisioned");
+        mSatelliteController.requestIsSatelliteProvisioned(subId, result);
+    }
+
+    /**
+     * Registers for modem state changed from satellite modem.
+     *
+     * @param subId The subId of the subscription to register for satellite modem state changed.
+     * @param callback The callback to handle the satellite modem state changed event.
+     *
+     * @return The {@link SatelliteManager.SatelliteError} result of the operation.
+     *
+     * @throws SecurityException if the caller doesn't have the required permission.
+     */
+    @Override
+    @SatelliteManager.SatelliteError public int registerForSatelliteModemStateChanged(int subId,
+            @NonNull ISatelliteStateCallback callback) {
+        enforceSatelliteCommunicationPermission("registerForSatelliteModemStateChanged");
+        return mSatelliteController.registerForSatelliteModemStateChanged(subId, callback);
+    }
+
+    /**
+     * Unregisters for modem state changed from satellite modem.
+     * If callback was not registered before, the request will be ignored.
+     *
+     * @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)}.
+     *
+     * @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);
+    }
+
+    /**
+     * Register to receive incoming datagrams over satellite.
+     *
+     * @param subId The subId of the subscription to register for incoming satellite datagrams.
+     * @param datagramType datagram type indicating whether the datagram is of type
+     *                     SOS_SMS or LOCATION_SHARING.
+     * @param callback The callback to handle incoming datagrams over satellite.
+     *
+     * @return The {@link SatelliteManager.SatelliteError} result of the operation.
+     *
+     * @throws SecurityException if the caller doesn't have the required permission.
+     */
+    @Override
+    @SatelliteManager.SatelliteError public int registerForSatelliteDatagram(int subId,
+            @SatelliteManager.DatagramType int datagramType,
+            @NonNull ISatelliteDatagramCallback callback) {
+        enforceSatelliteCommunicationPermission("registerForSatelliteDatagram");
+        return mSatelliteController.registerForSatelliteDatagram(subId, datagramType, callback);
+    }
+
+    /**
+     * Unregister to stop receiving incoming datagrams over satellite.
+     * If callback was not registered before, the request will be ignored.
+     *
+     * @param subId The subId of the subscription to unregister for incoming satellite datagrams.
+     * @param callback The callback that was passed to
+     *                 {@link #registerForSatelliteDatagram(int, int, ISatelliteDatagramCallback)}.
+     *
+     * @throws SecurityException if the caller doesn't have the required permission.
+     */
+    @Override
+    public void unregisterForSatelliteDatagram(int subId,
+            @NonNull ISatelliteDatagramCallback callback) {
+        enforceSatelliteCommunicationPermission("unregisterForSatelliteDatagram");
+        mSatelliteController.unregisterForSatelliteDatagram(subId, callback);
+    }
+
+    /**
+     * Poll pending satellite datagrams over satellite.
+     *
+     * This method requests modem to check if there are any pending datagrams to be received over
+     * satellite. If there are any incoming datagrams, they will be received via
+     * {@link SatelliteDatagramCallback#onSatelliteDatagramReceived(long, SatelliteDatagram, int,
+     * ILongConsumer)})}
+     *
+     * @param subId The subId of the subscription used for receiving datagrams.
+     * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request.
+     *
+     * @throws SecurityException if the caller doesn't have required permission.
+     */
+    @Override
+    public void pollPendingSatelliteDatagrams(int subId, IIntegerConsumer callback) {
+        enforceSatelliteCommunicationPermission("pollPendingSatelliteDatagrams");
+        mSatelliteController.pollPendingSatelliteDatagrams(subId, callback);
+    }
+
+    /**
+     * Send datagram over satellite.
+     *
+     * Gateway encodes SOS message or location sharing message into a datagram and passes it as
+     * input to this method. Datagram received here will be passed down to modem without any
+     * encoding or encryption.
+     *
+     * @param subId The subId of the subscription to send satellite datagrams for.
+     * @param datagramType datagram type indicating whether the datagram is of type
+     *                     SOS_SMS or LOCATION_SHARING.
+     * @param datagram encoded gateway datagram which is encrypted by the caller.
+     *                 Datagram will be passed down to modem without any encoding or encryption.
+     * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in
+     *                                 full screen mode.
+     * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request.
+     *
+     * @throws SecurityException if the caller doesn't have required permission.
+     */
+    @Override
+    public void sendSatelliteDatagram(int subId, @SatelliteManager.DatagramType int datagramType,
+            @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI,
+            @NonNull IIntegerConsumer callback) {
+        enforceSatelliteCommunicationPermission("sendSatelliteDatagram");
+        mSatelliteController.sendSatelliteDatagram(subId, datagramType, datagram,
+                needFullScreenPointingUI, callback);
+    }
+
+    /**
+     * Request to get whether satellite communication is allowed for the current location.
+     *
+     * @param subId The subId of the subscription to check whether satellite communication is
+     *              allowed for the current location for.
+     * @param result The result receiver that returns whether satellite communication is allowed
+     *               for the current location if the request is successful or an error code
+     *               if the request failed.
+     *
+     * @throws SecurityException if the caller doesn't have the required permission.
+     */
+    @Override
+    public void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId,
+            @NonNull ResultReceiver result) {
+        enforceSatelliteCommunicationPermission(
+                "requestIsSatelliteCommunicationAllowedForCurrentLocation");
+        mSatelliteController.requestIsSatelliteCommunicationAllowedForCurrentLocation(subId,
+                result);
+    }
+
+    /**
+     * Request to get the time after which the satellite will be visible
+     *
+     * @param subId The subId to get the time after which the satellite will be visible for.
+     * @param result The result receiver that returns the time after which the satellite will
+     *               be visible if the request is successful or an error code if the request failed.
+     *
+     * @throws SecurityException if the caller doesn't have the required permission.
+     */
+    @Override
+    public void requestTimeForNextSatelliteVisibility(int subId, @NonNull ResultReceiver result) {
+        enforceSatelliteCommunicationPermission("requestTimeForNextSatelliteVisibility");
+        mSatelliteController.requestTimeForNextSatelliteVisibility(subId, result);
+    }
+
+    private Phone getPhoneOrDefault(int subId, String caller) {
         Phone phone = getPhone(subId);
         if (phone == null) {
-            loge("getMaxCharactersPerSatelliteTextMessage called with invalid subId: " + subId
-                    + ".Retrying with default phone.");
+            loge(caller + " called with invalid subId: " + subId
+                    + ". Retrying with default phone.");
             phone = getDefaultPhone();
             if (phone == null) {
-                loge("getMaxCharactersPerSatelliteTextMessage failed with no phone object.");
-                return SatelliteManager.SATELLITE_SERVICE_TELEPHONY_INTERNAL_ERROR;
+                loge(caller + " failed with no phone object.");
             }
         }
-
-        Consumer<Integer> argument = FunctionalUtils.ignoreRemoteException(callback::accept);
-        int result = (int) sendRequest(CMD_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG, argument, subId);
-        if (DBG) log("getMaxCharPerTextMessageOnSatellite result: " + result);
-        return result;
+        return phone;
     }
 
     /**
@@ -12371,18 +12497,10 @@
     }
 
     /**
-     * Check if satellite is enabled for a subscription.
+     * @return The subscription manager service instance.
      */
-    private boolean isSatelliteEnabled(int subId) {
-        if (mSubscriptionController != null) {
-            String strResult = mSubscriptionController.getSubscriptionProperty(
-                    subId, SubscriptionManager.SATELLITE_ENABLED);
-            if (strResult != null) {
-                int intResult = Integer.parseInt(strResult);
-                return (intResult == 1) ? true : false;
-            }
-        }
-        return false;
+    public SubscriptionManagerService getSubscriptionManagerService() {
+        return SubscriptionManagerService.getInstance();
     }
 
     /**
@@ -12405,4 +12523,4 @@
             return mCarrierId;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index 5f14387..4826d2b 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -713,11 +713,11 @@
         // an emergency-only account
         String id = isEmergency ? EMERGENCY_ACCOUNT_HANDLE_ID : prefix +
                 String.valueOf(phone.getSubId());
-        return makePstnPhoneAccountHandleWithPrefix(id, prefix, isEmergency, userHandle);
+        return makePstnPhoneAccountHandleWithId(id, userHandle);
     }
 
-    public static PhoneAccountHandle makePstnPhoneAccountHandleWithPrefix(
-            String id, String prefix, boolean isEmergency, UserHandle userHandle) {
+    public static PhoneAccountHandle makePstnPhoneAccountHandleWithId(
+            String id, UserHandle userHandle) {
         ComponentName pstnConnectionServiceName = getPstnConnectionServiceName();
         // If user handle is null, resort to default constructor to use phone process's
         // user handle
diff --git a/src/com/android/phone/TimeConsumingPreferenceActivity.java b/src/com/android/phone/TimeConsumingPreferenceActivity.java
index d21f6a8..1fe548c 100644
--- a/src/com/android/phone/TimeConsumingPreferenceActivity.java
+++ b/src/com/android/phone/TimeConsumingPreferenceActivity.java
@@ -192,7 +192,12 @@
         if (mIsForeground) {
             showDialog(error);
         }
-        preference.setEnabled(false);
+
+        //If the error is due to RESPONSE_ERROR, do not disable the item so end user
+        //can continue to interact with it.
+        if (error != RESPONSE_ERROR) {
+            preference.setEnabled(false);
+        }
     }
 
     @Override
diff --git a/src/com/android/phone/slice/PremiumNetworkEntitlementApi.java b/src/com/android/phone/slice/PremiumNetworkEntitlementApi.java
index 2546023..8288c43 100644
--- a/src/com/android/phone/slice/PremiumNetworkEntitlementApi.java
+++ b/src/com/android/phone/slice/PremiumNetworkEntitlementApi.java
@@ -45,7 +45,7 @@
     private static final String ENTITLEMENT_STATUS_KEY = "EntitlementStatus";
     private static final String PROVISION_STATUS_KEY = "ProvStatus";
     private static final String SERVICE_FLOW_URL_KEY = "ServiceFlow_URL";
-    private static final String PROVISION_TIME_LEFT_KEY = "ProvisionTimeLeft";
+    private static final String SERVICE_FLOW_USERDATA_KEY = "ServiceFlow_UserData";
     private static final String DEFAULT_EAP_AKA_RESPONSE = "Default EAP AKA response";
     /**
      * UUID to report an anomaly if an unexpected error is received during entitlement check.
@@ -100,8 +100,7 @@
         requestBuilder.setTerminalModel("modelY");
         requestBuilder.setTerminalSoftwareVersion("versionZ");
         requestBuilder.setAcceptContentType(ServiceEntitlementRequest.ACCEPT_CONTENT_TYPE_JSON);
-        requestBuilder.setNetworkIdentifier(
-                TelephonyManager.convertPremiumCapabilityToString(capability));
+        requestBuilder.setBoostType(getBoostTypeFromPremiumCapability(capability));
         ServiceEntitlementRequest request = requestBuilder.build();
         PremiumNetworkEntitlementResponse premiumNetworkEntitlementResponse =
                 new PremiumNetworkEntitlementResponse();
@@ -109,7 +108,7 @@
         String response = null;
         try {
             response = mServiceEntitlement.queryEntitlementStatus(
-                    ServiceEntitlement.APP_PREMIUM_NETWORK_SLICE,
+                    ServiceEntitlement.APP_DATA_PLAN_BOOST,
                     request);
         } catch (ServiceEntitlementException e) {
             Log.e(TAG, "queryEntitlementStatus failed", e);
@@ -123,10 +122,9 @@
             JSONObject jsonAuthResponse = new JSONObject(response);
             String entitlementStatus = null;
             String provisionStatus = null;
-            String provisionTimeLeft = null;
-            if (jsonAuthResponse.has(ServiceEntitlement.APP_PREMIUM_NETWORK_SLICE)) {
+            if (jsonAuthResponse.has(ServiceEntitlement.APP_DATA_PLAN_BOOST)) {
                 JSONObject jsonToken = jsonAuthResponse.getJSONObject(
-                        ServiceEntitlement.APP_PREMIUM_NETWORK_SLICE);
+                        ServiceEntitlement.APP_DATA_PLAN_BOOST);
                 if (jsonToken.has(ENTITLEMENT_STATUS_KEY)) {
                     entitlementStatus = jsonToken.getString(ENTITLEMENT_STATUS_KEY);
                     if (entitlementStatus == null) {
@@ -142,20 +140,17 @@
                                 Integer.parseInt(provisionStatus);
                     }
                 }
-                if (jsonToken.has(PROVISION_TIME_LEFT_KEY)) {
-                    provisionTimeLeft = jsonToken.getString(PROVISION_TIME_LEFT_KEY);
-                    if (provisionTimeLeft != null) {
-                        premiumNetworkEntitlementResponse.mProvisionTimeLeft =
-                                Integer.parseInt(provisionTimeLeft);
-                    }
-                }
                 if (jsonToken.has(SERVICE_FLOW_URL_KEY)) {
                     premiumNetworkEntitlementResponse.mServiceFlowURL =
                             jsonToken.getString(SERVICE_FLOW_URL_KEY);
                 }
+                if (jsonToken.has(SERVICE_FLOW_USERDATA_KEY)) {
+                    premiumNetworkEntitlementResponse.mServiceFlowUserData =
+                            jsonToken.getString(SERVICE_FLOW_USERDATA_KEY);
+                }
+            } else {
+                Log.e(TAG, "queryEntitlementStatus failed with no app");
             }
-
-
         } catch (JSONException e) {
             Log.e(TAG, "queryEntitlementStatus failed", e);
             reportAnomaly(UUID_ENTITLEMENT_CHECK_UNEXPECTED_ERROR,
@@ -194,4 +189,12 @@
         return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TELEPHONY,
                 BYPASS_EAP_AKA_AUTH_FOR_SLICE_PURCHASE_ENABLED, false);
     }
+
+    @NonNull private String getBoostTypeFromPremiumCapability(
+            @TelephonyManager.PremiumCapability int capability) {
+        if (capability == TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY) {
+            return "0" /* REALTIME_INTERACTIVE_TRAFFIC */;
+        }
+        return "";
+    }
 }
diff --git a/src/com/android/phone/slice/PremiumNetworkEntitlementResponse.java b/src/com/android/phone/slice/PremiumNetworkEntitlementResponse.java
index 4e63e35..242ca69 100644
--- a/src/com/android/phone/slice/PremiumNetworkEntitlementResponse.java
+++ b/src/com/android/phone/slice/PremiumNetworkEntitlementResponse.java
@@ -30,40 +30,39 @@
     public static final int PREMIUM_NETWORK_ENTITLEMENT_STATUS_PROVISIONING = 3;
     public static final int PREMIUM_NETWORK_ENTITLEMENT_STATUS_INCLUDED = 4;
 
-    @IntDef(prefix = {"PREMIUM_NETWORK_ENTITLEMENT_STATUS_"},
-            value = {
-                    PREMIUM_NETWORK_ENTITLEMENT_STATUS_DISABLED,
-                    PREMIUM_NETWORK_ENTITLEMENT_STATUS_ENABLED,
-                    PREMIUM_NETWORK_ENTITLEMENT_STATUS_INCOMPATIBLE,
-                    PREMIUM_NETWORK_ENTITLEMENT_STATUS_PROVISIONING,
-                    PREMIUM_NETWORK_ENTITLEMENT_STATUS_INCLUDED
-            })
+    @IntDef(prefix = {"PREMIUM_NETWORK_ENTITLEMENT_STATUS_"}, value = {
+            PREMIUM_NETWORK_ENTITLEMENT_STATUS_DISABLED,
+            PREMIUM_NETWORK_ENTITLEMENT_STATUS_ENABLED,
+            PREMIUM_NETWORK_ENTITLEMENT_STATUS_INCOMPATIBLE,
+            PREMIUM_NETWORK_ENTITLEMENT_STATUS_PROVISIONING,
+            PREMIUM_NETWORK_ENTITLEMENT_STATUS_INCLUDED
+    })
     public @interface PremiumNetworkEntitlementStatus {}
 
     public static final int PREMIUM_NETWORK_PROVISION_STATUS_NOT_PROVISIONED = 0;
     public static final int PREMIUM_NETWORK_PROVISION_STATUS_PROVISIONED = 1;
-    public static final int PREMIUM_NETWORK_PROVISION_STATUS_NOT_REQUIRED = 2;
+    public static final int PREMIUM_NETWORK_PROVISION_STATUS_NOT_AVAILABLE = 2;
     public static final int PREMIUM_NETWORK_PROVISION_STATUS_IN_PROGRESS = 3;
 
-    @IntDef(prefix = {"PREMIUM_NETWORK_PROVISION_STATUS_"},
-            value = {
-                    PREMIUM_NETWORK_PROVISION_STATUS_NOT_PROVISIONED,
-                    PREMIUM_NETWORK_PROVISION_STATUS_PROVISIONED,
-                    PREMIUM_NETWORK_PROVISION_STATUS_NOT_REQUIRED,
-                    PREMIUM_NETWORK_PROVISION_STATUS_IN_PROGRESS
-            })
+    @IntDef(prefix = {"PREMIUM_NETWORK_PROVISION_STATUS_"}, value = {
+            PREMIUM_NETWORK_PROVISION_STATUS_NOT_PROVISIONED,
+            PREMIUM_NETWORK_PROVISION_STATUS_PROVISIONED,
+            PREMIUM_NETWORK_PROVISION_STATUS_NOT_AVAILABLE,
+            PREMIUM_NETWORK_PROVISION_STATUS_IN_PROGRESS
+    })
     public @interface PremiumNetworkProvisionStatus {}
 
     @PremiumNetworkEntitlementStatus public int mEntitlementStatus;
     @PremiumNetworkProvisionStatus public int mProvisionStatus;
-    public int mProvisionTimeLeft;
     @NonNull public String mServiceFlowURL;
+    @NonNull public String mServiceFlowUserData;
 
     /**
      * @return {@code true} if the premium network is provisioned and {@code false} otherwise.
      */
     public boolean isProvisioned() {
         return mProvisionStatus == PREMIUM_NETWORK_PROVISION_STATUS_PROVISIONED
+                || mEntitlementStatus == PREMIUM_NETWORK_ENTITLEMENT_STATUS_ENABLED
                 || mEntitlementStatus == PREMIUM_NETWORK_ENTITLEMENT_STATUS_INCLUDED;
     }
 
@@ -83,7 +82,10 @@
     public boolean isPremiumNetworkCapabilityAllowed() {
         switch (mEntitlementStatus) {
             case PREMIUM_NETWORK_ENTITLEMENT_STATUS_INCOMPATIBLE:
-            case PREMIUM_NETWORK_ENTITLEMENT_STATUS_DISABLED:
+                return false;
+        }
+        switch (mProvisionStatus) {
+            case PREMIUM_NETWORK_PROVISION_STATUS_NOT_AVAILABLE:
                 return false;
         }
         return true;
diff --git a/src/com/android/services/telephony/ConferenceParticipantConnection.java b/src/com/android/services/telephony/ConferenceParticipantConnection.java
index 92e95cc..8179817 100644
--- a/src/com/android/services/telephony/ConferenceParticipantConnection.java
+++ b/src/com/android/services/telephony/ConferenceParticipantConnection.java
@@ -17,14 +17,19 @@
 package com.android.services.telephony;
 
 import android.net.Uri;
+import android.os.PersistableBundle;
 import android.telecom.Connection;
 import android.telecom.DisconnectCause;
+import android.telecom.PhoneAccount;
+import android.telephony.CarrierConfigManager;
+import android.telephony.PhoneNumberUtils;
 import android.telephony.SubscriptionInfo;
 import android.text.TextUtils;
 
 import com.android.ims.internal.ConferenceParticipant;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
+import com.android.phone.PhoneGlobals;
 import com.android.telephony.Rlog;
 
 import java.util.Locale;
@@ -36,6 +41,9 @@
 
     private static final String LOG_TAG = "ConferenceParticipantConnection";
 
+    private static final String JAPAN_COUNTRY_CODE_WITH_PLUS_SIGN = "+81";
+    private static final String JAPAN_ISO_COUNTRY_CODE = "JP";
+
     /**
      * The user entity URI For the conference participant.
      */
@@ -70,9 +78,19 @@
         if (presentation != PhoneConstants.PRESENTATION_ALLOWED) {
             address = null;
         } else {
-            String countryIso = getCountryIso(parentConnection.getCall().getPhone());
+            Phone phone = parentConnection.getCall().getPhone();
+            String countryIso = getCountryIso(phone);
             address = ConferenceParticipant.getParticipantAddress(participant.getHandle(),
                     countryIso);
+            if (address != null
+                    && isNeedParticipantPhoneNumberToNationalFormatForJp(phone, address)) {
+                String number = PhoneNumberUtils.stripSeparators(
+                        PhoneNumberUtils.formatNumber(address.getSchemeSpecificPart(),
+                        JAPAN_ISO_COUNTRY_CODE));
+                if (number != null) {
+                    address = Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null);
+                }
+            }
         }
         setAddress(address, presentation);
         setVideoState(parentConnection.getVideoState());
@@ -195,6 +213,22 @@
     }
 
     /**
+     * Whether the Conference call participant number should be formatted to national number for
+     * Japan.
+     * @return {@code true} should be convert to the national format, {@code false} otherwise.
+     */
+    private boolean isNeedParticipantPhoneNumberToNationalFormatForJp(Phone phone, Uri uri) {
+        if (phone == null || uri == null) {
+            return false;
+        }
+        PersistableBundle bundle = PhoneGlobals.getInstance().getCarrierConfigForSubId(
+                phone.getSubId());
+        return bundle != null && bundle.getBoolean(
+                CarrierConfigManager.KEY_FORMAT_INCOMING_NUMBER_TO_NATIONAL_FOR_JP_BOOL)
+                && uri.getSchemeSpecificPart().startsWith(JAPAN_COUNTRY_CODE_WITH_PLUS_SIGN);
+    }
+
+    /**
      * Builds a string representation of this conference participant connection.
      *
      * @return String representation of connection.
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index c62b4fa..654fb93 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -980,23 +980,25 @@
             // event package; some carriers are known to keep a disconnected participant around in
             // subsequent CEP updates with a state of disconnected, even though its no longer part
             // of the conference.
-            // Note: We consider 0 to still be a single party conference since some carriers will
-            // send a conference event package with JUST the host in it when the conference is
-            // disconnected.  We don't want to change back to conference mode prior to disconnection
-            // or we will not log the call.
-            boolean isSinglePartyConference = participants.stream()
+            final long numActiveCepParticipantsOtherThanHost = participants.stream()
                     .filter(p -> {
                         Pair<Uri, Uri> pIdent = new Pair<>(p.getHandle(), p.getEndpoint());
                         return !Objects.equals(mHostParticipantIdentity, pIdent)
                                 && p.getState() != Connection.STATE_DISCONNECTED;
                     })
-                    .count() <= 1;
+                    .count();
+            // We consider 0 to still be a single party conference since some carriers
+            // will send a conference event package with JUST the host in it when the conference
+            // is disconnected.  We don't want to change back to conference mode prior to
+            // disconnection or we will not log the call.
+            final boolean isCepForSinglePartyConference =
+                    numActiveCepParticipantsOtherThanHost <= 1;
 
             // We will only process the CEP data if:
             // 1. We're not emulating a single party call.
             // 2. We're emulating a single party call and the CEP contains more than just the
             //    single party
-            if ((!isMultiparty() && !isSinglePartyConference)
+            if ((!isMultiparty() && !isCepForSinglePartyConference)
                     || isMultiparty()) {
                 // Add any new participants and update existing.
                 for (ConferenceParticipant participant : participants) {
@@ -1082,15 +1084,17 @@
 
             int newParticipantCount = mConferenceParticipantConnections.size();
             Log.v(this, "handleConferenceParticipantsUpdate: oldParticipantCount=%d, "
-                            + "newParticipantcount=%d", oldParticipantCount, newParticipantCount);
-            // If the single party call emulation fature flag is enabled, we can potentially treat
+                            + "newParticipantCount=%d, isMultiPty=%b, cepParticipantCt=%d",
+                    oldParticipantCount, newParticipantCount, isMultiparty(),
+                    numActiveCepParticipantsOtherThanHost);
+            // If the single party call emulation feature flag is enabled, we can potentially treat
             // the conference as a single party call when there is just one participant.
             if (mFeatureFlagProxy.isUsingSinglePartyCallEmulation() &&
                     !mConferenceHost.isAdhocConferenceCall()) {
                 if (oldParticipantCount != 1 && newParticipantCount == 1) {
                     // If number of participants goes to 1, emulate a single party call.
                     startEmulatingSinglePartyCall();
-                } else if (!isMultiparty() && !isSinglePartyConference) {
+                } else if (!isMultiparty() && !isCepForSinglePartyConference) {
                     // Number of participants increased, so stop emulating a single party call.
                     stopEmulatingSinglePartyCall();
                 }
@@ -1108,8 +1112,8 @@
                     // OR if the conference had a single participant and is emulating a standalone
                     // call.
                     && (oldParticipantCount > 0 || !isMultiparty())
-                    // AND the CEP says there is nobody left any more.
-                    && newParticipantCount == 0) {
+                    // AND the CEP says there is nobody left anymore.
+                    && numActiveCepParticipantsOtherThanHost == 0) {
                 Log.i(this, "handleConferenceParticipantsUpdate: empty conference; "
                         + "local disconnect.");
                 onDisconnect();
diff --git a/src/com/android/services/telephony/ImsConferenceController.java b/src/com/android/services/telephony/ImsConferenceController.java
index 7cf9415..4200904 100644
--- a/src/com/android/services/telephony/ImsConferenceController.java
+++ b/src/com/android/services/telephony/ImsConferenceController.java
@@ -16,6 +16,7 @@
 
 package com.android.services.telephony;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.os.PersistableBundle;
 import android.telecom.Conference;
@@ -26,17 +27,17 @@
 import android.telecom.PhoneAccountHandle;
 import android.telephony.CarrierConfigManager;
 
-import com.android.telephony.Rlog;
-
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.phone.PhoneUtils;
+import com.android.telephony.Rlog;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 /**
@@ -220,14 +221,33 @@
         recalculateConference();
     }
 
+    private PhoneAccountHandle getPhoneAccountHandle(@NonNull Conferenceable c) {
+        if (c instanceof Connection) {
+            Connection connection = (Connection) c;
+            return connection.getPhoneAccountHandle();
+        } else if (c instanceof Conference) {
+            Conference conference = (Conference) c;
+            return conference.getPhoneAccountHandle();
+        }
+        throw new IllegalArgumentException("Unrecognized Conferenceable!" + c);
+    }
+
+    private boolean isSamePhoneAccountHandle(
+            @NonNull Conferenceable left, @NonNull Conferenceable right) {
+        PhoneAccountHandle leftHandle = getPhoneAccountHandle(left);
+        PhoneAccountHandle rightHandle = getPhoneAccountHandle(right);
+        return Objects.equals(leftHandle, rightHandle);
+    }
+
     /**
      * Calculates the conference-capable state of all GSM connections in this connection service.
+     * Connections from different {@link PhoneAccountHandle}s shall not be conferenceable.
      */
     private void recalculateConferenceable() {
         Log.v(this, "recalculateConferenceable : %d", mTelephonyConnections.size());
         HashSet<Conferenceable> conferenceableSet = new HashSet<>(mTelephonyConnections.size() +
                 mImsConferences.size());
-        HashSet<Conferenceable> conferenceParticipantsSet = new HashSet<>();
+        HashSet<Connection> conferenceParticipantsSet = new HashSet<>();
 
         // Loop through and collect all calls which are active or holding
         for (TelephonyConnection connection : mTelephonyConnections) {
@@ -300,11 +320,6 @@
 
         for (Conferenceable c : conferenceableSet) {
             if (c instanceof Connection) {
-                // Remove this connection from the Set and add all others
-                List<Conferenceable> conferenceables = conferenceableSet
-                        .stream()
-                        .filter(conferenceable -> c != conferenceable)
-                        .collect(Collectors.toList());
                 // TODO: Remove this once RemoteConnection#setConferenceableConnections is fixed.
                 // Add all conference participant connections as conferenceable with a standalone
                 // Connection.  We need to do this to ensure that RemoteConnections work properly.
@@ -313,7 +328,18 @@
                 // into the conference.
                 // We should add support for RemoteConnection#setConferenceables, which accepts a
                 // list of remote conferences and connections in the future.
-                conferenceables.addAll(conferenceParticipantsSet);
+                List<Conferenceable> conferenceables = conferenceParticipantsSet
+                        .stream()
+                        // Removes conference participants from different PhoneAccountHandles.
+                        .filter(connection -> isSamePhoneAccountHandle(c, connection))
+                        .collect(Collectors.toCollection(ArrayList::new));
+
+                // Removes this connection from the Set and add all others. Removes conferenceables
+                // from different PhoneAccountHandles.
+                conferenceables.addAll(conferenceableSet
+                        .stream()
+                        .filter(conferenceable -> c != conferenceable
+                                && isSamePhoneAccountHandle(c, conferenceable)).toList());
 
                 ((Connection) c).setConferenceables(conferenceables);
             } else if (c instanceof ImsConference) {
@@ -325,10 +351,11 @@
                 }
 
                 // Remove all conferences from the set, since we can not conference a conference
-                // to another conference.
+                // to another conference. Removes connections from different PhoneAccountHandles.
                 List<Connection> connections = conferenceableSet
                         .stream()
-                        .filter(conferenceable -> conferenceable instanceof Connection)
+                        .filter(conferenceable -> conferenceable instanceof Connection
+                                && isSamePhoneAccountHandle(c, conferenceable))
                         .map(conferenceable -> (Connection) conferenceable)
                         .collect(Collectors.toList());
                 // Conference equivalent to setConferenceables that only accepts Connections
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 6650eac..57e65ee 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -1593,9 +1593,8 @@
                         int subscriptionId = phone.getSubId();
                         Log.i(this, "setupAccounts: Phone with subscription id %d", subscriptionId);
                         // setupAccounts can be called multiple times during service changes.
-                        // Don't add an account if the Icc has not been set yet.
-                        if (!SubscriptionManager.isValidSubscriptionId(subscriptionId)
-                                || phone.getFullIccSerialNumber() == null) {
+                        // Don't add an account if subscription is not ready.
+                        if (!SubscriptionManager.isValidSubscriptionId(subscriptionId)) {
                             Log.d(this, "setupAccounts: skipping invalid subid %d", subscriptionId);
                             continue;
                         }
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index e278240..9f248b7 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -16,6 +16,10 @@
 
 package com.android.services.telephony;
 
+import static android.telephony.ims.ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED;
+import static android.telephony.ims.ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL;
+import static android.telephony.ims.ImsReasonInfo.EXTRA_CODE_CALL_RETRY_EMERGENCY;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ContentResolver;
@@ -1326,6 +1330,8 @@
                     if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
                         ImsPhone imsPhone = (ImsPhone) phone;
                         imsPhone.holdActiveCall();
+                        mTelephonyConnectionService.maybeUnholdCallsOnOtherSubs(
+                                getPhoneAccountHandle());
                         return;
                     }
                     phone.switchHoldingAndActive();
@@ -2481,13 +2487,25 @@
                             ImsPhoneConnection imsPhoneConnection =
                                     (ImsPhoneConnection) mOriginalConnection;
                             reasonInfo = imsPhoneConnection.getImsReasonInfo();
-                            if (reasonInfo != null && reasonInfo.getCode()
-                                    == ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL) {
-                                EmergencyNumber emergencyNumber =
-                                        imsPhoneConnection.getEmergencyNumberInfo();
-                                if (emergencyNumber != null) {
-                                    mEmergencyServiceCategory =
-                                            emergencyNumber.getEmergencyServiceCategoryBitmask();
+                            if (reasonInfo != null) {
+                                int reasonCode = reasonInfo.getCode();
+                                int extraCode = reasonInfo.getExtraCode();
+                                if ((reasonCode == CODE_SIP_ALTERNATE_EMERGENCY_CALL)
+                                        || (reasonCode == CODE_LOCAL_CALL_CS_RETRY_REQUIRED
+                                                && extraCode == EXTRA_CODE_CALL_RETRY_EMERGENCY)) {
+                                    EmergencyNumber numberInfo =
+                                            imsPhoneConnection.getEmergencyNumberInfo();
+                                    if (numberInfo != null) {
+                                        mEmergencyServiceCategory =
+                                                numberInfo.getEmergencyServiceCategoryBitmask();
+                                    } else {
+                                        Log.i(this, "mEmergencyServiceCategory no EmergencyNumber");
+                                    }
+
+                                    if (mEmergencyServiceCategory != null) {
+                                        Log.i(this, "mEmergencyServiceCategory="
+                                                + mEmergencyServiceCategory);
+                                    }
                                 }
                             }
                         }
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 8253f71..7311113 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -32,7 +32,9 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.ParcelUuid;
+import android.provider.DeviceConfig;
 import android.telecom.Conference;
+import android.telecom.Conferenceable;
 import android.telecom.Connection;
 import android.telecom.ConnectionRequest;
 import android.telecom.ConnectionService;
@@ -81,6 +83,7 @@
 import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.imsphone.ImsPhoneConnection;
 import com.android.internal.telephony.imsphone.ImsPhoneMmiCode;
+import com.android.internal.telephony.satellite.SatelliteSOSMessageRecommender;
 import com.android.internal.telephony.subscription.SubscriptionInfoInternal;
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
 import com.android.phone.FrameworksUtils;
@@ -118,6 +121,12 @@
     // from the modem.
     private static final int DEFAULT_DATA_SWITCH_TIMEOUT_MS = 1000;
 
+    // Timeout before we terminate the outgoing DSDA call if HOLD did not complete in time on the
+    // existing call.
+    private static final int DEFAULT_DSDA_OUTGOING_CALL_HOLD_TIMEOUT_MS = 1000;
+    private static final String KEY_DOMAIN_COMPARE_FEATURE_ENABLED_FLAG =
+            "is_domain_selection_compare_feature_enabled";
+
     // If configured, reject attempts to dial numbers matching this pattern.
     private static final Pattern CDMA_ACTIVATION_CODE_REGEX_PATTERN =
             Pattern.compile("\\*228[0-9]{0,2}");
@@ -134,6 +143,12 @@
         }
         @Override
         public void addConference(ImsConference mImsConference) {
+            Connection conferenceHost = mImsConference.getConferenceHost();
+            if (conferenceHost instanceof TelephonyConnection) {
+                TelephonyConnection tcConferenceHost = (TelephonyConnection) conferenceHost;
+                tcConferenceHost.setTelephonyConnectionService(TelephonyConnectionService.this);
+                tcConferenceHost.setPhoneAccountHandle(mImsConference.getPhoneAccountHandle());
+            }
             TelephonyConnectionService.this.addTelephonyConference(mImsConference);
         }
         @Override
@@ -195,6 +210,7 @@
     public Pair<WeakReference<TelephonyConnection>, Queue<Phone>> mEmergencyRetryCache;
     private DeviceState mDeviceState = new DeviceState();
     private EmergencyStateTracker mEmergencyStateTracker;
+    private SatelliteSOSMessageRecommender mSatelliteSOSMessageRecommender;
     private DomainSelectionResolver mDomainSelectionResolver;
     private EmergencyCallDomainSelectionConnection mEmergencyCallDomainSelectionConnection;
     private TelephonyConnection mEmergencyConnection;
@@ -543,19 +559,48 @@
                 }
 
                 @Override
-        public void onStateChanged(Connection connection, @Connection.ConnectionState int state) {
-            if (connection != null) {
-                TelephonyConnection c = (TelephonyConnection) connection;
-                Log.i(this, "onStateChanged callId=" + c.getTelecomCallId() + ", state=" + state);
-                if (c.getState() == Connection.STATE_ACTIVE) {
-                    mEmergencyStateTracker.onEmergencyCallStateChanged(
-                            c.getOriginalConnection().getState(), c.getTelecomCallId());
-                    c.removeTelephonyConnectionListener(mEmergencyConnectionListener);
-                    releaseEmergencyCallDomainSelection(false);
+                public void onStateChanged(Connection connection,
+                        @Connection.ConnectionState int state) {
+                    if (mEmergencyCallDomainSelectionConnection == null) return;
+                    if (connection == null) return;
+                    TelephonyConnection c = (TelephonyConnection) connection;
+                    Log.i(this, "onStateChanged callId=" + c.getTelecomCallId()
+                            + ", state=" + state);
+                    if (c.getState() == Connection.STATE_ACTIVE) {
+                        mEmergencyStateTracker.onEmergencyCallStateChanged(
+                                c.getOriginalConnection().getState(), c.getTelecomCallId());
+                        releaseEmergencyCallDomainSelection(false);
+                    }
                 }
-            }
-        }
-    };
+            };
+
+    private final TelephonyConnection.TelephonyConnectionListener
+            mEmergencyConnectionSatelliteListener =
+            new TelephonyConnection.TelephonyConnectionListener() {
+                @Override
+                public void onStateChanged(Connection connection,
+                        @Connection.ConnectionState int state) {
+                    if (connection == null) {
+                        Log.d(this,
+                                "onStateChanged for satellite listener: connection is null");
+                        return;
+                    }
+                    if (mSatelliteSOSMessageRecommender == null) {
+                        Log.d(this, "onStateChanged for satellite listener: "
+                                + "mSatelliteSOSMessageRecommender is null");
+                        return;
+                    }
+
+                    TelephonyConnection c = (TelephonyConnection) connection;
+                    mSatelliteSOSMessageRecommender.onEmergencyCallConnectionStateChanged(
+                            c.getTelecomCallId(), state);
+                    if (state == Connection.STATE_DISCONNECTED
+                            || state == Connection.STATE_ACTIVE) {
+                        c.removeTelephonyConnectionListener(mEmergencyConnectionSatelliteListener);
+                        mSatelliteSOSMessageRecommender = null;
+                    }
+                }
+            };
 
     /**
      * A listener for calls.
@@ -588,43 +633,74 @@
                 }
             };
 
+    private static class StateHoldingListener extends
+            TelephonyConnection.TelephonyConnectionListener {
+        private final CompletableFuture<Boolean> mStateHoldingFuture;
+
+        StateHoldingListener(CompletableFuture<Boolean> future) {
+            mStateHoldingFuture = future;
+        }
+
+        @Override
+        public void onStateChanged(
+                Connection connection, @Connection.ConnectionState int state) {
+            TelephonyConnection c = (TelephonyConnection) connection;
+            if (c != null) {
+                switch (c.getState()) {
+                    case Connection.STATE_HOLDING: {
+                        Log.d(LOG_TAG, "Connection " + connection
+                                + " changed to STATE_HOLDING!");
+                        mStateHoldingFuture.complete(true);
+                        c.removeTelephonyConnectionListener(this);
+                    }
+                    break;
+                    case Connection.STATE_DISCONNECTED: {
+                        Log.d(LOG_TAG, "Connection " + connection
+                                + " changed to STATE_DISCONNECTED!");
+                        mStateHoldingFuture.complete(false);
+                        c.removeTelephonyConnectionListener(this);
+                    }
+                    break;
+                }
+            }
+        }
+    }
+
     private final DomainSelectionConnection.DomainSelectionConnectionCallback
             mEmergencyDomainSelectionConnectionCallback =
                     new DomainSelectionConnection.DomainSelectionConnectionCallback() {
         @Override
         public void onSelectionTerminated(@DisconnectCauses int cause) {
-            if (mEmergencyCallDomainSelectionConnection != null) {
+            mDomainSelectionMainExecutor.execute(() -> {
                 Log.i(this, "onSelectionTerminated cause=" + cause);
+                if (mEmergencyCallDomainSelectionConnection == null) {
+                    Log.i(this, "onSelectionTerminated no DomainSelectionConnection");
+                    return;
+                }
 
                 // Cross stack redial
                 if (cause == android.telephony.DisconnectCause.EMERGENCY_TEMP_FAILURE
                         || cause == android.telephony.DisconnectCause.EMERGENCY_PERM_FAILURE) {
                     if (mEmergencyConnection != null) {
-                        final boolean isPermanentFailure =
+                        boolean isPermanentFailure =
                                 cause == android.telephony.DisconnectCause.EMERGENCY_PERM_FAILURE;
-                        Log.i(this, "onSelectionTerminated trigger cross stack redial"
-                                + " permanent=" + isPermanentFailure);
-                        mDomainSelectionMainExecutor.execute(() -> {
-                            Log.i(this, "onSelectionTerminated execute cross stack redial"
-                                    + " permanent=" + isPermanentFailure);
-                            TelephonyConnection c = mEmergencyConnection;
-                            Phone phone = mEmergencyCallDomainSelectionConnection.getPhone();
-                            mEmergencyConnection.removeTelephonyConnectionListener(
-                                    mEmergencyConnectionListener);
-                            mEmergencyStateTracker.endCall(
-                                    mEmergencyConnection.getTelecomCallId());
-                            releaseEmergencyCallDomainSelection(true);
-                            retryOutgoingOriginalConnection(c, phone, isPermanentFailure);
-                        });
+                        Log.i(this, "onSelectionTerminated permanent=" + isPermanentFailure);
+                        TelephonyConnection c = mEmergencyConnection;
+                        Phone phone = mEmergencyCallDomainSelectionConnection.getPhone();
+                        mEmergencyConnection.removeTelephonyConnectionListener(
+                                mEmergencyConnectionListener);
+                        releaseEmergencyCallDomainSelection(true);
+                        mEmergencyStateTracker.endCall(mEmergencyCallId);
+                        mEmergencyCallId = null;
+                        retryOutgoingOriginalConnection(c, phone, isPermanentFailure);
                         return;
                     }
                 }
-                mEmergencyCallDomainSelectionConnection = null;
                 if (mEmergencyConnection != null) {
                     mEmergencyConnection.hangup(android.telephony.DisconnectCause.OUT_OF_NETWORK);
                     mEmergencyConnection = null;
                 }
-            }
+            });
         }
     };
 
@@ -1074,6 +1150,21 @@
                     }
                     return resultConnection;
                 } else {
+                    if (mTelephonyManagerProxy.isConcurrentCallsPossible()) {
+                        delayDialForOtherSubHold(phone, request.getAccountHandle(), (result) -> {
+                            Log.d(this,
+                                    "onCreateOutgoingConn - delayDialForOtherSubHold result = "
+                                            + result);
+                            if (result) {
+                                placeOutgoingConnection(request, resultConnection, phone);
+                            } else {
+                                ((TelephonyConnection) resultConnection).hangup(
+                                        android.telephony.DisconnectCause.LOCAL);
+                            }
+                        });
+                        return resultConnection;
+                    }
+                    // The standard case.
                     return placeOutgoingConnection(request, resultConnection, phone);
                 }
             } else {
@@ -1950,12 +2041,14 @@
                         }
                     });
         }
+
         final com.android.internal.telephony.Connection originalConnection;
         try {
             if (phone != null) {
                 boolean isEmergency = mTelephonyManagerProxy.isCurrentEmergencyNumber(number);
                 Log.i(this, "placeOutgoingConnection isEmergency=" + isEmergency);
                 if (isEmergency) {
+                    handleEmergencyCallStartedForSatelliteSOSMessageRecommender(connection, phone);
                     if (!getAllConnections().isEmpty()) {
                         if (!shouldHoldForEmergencyCall(phone)) {
                             // If we do not support holding ongoing calls for an outgoing
@@ -2068,6 +2161,14 @@
                 extras = new Bundle();
             }
             extras.putInt(PhoneConstants.EXTRA_DIAL_DOMAIN, domain);
+            // Add flag to bundle for comparing legacy and new domain selection results. When
+            // EXTRA_COMPARE_DOMAIN flag is true, legacy domain selection result is used for
+            // placing the call and if both the results are not same then bug report is generated.
+            DeviceConfig.Properties properties = //read all telephony properties
+                    DeviceConfig.getProperties(DeviceConfig.NAMESPACE_TELEPHONY);
+            boolean compareDomainSelection =
+                    properties.getBoolean(KEY_DOMAIN_COMPARE_FEATURE_ENABLED_FLAG, false);
+            extras.putBoolean(PhoneConstants.EXTRA_COMPARE_DOMAIN, compareDomainSelection);
 
             if (phone != null) {
                 Log.v(LOG_TAG, "Call dialing. Domain: " + domain);
@@ -2198,6 +2299,10 @@
                     phone, mEmergencyCallId, isTestEmergencyNumber);
             future.thenAccept((result) -> {
                 Log.d(this, "startEmergencyCall-complete result=" + result);
+                if (mEmergencyCallId == null) {
+                    Log.i(this, "startEmergencyCall-complete dialing canceled");
+                    return;
+                }
                 if (result == android.telephony.DisconnectCause.NOT_DISCONNECTED) {
                     createEmergencyConnection(phone, (TelephonyConnection) resultConnection,
                             numberToDial, request, needToTurnOnRadio,
@@ -2272,6 +2377,10 @@
                         attr, mEmergencyDomainSelectionConnectionCallback);
         future.thenAcceptAsync((result) -> {
             Log.d(this, "createEmergencyConnection-complete result=" + result);
+            if (mEmergencyCallId == null) {
+                Log.i(this, "createEmergencyConnection-complete dialing canceled");
+                return;
+            }
             Bundle extras = request.getExtras();
             extras.putInt(PhoneConstants.EXTRA_DIAL_DOMAIN, result);
             placeOutgoingConnection(request, resultConnection, phone);
@@ -2285,7 +2394,13 @@
         Bundle extras = request.getExtras();
         extras.putInt(PhoneConstants.EXTRA_DIAL_DOMAIN, NetworkRegistrationInfo.DOMAIN_CS);
         mDomainSelectionMainExecutor.execute(
-                () -> placeOutgoingConnection(request, resultConnection, phone));
+                () -> {
+                    if (mEmergencyCallId == null) {
+                        Log.i(this, "dialCsEmergencyCall dialing canceled");
+                        return;
+                    }
+                    placeOutgoingConnection(request, resultConnection, phone);
+                });
     }
 
     private void releaseEmergencyCallDomainSelection(boolean cancel) {
@@ -2316,15 +2431,29 @@
                 return maybeReselectDomainForEmergencyCall(c, callFailCause, reasonInfo);
             }
             Log.i(this, "maybeReselectDomain endCall()");
+            c.removeTelephonyConnectionListener(mEmergencyConnectionListener);
             mEmergencyStateTracker.endCall(c.getTelecomCallId());
             mEmergencyCallId = null;
             return false;
         }
 
-        if (reasonInfo != null
-                && reasonInfo.getCode() == ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL) {
-            onEmergencyRedial(c, c.getPhone().getDefaultPhone());
-            return true;
+        if (reasonInfo != null) {
+            int reasonCode = reasonInfo.getCode();
+            int extraCode = reasonInfo.getExtraCode();
+            if ((reasonCode == ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL)
+                    || (reasonCode == ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED
+                            && extraCode == ImsReasonInfo.EXTRA_CODE_CALL_RETRY_EMERGENCY)) {
+                // clear normal call domain selector
+                c.removeTelephonyConnectionListener(mNormalCallConnectionListener);
+                if (mDomainSelectionConnection != null) {
+                    mDomainSelectionConnection.finishSelection();
+                    mDomainSelectionConnection = null;
+                }
+                mNormalCallConnection = null;
+
+                onEmergencyRedial(c, c.getPhone().getDefaultPhone());
+                return true;
+            }
         }
 
         return maybeReselectDomainForNormalCall(c, callFailCause, reasonInfo);
@@ -2335,14 +2464,8 @@
         Log.i(this, "maybeReselectDomainForEmergencyCall "
                 + "csCause=" +  callFailCause + ", psCause=" + reasonInfo);
 
-        // EMERGENCY_TEMP_FAILURE and EMERGENCY_PERM_FAILURE shall be handled after
-        // reselecting new {@link Phone} in {@link #retryOutgoingOriginalConnection()}.
         if (c.getOriginalConnection() != null
                 && c.getOriginalConnection().getDisconnectCause()
-                        != android.telephony.DisconnectCause.EMERGENCY_TEMP_FAILURE
-                && c.getOriginalConnection().getDisconnectCause()
-                        != android.telephony.DisconnectCause.EMERGENCY_PERM_FAILURE
-                && c.getOriginalConnection().getDisconnectCause()
                         != android.telephony.DisconnectCause.LOCAL
                 && c.getOriginalConnection().getDisconnectCause()
                         != android.telephony.DisconnectCause.POWER_OFF) {
@@ -2360,6 +2483,10 @@
             if (future != null) {
                 future.thenAcceptAsync((result) -> {
                     Log.d(this, "reselectDomain-complete");
+                    if (mEmergencyCallId == null) {
+                        Log.i(this, "reselectDomain-complete dialing canceled");
+                        return;
+                    }
                     onEmergencyRedialOnDomain(c, phone, result);
                 }, mDomainSelectionMainExecutor);
                 return true;
@@ -2368,9 +2495,9 @@
 
         Log.i(this, "maybeReselectDomainForEmergencyCall endCall()");
         c.removeTelephonyConnectionListener(mEmergencyConnectionListener);
-        mEmergencyStateTracker.endCall(c.getTelecomCallId());
         releaseEmergencyCallDomainSelection(true);
-
+        mEmergencyStateTracker.endCall(c.getTelecomCallId());
+        mEmergencyCallId = null;
         return false;
     }
 
@@ -2392,7 +2519,7 @@
                 + ", psCause:" + reasonInfo);
 
         if (mDomainSelectionConnection != null && c.getOriginalConnection() != null) {
-            Phone phone = c.getPhone();
+            Phone phone = c.getPhone().getDefaultPhone();
             final String number = c.getAddress().getSchemeSpecificPart();
             int videoState = c.getOriginalConnection().getVideoState();
             SelectionAttributes selectionAttributes = NormalCallDomainSelectionConnection
@@ -2406,7 +2533,7 @@
                     .reselectDomain(selectionAttributes);
             if (future != null) {
                 future.thenAcceptAsync((result) -> {
-                    onNormalCallRedial(c, result, videoState);
+                    onNormalCallRedial(c, phone, result, videoState);
                 }, mDomainSelectionMainExecutor);
                 return true;
             }
@@ -2477,6 +2604,7 @@
 
         mIsEmergencyCallPending = true;
         c.addTelephonyConnectionListener(mEmergencyConnectionListener);
+        handleEmergencyCallStartedForSatelliteSOSMessageRecommender(c, phone);
 
         if (mEmergencyStateTracker == null) {
             mEmergencyStateTracker = EmergencyStateTracker.getInstance();
@@ -2487,8 +2615,11 @@
                 phone, mEmergencyCallId, isTestEmergencyNumber);
         future.thenAccept((result) -> {
             Log.d(this, "onEmergencyRedial-complete result=" + result);
+            if (mEmergencyCallId == null) {
+                Log.i(this, "onEmergencyRedial-complete dialing canceled");
+                return;
+            }
             if (result == android.telephony.DisconnectCause.NOT_DISCONNECTED) {
-
                 DomainSelectionConnection selectConnection =
                         mDomainSelectionResolver.getDomainSelectionConnection(
                                 phone, SELECTOR_TYPE_CALLING, true);
@@ -2536,6 +2667,10 @@
     private void recreateEmergencyConnection(final TelephonyConnection connection,
             final Phone phone, final @NetworkRegistrationInfo.Domain int result) {
         Log.d(this, "recreateEmergencyConnection result=" + result);
+        if (mEmergencyCallId == null) {
+            Log.i(this, "recreateEmergencyConnection dialing canceled");
+            return;
+        }
         if (!getAllConnections().isEmpty()) {
             if (!shouldHoldForEmergencyCall(phone)) {
                 // If we do not support holding ongoing calls for an outgoing
@@ -2573,17 +2708,24 @@
         onEmergencyRedialOnDomain(connection, phone, result);
     }
 
-    private void onNormalCallRedial(TelephonyConnection connection,
+    private void onNormalCallRedial(TelephonyConnection connection, Phone phone,
             @NetworkRegistrationInfo.Domain int domain, int videocallState) {
 
         Log.v(LOG_TAG, "Redialing the call in domain:"
                 + DomainSelectionService.getDomainName(domain));
 
         String number = connection.getAddress().getSchemeSpecificPart();
-        Phone phone = connection.getPhone();
 
         Bundle extras = new Bundle();
         extras.putInt(PhoneConstants.EXTRA_DIAL_DOMAIN, domain);
+        // Add flag to bundle for comparing legacy and new domain selection results. When
+        // EXTRA_COMPARE_DOMAIN flag is true, legacy domain selection result is used for
+        // placing the call and if both the results are not same then bug report is generated.
+        DeviceConfig.Properties properties = //read all telephony properties
+                DeviceConfig.getProperties(DeviceConfig.NAMESPACE_TELEPHONY);
+        boolean compareDomainSelection =
+                properties.getBoolean(KEY_DOMAIN_COMPARE_FEATURE_ENABLED_FLAG, false);
+        extras.putBoolean(PhoneConstants.EXTRA_COMPARE_DOMAIN, compareDomainSelection);
 
         com.android.internal.telephony.Connection originalConnection =
                 connection.getOriginalConnection();
@@ -2622,12 +2764,23 @@
         if (TextUtils.equals(mEmergencyCallId, c.getTelecomCallId())) {
             Log.i(this, "onLocalHangup " + mEmergencyCallId);
             c.removeTelephonyConnectionListener(mEmergencyConnectionListener);
-            mEmergencyStateTracker.endCall(c.getTelecomCallId());
             releaseEmergencyCallDomainSelection(true);
+            mEmergencyStateTracker.endCall(c.getTelecomCallId());
             mEmergencyCallId = null;
         }
     }
 
+    @VisibleForTesting
+    public TelephonyConnection.TelephonyConnectionListener getEmergencyConnectionListener() {
+        return mEmergencyConnectionListener;
+    }
+
+    @VisibleForTesting
+    public TelephonyConnection.TelephonyConnectionListener
+            getEmergencyConnectionSatelliteListener() {
+        return mEmergencyConnectionSatelliteListener;
+    }
+
     private boolean isVideoCallHoldAllowed(Phone phone) {
          CarrierConfigManager cfgManager = (CarrierConfigManager)
                 phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
@@ -2794,6 +2947,7 @@
         if (phone == null) {
             // Do not block indefinitely.
             completeConsumer.accept(false);
+            return;
         }
         try {
             // Waiting for PhoneSwitcher to complete the operation.
@@ -2913,6 +3067,64 @@
         return modemResultFuture;
     }
 
+    private void addTelephonyConnectionListener(Conferenceable c,
+            TelephonyConnection.TelephonyConnectionListener listener) {
+        if (c instanceof TelephonyConnection) {
+            TelephonyConnection telephonyConnection = (TelephonyConnection) c;
+            telephonyConnection.addTelephonyConnectionListener(listener);
+        } else if (c instanceof ImsConference) {
+            ImsConference imsConference = (ImsConference) c;
+            TelephonyConnection conferenceHost =
+                    (TelephonyConnection) imsConference.getConferenceHost();
+            conferenceHost.addTelephonyConnectionListener(listener);
+        } else {
+            throw new IllegalArgumentException(
+                    "addTelephonyConnectionListener(): Unexpected conferenceable! " + c);
+        }
+    }
+
+    private CompletableFuture<Boolean> listenForHoldStateChanged(
+            @NonNull Conferenceable conferenceable) {
+        CompletableFuture<Boolean> future = new CompletableFuture<>();
+        final StateHoldingListener stateHoldingListener = new StateHoldingListener(future);
+        addTelephonyConnectionListener(conferenceable, stateHoldingListener);
+        return future;
+    }
+
+    // If there are any live calls on the other subscription, sends a hold request for the live call
+    // and waits for the STATE_HOLDING confirmation, to sequence the dial of the outgoing call.
+    private void delayDialForOtherSubHold(Phone phone, PhoneAccountHandle phoneAccountHandle,
+            Consumer<Boolean> completeConsumer) {
+        Conferenceable c = maybeHoldCallsOnOtherSubs(phoneAccountHandle);
+        if (c == null) {
+            // Nothing to hold.
+            completeConsumer.accept(true);
+            return;
+        }
+
+        if (phone == null) {
+            completeConsumer.accept(false);
+            return;
+        }
+
+        try {
+            // We have dispatched a 'hold' command to a live call (Connection or Conference) on the
+            // other sub. Listen to state changed events to see if this entered hold state.
+            CompletableFuture<Boolean> stateHoldingFuture = listenForHoldStateChanged(c);
+            // a timeout that will complete the future to not block the outgoing call indefinitely.
+            CompletableFuture<Boolean> timeout = new CompletableFuture<>();
+            phone.getContext().getMainThreadHandler().postDelayed(
+                    () -> timeout.complete(false), DEFAULT_DSDA_OUTGOING_CALL_HOLD_TIMEOUT_MS);
+            // Ensure that the Consumer is completed on the main thread.
+            stateHoldingFuture.acceptEitherAsync(timeout, completeConsumer,
+                    phone.getContext().getMainExecutor());
+        } catch (Exception e) {
+            Log.w(this, "delayDialForOtherSubHold - exception= "
+                    + e.getMessage());
+            completeConsumer.accept(false);
+        }
+    }
+
     /**
      * Get the Phone to use for an emergency call of the given emergency number address:
      *  a) If there are multiple Phones with the Subscriptions that support the emergency number
@@ -3530,6 +3742,156 @@
                 });
     }
 
+    static void onHold(Conferenceable conferenceable) {
+        if (conferenceable instanceof Connection) {
+            Connection connection = (Connection) conferenceable;
+            connection.onHold();
+        } else if (conferenceable instanceof Conference) {
+            Conference conference = (Conference) conferenceable;
+            conference.onHold();
+        } else {
+            throw new IllegalArgumentException(
+                    "onHold(): Unexpected conferenceable! " + conferenceable);
+        }
+    }
+
+    static void onUnhold(Conferenceable conferenceable) {
+        if (conferenceable instanceof Connection) {
+            Connection connection = (Connection) conferenceable;
+            connection.onUnhold();
+        } else if (conferenceable instanceof Conference) {
+            Conference conference = (Conference) conferenceable;
+            conference.onUnhold();
+        } else {
+            throw new IllegalArgumentException(
+                    "onUnhold(): Unexpected conferenceable! " + conferenceable);
+        }
+    }
+
+     /**
+     * Evaluates whether a connection or conference exists on subscriptions other than the one
+     * corresponding to the existing {@link PhoneAccountHandle}.
+     * @param connections all individual connections, including conference participants.
+     * @param conferences all conferences.
+     * @param currentHandle the existing call handle;
+     * @param telephonyManagerProxy the proxy to the {@link TelephonyManager} instance.
+     */
+    private static @Nullable Conferenceable maybeGetFirstConferenceableFromOtherSubscription(
+            @NonNull Collection<Connection> connections,
+            @NonNull Collection<Conference> conferences,
+            @NonNull PhoneAccountHandle currentHandle,
+            TelephonyManagerProxy telephonyManagerProxy) {
+        if (!telephonyManagerProxy.isConcurrentCallsPossible()) {
+            return null;
+        }
+
+        List<Conference> otherSubConferences = conferences.stream()
+                .filter(c ->
+                        // Exclude multiendpoint calls as they're not on this device.
+                        (c.getConnectionProperties()
+                                & Connection.PROPERTY_IS_EXTERNAL_CALL) == 0
+                                // Include any conferences not on same sub as current connection.
+                                && !Objects.equals(c.getPhoneAccountHandle(),
+                                currentHandle))
+                .toList();
+        if (!otherSubConferences.isEmpty()) {
+            return otherSubConferences.get(0);
+        }
+
+        // Considers Connections (including conference participants) only if no conferences.
+        List<Connection> otherSubConnections = connections.stream()
+                .filter(c ->
+                        // Exclude multiendpoint calls as they're not on this device.
+                        (c.getConnectionProperties() & Connection.PROPERTY_IS_EXTERNAL_CALL) == 0
+                                // Include any calls not on same sub as current connection.
+                                && !Objects.equals(c.getPhoneAccountHandle(),
+                                currentHandle)).toList();
+
+        if (!otherSubConnections.isEmpty()) {
+            if (otherSubConnections.size() > 1) {
+                Log.w(LOG_TAG, "Unexpected number of connections: "
+                        + otherSubConnections.size() + " on other sub!");
+            }
+            return otherSubConnections.get(0);
+        }
+        return null;
+    }
+
+    /**
+     * Where there are ongoing calls on multiple subscriptions for DSDA devices, let the 'hold'
+     * button perform an unhold on the other sub's Connection or Conference. This covers for Dialer
+     * apps that may not have a dedicated 'swap' button for calls across different subs.
+     * @param currentHandle The {@link PhoneAccountHandle} of the current active voice call.
+     */
+    public void maybeUnholdCallsOnOtherSubs(
+            @NonNull PhoneAccountHandle currentHandle) {
+        Log.i(this, "maybeUnholdCallsOnOtherSubs: check for calls not on %s",
+                currentHandle);
+        maybeUnholdCallsOnOtherSubs(getAllConnections(), getAllConferences(),
+                currentHandle, mTelephonyManagerProxy);
+    }
+
+    /**
+     * Where there are ongoing calls on multiple subscriptions for DSDA devices, let the 'hold'
+     * button perform an unhold on the other sub's Connection or Conference. This is a convenience
+     * method to unit test the core functionality.
+     *
+     * @param connections all individual connections, including conference participants.
+     * @param conferences all conferences.
+     * @param currentHandle The {@link PhoneAccountHandle} of the current active call.
+     * @param telephonyManagerProxy the proxy to the {@link TelephonyManager} instance.
+     */
+    @VisibleForTesting
+    protected static void maybeUnholdCallsOnOtherSubs(@NonNull Collection<Connection> connections,
+            @NonNull Collection<Conference> conferences,
+            @NonNull PhoneAccountHandle currentHandle,
+            TelephonyManagerProxy telephonyManagerProxy) {
+        Conferenceable c = maybeGetFirstConferenceableFromOtherSubscription(
+                connections, conferences, currentHandle, telephonyManagerProxy);
+        if (c != null) {
+            onUnhold(c);
+        }
+    }
+
+    /**
+     * For DSDA devices, when an outgoing call is dialed out from the 2nd sub, holds the first call.
+     *
+     * @param outgoingHandle The outgoing {@link PhoneAccountHandle}.
+     * @return the Conferenceable representing the Connection or Conference to be held.
+     */
+    private @Nullable Conferenceable maybeHoldCallsOnOtherSubs(
+            @NonNull PhoneAccountHandle outgoingHandle) {
+        Log.i(this, "maybeHoldCallsOnOtherSubs: check for calls not on %s",
+                outgoingHandle);
+        return maybeHoldCallsOnOtherSubs(getAllConnections(), getAllConferences(),
+                outgoingHandle, mTelephonyManagerProxy);
+    }
+
+    /**
+     * For DSDA devices, when an outgoing call is dialed out from the 2nd sub, holds the first call.
+     * This is a convenience method to unit test the core functionality.
+     *
+     * @param connections all individual connections, including conference participants.
+     * @param conferences all conferences.
+     * @param outgoingHandle The outgoing {@link PhoneAccountHandle}.
+     * @param telephonyManagerProxy the proxy to the {@link TelephonyManager} instance.
+     * @return the {@link Conferenceable} representing the Connection or Conference to be held.
+     */
+    @VisibleForTesting
+    protected static @Nullable Conferenceable maybeHoldCallsOnOtherSubs(
+            @NonNull Collection<Connection> connections,
+            @NonNull Collection<Conference> conferences,
+            @NonNull PhoneAccountHandle outgoingHandle,
+            TelephonyManagerProxy telephonyManagerProxy) {
+        Conferenceable c = maybeGetFirstConferenceableFromOtherSubscription(
+                connections, conferences, outgoingHandle, telephonyManagerProxy);
+        if (c != null) {
+            onHold(c);
+            return c;
+        }
+        return null;
+    }
+
     private void disconnectAllCallsOnOtherSubs (@NonNull PhoneAccountHandle handle) {
         Collection<Connection>connections = getAllConnections();
         connections.stream()
@@ -3569,4 +3931,14 @@
         }
         return NetworkRegistrationInfo.DOMAIN_UNKNOWN;
     }
+
+    private void handleEmergencyCallStartedForSatelliteSOSMessageRecommender(
+            @NonNull TelephonyConnection connection, @NonNull Phone phone) {
+        if (mSatelliteSOSMessageRecommender == null) {
+            mSatelliteSOSMessageRecommender = new SatelliteSOSMessageRecommender(
+                    phone.getContext().getMainLooper());
+        }
+        connection.addTelephonyConnectionListener(mEmergencyConnectionSatelliteListener);
+        mSatelliteSOSMessageRecommender.onEmergencyCallStarted(connection, phone);
+    }
 }
diff --git a/src/com/android/services/telephony/domainselection/CrossSimRedialingController.java b/src/com/android/services/telephony/domainselection/CrossSimRedialingController.java
new file mode 100644
index 0000000..f1bb78c
--- /dev/null
+++ b/src/com/android/services/telephony/domainselection/CrossSimRedialingController.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.services.telephony.domainselection;
+
+import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_CROSS_STACK_REDIAL_TIMER_SEC_INT;
+import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT;
+import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_START_QUICK_CROSS_STACK_REDIAL_TIMER_WHEN_REGISTERED_BOOL;
+import static android.telephony.CarrierConfigManager.ImsEmergency.REDIAL_TIMER_DISABLED;
+import static android.telephony.PreciseDisconnectCause.EMERGENCY_PERM_FAILURE;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PersistableBundle;
+import android.os.SystemProperties;
+import android.telephony.Annotation.PreciseDisconnectCauses;
+import android.telephony.CarrierConfigManager;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.LocalLog;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
+
+import java.util.ArrayList;
+
+/** Controls the cross stack redialing. */
+public class CrossSimRedialingController extends Handler {
+    private static final String TAG = "CrossSimRedialingCtrl";
+    private static final boolean DBG = (SystemProperties.getInt("ro.debuggable", 0) == 1);
+    private static final int LOG_SIZE = 50;
+
+    /** An interface of a helper to check emergency number. */
+    public interface EmergencyNumberHelper {
+        /**
+         * Returns whether the number is an emergency number in the given modem slot.
+         *
+         * @param slotId The slot id to be checked.
+         * @param number The number.
+         * @return {@code true} if the number is an emergency number in the given slot.
+         */
+        boolean isEmergencyNumber(int slotId, String number);
+    }
+
+    @VisibleForTesting
+    public static final int MSG_CROSS_STACK_TIMEOUT = 1;
+    @VisibleForTesting
+    public static final int MSG_QUICK_CROSS_STACK_TIMEOUT = 2;
+
+    private static final LocalLog sLocalLog = new LocalLog(LOG_SIZE);
+
+    private final ArrayList<Integer> mStackSelectionHistory = new ArrayList<>();
+    private final ArrayList<Integer> mPermanentRejectedSlots = new ArrayList<>();
+    private final TelephonyManager mTelephonyManager;
+
+    private EmergencyNumberHelper mEmergencyNumberHelper = new EmergencyNumberHelper() {
+        @Override
+        public boolean isEmergencyNumber(int slotId, String number) {
+            // TODO(b/258112541) Add System api to check emergency number per subscription.
+            try {
+                Phone phone = PhoneFactory.getPhone(slotId);
+                if (phone != null
+                        && phone.getEmergencyNumberTracker() != null
+                        && phone.getEmergencyNumberTracker().isEmergencyNumber(number)) {
+                    return true;
+                }
+            } catch (IllegalStateException e) {
+                loge("isEmergencyNumber e=" + e);
+            }
+            return false;
+        }
+    };
+
+    private int mModemCount;
+
+    /** A cache of the carrier config {@link #KEY_CROSS_STACK_REDIAL_TIMER_SEC_INT}. */
+    private int mCrossStackTimer;
+    /** A cache of the carrier config {@link #KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT}. */
+    private int mQuickCrossStackTimer;
+    /**
+     * A cache of the carrier config
+     * {@link #KEY_START_QUICK_CROSS_STACK_REDIAL_TIMER_WHEN_REGISTERED_BOOL}.
+     */
+    private boolean mStartQuickCrossStackTimerWhenInService;
+
+    private String mCallId;
+    private EmergencyCallDomainSelector mSelector;
+    private String mNumber;
+    private int mSlotId;
+    private int mSubId;
+
+    /**
+     * Creates an instance.
+     *
+     * @param context The Context this is associated with.
+     * @param looper The Looper to run the CrossSimRedialingController.
+     */
+    public CrossSimRedialingController(@NonNull Context context, @NonNull Looper looper) {
+        super(looper);
+
+        mTelephonyManager = context.getSystemService(TelephonyManager.class);
+    }
+
+    /** For unit test only */
+    @VisibleForTesting
+    public CrossSimRedialingController(@NonNull Context context, @NonNull Looper looper,
+            EmergencyNumberHelper emergencyNumberHelper) {
+        this(context, looper);
+
+        mEmergencyNumberHelper = emergencyNumberHelper;
+    }
+
+    /**
+     * Starts the timer.
+     *
+     * @param context The Context this is associated with.
+     * @param selector The instance of {@link EmergencyCallDomainSelector}.
+     * @param callId The call identifier.
+     * @param number The dialing number.
+     * @param inService Indiates that normal service is available.
+     * @param roaming Indicates that it's in roaming or non-domestic network.
+     * @param modemCount The number of active modem count
+     */
+    public void startTimer(@NonNull Context context,
+            @NonNull EmergencyCallDomainSelector selector,
+            @NonNull String callId, @NonNull String number,
+            boolean inService, boolean roaming, int modemCount) {
+        logi("startTimer callId=" + callId
+                + ", in service=" + inService + ", roaming=" + roaming);
+
+        if (!TextUtils.equals(mCallId, callId)) {
+            logi("startTimer callId changed");
+            mCallId = callId;
+            mStackSelectionHistory.clear();
+            mPermanentRejectedSlots.clear();
+        }
+        mSelector = selector;
+        mSlotId = selector.getSlotId();
+        mSubId = selector.getSubId();
+        mNumber = number;
+        mModemCount = modemCount;
+
+        updateCarrierConfiguration(context);
+
+        boolean firstAttempt = !mStackSelectionHistory.contains(mSlotId);
+        logi("startTimer slot=" + mSlotId + ", firstAttempt=" + firstAttempt);
+        mStackSelectionHistory.add(mSlotId);
+
+        if (firstAttempt && mQuickCrossStackTimer > REDIAL_TIMER_DISABLED && !roaming) {
+            if (inService || !mStartQuickCrossStackTimerWhenInService) {
+                logi("startTimer quick timer started");
+                sendEmptyMessageDelayed(MSG_QUICK_CROSS_STACK_TIMEOUT,
+                        mQuickCrossStackTimer);
+                return;
+            }
+        }
+
+        if (mCrossStackTimer > REDIAL_TIMER_DISABLED) {
+            logi("startTimer timer started");
+            sendEmptyMessageDelayed(MSG_CROSS_STACK_TIMEOUT, mCrossStackTimer);
+        }
+    }
+
+    /** Stops the timers. */
+    public void stopTimer() {
+        logi("stopTimer");
+        removeMessages(MSG_CROSS_STACK_TIMEOUT);
+        removeMessages(MSG_QUICK_CROSS_STACK_TIMEOUT);
+    }
+
+    /**
+     * Informs the call failure.
+     * @param cause The call failure cause.
+     */
+    public void notifyCallFailure(@PreciseDisconnectCauses int cause) {
+        logi("notifyCallFailure cause=" + cause);
+        if (cause == EMERGENCY_PERM_FAILURE) {
+            mPermanentRejectedSlots.add(mSlotId);
+        }
+    }
+
+    @Override
+    public void handleMessage(Message msg) {
+        switch(msg.what) {
+            case MSG_CROSS_STACK_TIMEOUT:
+            case MSG_QUICK_CROSS_STACK_TIMEOUT:
+                handleCrossStackTimeout();
+                break;
+            default:
+                super.handleMessage(msg);
+                break;
+        }
+    }
+
+    private void handleCrossStackTimeout() {
+        logi("handleCrossStackTimeout");
+
+        if (isThereOtherSlot()) {
+            mSelector.notifyCrossStackTimerExpired();
+        }
+    }
+
+    /**
+     * Returns whether there is another slot emergency capable.
+     *
+     * @return {@code true} if there is another slot emergency capable,
+     *         {@code false} otherwise.
+     */
+    public boolean isThereOtherSlot() {
+        logi("isThereOtherSlot modemCount=" + mModemCount);
+        if (mModemCount < 2) return false;
+
+        for (int i = 0; i < mModemCount; i++) {
+            if (i == mSlotId) continue;
+
+            if (mPermanentRejectedSlots.contains(i)) {
+                logi("isThereOtherSlot index=" + i + ", permanent rejected");
+                continue;
+            }
+
+            int simState = mTelephonyManager.getSimState(i);
+            if (simState != TelephonyManager.SIM_STATE_READY) {
+                logi("isThereOtherSlot index=" + i + ", simState=" + simState);
+                continue;
+            }
+
+            if (mEmergencyNumberHelper.isEmergencyNumber(i, mNumber)) {
+                logi("isThereOtherSlot index=" + i + ", found");
+                return true;
+            } else {
+                logi("isThereOtherSlot index=" + i + ", not emergency number");
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Caches the configuration.
+     */
+    private void updateCarrierConfiguration(Context context) {
+        CarrierConfigManager configMgr = context.getSystemService(CarrierConfigManager.class);
+        PersistableBundle b = configMgr.getConfigForSubId(mSubId,
+                KEY_CROSS_STACK_REDIAL_TIMER_SEC_INT,
+                KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT,
+                KEY_START_QUICK_CROSS_STACK_REDIAL_TIMER_WHEN_REGISTERED_BOOL);
+        if (b == null) {
+            b = CarrierConfigManager.getDefaultConfig();
+        }
+
+        mCrossStackTimer = b.getInt(KEY_CROSS_STACK_REDIAL_TIMER_SEC_INT) * 1000;
+        mQuickCrossStackTimer =
+                b.getInt(KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT) * 1000;
+        mStartQuickCrossStackTimerWhenInService =
+                b.getBoolean(KEY_START_QUICK_CROSS_STACK_REDIAL_TIMER_WHEN_REGISTERED_BOOL);
+
+        logi("updateCarrierConfiguration "
+                + ", crossStackTimer=" + mCrossStackTimer
+                + ", quickCrossStackTimer=" + mQuickCrossStackTimer
+                + ", startQuickTimerInService=" + mStartQuickCrossStackTimerWhenInService);
+    }
+
+    /** Destroys the instance. */
+    public void destroy() {
+        if (DBG) logd("destroy");
+
+        removeMessages(MSG_CROSS_STACK_TIMEOUT);
+        removeMessages(MSG_QUICK_CROSS_STACK_TIMEOUT);
+    }
+
+    private void logd(String s) {
+        Log.d(TAG, "[" + mSlotId + "|" + mSubId + "] " + s);
+    }
+
+    private void logi(String s) {
+        Log.i(TAG, "[" + mSlotId + "|" + mSubId + "] " + s);
+        sLocalLog.log(s);
+    }
+
+    private void loge(String s) {
+        Log.e(TAG, "[" + mSlotId + "|" + mSubId + "] " + s);
+        sLocalLog.log(s);
+    }
+}
diff --git a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
index 51becde..b1c288c 100644
--- a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
@@ -50,6 +50,8 @@
 import static android.telephony.CarrierConfigManager.ImsWfc.KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL;
 import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME;
 import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING;
+import static android.telephony.PreciseDisconnectCause.EMERGENCY_PERM_FAILURE;
+import static android.telephony.PreciseDisconnectCause.EMERGENCY_TEMP_FAILURE;
 
 import android.annotation.NonNull;
 import android.content.Context;
@@ -73,9 +75,11 @@
 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;
@@ -86,7 +90,9 @@
 
 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;
 
 /**
@@ -157,6 +163,7 @@
     private @TransportType int mLastTransportType = TRANSPORT_TYPE_INVALID;
     private @DomainSelectionService.EmergencyScanType int mScanType;
     private @RadioAccessNetworkType List<Integer> mLastPreferredNetworks;
+    private boolean mIsTestEmergencyNumber;
 
     private CancellationSignal mCancelSignal;
 
@@ -180,6 +187,7 @@
     private boolean mRequiresVoLteEnabled;
     private boolean mLtePreferredAfterNrFailure;
     private boolean mTryCsWhenPsFails;
+    private boolean mTryEpsFallback;
     private int mModemCount;
 
     /** Indicates whether this instance is deactivated. */
@@ -188,6 +196,9 @@
     private boolean mIsScanRequested = false;
     /** Indicates whether selected domain has been notified. */
     private boolean mDomainSelected = false;
+    /** Indicates whether the cross sim redialing timer has expired. */
+    private boolean mCrossStackTimerExpired = false;
+
     /**
      * Indicates whether {@link #selectDomain(SelectionAttributes, TransportSelectionCallback)}
      * is called or not.
@@ -195,11 +206,13 @@
     private boolean mDomainSelectionRequested = false;
 
     private final PowerManager.WakeLock mPartialWakeLock;
+    private final CrossSimRedialingController mCrossSimRedialingController;
 
     /** Constructor. */
     public EmergencyCallDomainSelector(Context context, int slotId, int subId,
             @NonNull Looper looper, @NonNull ImsStateTracker imsStateTracker,
-            @NonNull DestroyListener destroyListener) {
+            @NonNull DestroyListener destroyListener,
+            @NonNull CrossSimRedialingController csrController) {
         super(context, slotId, subId, looper, imsStateTracker, destroyListener, TAG);
 
         mImsStateTracker.addBarringInfoListener(this);
@@ -208,6 +221,7 @@
         PowerManager pm = context.getSystemService(PowerManager.class);
         mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
 
+        mCrossSimRedialingController = csrController;
         acquireWakeLock();
     }
 
@@ -255,7 +269,7 @@
 
         if (result.getAccessNetwork() == UNKNOWN) {
             if ((mPreferredNetworkScanType == SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE)
-                      || (mScanType == DomainSelectionService.SCAN_TYPE_FULL_SERVICE)) {
+                      && (mScanType == DomainSelectionService.SCAN_TYPE_FULL_SERVICE)) {
                 mScanType = DomainSelectionService.SCAN_TYPE_LIMITED_SERVICE;
                 mWwanSelectorCallback.onRequestEmergencyNetworkScan(
                         mLastPreferredNetworks, mScanType, mCancelSignal,
@@ -271,10 +285,33 @@
         }
 
         removeMessages(MSG_NETWORK_SCAN_TIMEOUT);
-        onWwanNetworkTypeSelected(result.getAccessNetwork());
+        onWwanNetworkTypeSelected(getAccessNetworkType(result));
         mCancelSignal = null;
     }
 
+    /**
+     * Determines the scanned network type.
+     *
+     * @param result The result of network scan.
+     * @return The selected network type.
+     */
+    private @RadioAccessNetworkType int getAccessNetworkType(EmergencyRegResult result) {
+        int accessNetworkType = result.getAccessNetwork();
+        if (accessNetworkType != EUTRAN) return accessNetworkType;
+
+        int regState = result.getRegState();
+        int domain = result.getDomain();
+
+        // Emergency is not supported with LTE, but CSFB is possible.
+        if ((regState == REGISTRATION_STATE_HOME || regState == REGISTRATION_STATE_ROAMING)
+                && (domain == NetworkRegistrationInfo.DOMAIN_CS)) {
+            logi("getAccessNetworkType emergency not supported but CSFB is possible");
+            accessNetworkType = UTRAN;
+        }
+
+        return accessNetworkType;
+    }
+
     @Override
     public void cancelSelection() {
         logi("cancelSelection");
@@ -291,9 +328,32 @@
     private void reselectDomain() {
         logi("reselectDomain tryCsWhenPsFails=" + mTryCsWhenPsFails);
 
+        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");
+            terminateSelectionForCrossSimRedialing(cause == EMERGENCY_PERM_FAILURE);
+            return;
+        }
+
+        if (mCrossStackTimerExpired) {
+            logi("reselectDomain cross stack timer expired");
+            terminateSelectionForCrossSimRedialing(false);
+            return;
+        }
+
+        if (mIsTestEmergencyNumber) {
+            selectDomainForTestEmergencyNumber();
+            return;
+        }
+
         if (mTryCsWhenPsFails) {
             mTryCsWhenPsFails = false;
-            mCsNetworkType = getSelectableCsNetworkType();
+            // Initial state was CSFB available and dial PS failed.
+            // Dial CS for CSFB instead of scanning with CS preferred network list.
             logi("reselectDomain tryCs=" + accessNetworkTypeToString(mCsNetworkType));
             if (mCsNetworkType != UNKNOWN) {
                 onWwanNetworkTypeSelected(mCsNetworkType);
@@ -342,6 +402,7 @@
         logi("selectDomain attr=" + attr);
         mTransportSelectorCallback = cb;
         mSelectionAttributes = attr;
+        mIsTestEmergencyNumber = isTestEmergencyNumber(attr.getNumber());
 
         TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
         mModemCount = tm.getActiveModemCount();
@@ -353,6 +414,7 @@
         logi("startDomainSelection modemCount=" + mModemCount);
         updateCarrierConfiguration();
         mDomainSelectionRequested = true;
+        startCrossStackTimer();
         if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
             selectDomain();
         } else {
@@ -505,6 +567,11 @@
     }
 
     private void selectDomainFromInitialState() {
+        if (mIsTestEmergencyNumber) {
+            selectDomainForTestEmergencyNumber();
+            return;
+        }
+
         boolean csInService = isCsInService();
         boolean psInService = isPsInService();
 
@@ -542,6 +609,7 @@
                 onWwanNetworkTypeSelected(mCsNetworkType);
             }
         } else if (psAvailable) {
+            mTryEpsFallback = (mPsNetworkType == NGRAN) && isEpsFallbackAvailable();
             if (!mRequiresImsRegistration || isImsRegisteredWithVoiceCapability()) {
                 onWwanNetworkTypeSelected(mPsNetworkType);
             } else if (isDeactivatedSim()) {
@@ -550,6 +618,7 @@
             } else {
                 // Carrier configuration requires IMS registration for emergency services over PS,
                 // but not registered. Try CS emergency call.
+                mTryEpsFallback = false;
                 requestScan(true, true);
             }
         } else if (csAvailable) {
@@ -561,6 +630,7 @@
                 // but not registered. Try CS emergency call.
                 requestScan(true, true);
             } else {
+                mTryEpsFallback = isEpsFallbackAvailable();
                 requestScan(true);
             }
         }
@@ -598,7 +668,10 @@
 
         mCancelSignal = new CancellationSignal();
         // In case dialing over Wi-Fi has failed, do not the change the domain preference.
-        if (!wifiFailed) mLastPreferredNetworks = getNextPreferredNetworks(csPreferred);
+        if (!wifiFailed) {
+            mLastPreferredNetworks = getNextPreferredNetworks(csPreferred, mTryEpsFallback);
+        }
+        mTryEpsFallback = false;
 
         if (isInRoaming()
                 && (mPreferredNetworkScanType == DomainSelectionService.SCAN_TYPE_FULL_SERVICE)) {
@@ -630,9 +703,12 @@
      * Gets the list of preferred network type for the new scan request.
      *
      * @param csPreferred Indicates whether CS preferred scan is requested.
+     * @param tryEpsFallback Indicates whether scan requested for EPS fallback.
      * @return The list of preferred network types.
      */
-    private @RadioAccessNetworkType List<Integer> getNextPreferredNetworks(boolean csPreferred) {
+    @VisibleForTesting
+    public @RadioAccessNetworkType List<Integer> getNextPreferredNetworks(boolean csPreferred,
+            boolean tryEpsFallback) {
         if (mRequiresVoLteEnabled && !isAdvancedCallingSettingEnabled()) {
             // Emergency call over IMS is not supported.
             logi("getNextPreferredNetworks VoLte setting is not enabled.");
@@ -645,14 +721,16 @@
         int psPriority = domains.indexOf(DOMAIN_PS_3GPP);
         int csPriority = domains.indexOf(DOMAIN_CS);
         logi("getNextPreferredNetworks psPriority=" + psPriority + ", csPriority=" + csPriority
-                + ", csPreferred=" + csPreferred
+                + ", csPreferred=" + csPreferred + ", epsFallback=" + tryEpsFallback
                 + ", lastNetworkType=" + accessNetworkTypeToString(mLastNetworkType));
 
-        if (!csPreferred && mLastNetworkType == UNKNOWN) {
+        if (!csPreferred && (mLastNetworkType == UNKNOWN || tryEpsFallback)) {
             // Generate the list per the domain preference.
 
             if (psPriority == NOT_SUPPORTED && csPriority == NOT_SUPPORTED) {
-                // should not reach here.
+                // should not reach here. However, to avoid unexpected problems.
+                preferredNetworks = generatePreferredNetworks(getCsNetworkTypeConfiguration(),
+                        getImsNetworkTypeConfiguration());
             } else if (psPriority == NOT_SUPPORTED && csPriority > NOT_SUPPORTED) {
                 // CS networks only.
                 preferredNetworks = generatePreferredNetworks(getCsNetworkTypeConfiguration());
@@ -665,14 +743,20 @@
                         getCsNetworkTypeConfiguration());
             } else {
                 // CS preferred.
-                generatePreferredNetworks(getCsNetworkTypeConfiguration(),
+                preferredNetworks = generatePreferredNetworks(getCsNetworkTypeConfiguration(),
                         getImsNetworkTypeConfiguration());
             }
+
+            // Make NGRAN have the lowest priority
+            if (tryEpsFallback && preferredNetworks.contains(NGRAN)) {
+                preferredNetworks.remove(Integer.valueOf(NGRAN));
+                preferredNetworks.add(NGRAN);
+            }
         } else if (csPreferred || mLastNetworkType == EUTRAN || mLastNetworkType == NGRAN) {
             if (!csPreferred && mLastNetworkType == NGRAN && mLtePreferredAfterNrFailure) {
                 // LTE is preferred after dialing over NR failed.
                 List<Integer> imsRats = getImsNetworkTypeConfiguration();
-                imsRats.remove(new Integer(NGRAN));
+                imsRats.remove(Integer.valueOf(NGRAN));
                 preferredNetworks = generatePreferredNetworks(imsRats,
                         getCsNetworkTypeConfiguration());
             } else  if (csPriority > NOT_SUPPORTED) {
@@ -681,7 +765,7 @@
                         getImsNetworkTypeConfiguration());
             } else {
                 // CS not suppored.
-                generatePreferredNetworks(getImsNetworkTypeConfiguration());
+                preferredNetworks = generatePreferredNetworks(getImsNetworkTypeConfiguration());
             }
         } else {
             // CS tried, generate the list with PS preferred.
@@ -843,6 +927,17 @@
         return UNKNOWN;
     }
 
+    private boolean isEpsFallbackAvailable() {
+        EmergencyRegResult regResult = mSelectionAttributes.getEmergencyRegResult();
+        if (regResult == null) return false;
+
+        List<Integer> ratList = getImsNetworkTypeConfiguration();
+        if (ratList.contains(EUTRAN)) {
+            return (regResult.getNwProvidedEmf() > 0);
+        }
+        return false;
+    }
+
     /**
      * Determines whether the SIM is a deactivated one.
      *
@@ -1066,7 +1161,7 @@
         mDomainSelected = true;
         mLastTransportType = TRANSPORT_TYPE_WLAN;
         mVoWifiTrialCount++;
-        mTransportSelectorCallback.onWlanSelected();
+        mTransportSelectorCallback.onWlanSelected(mVoWifiOverEmergencyPdn);
         mWwanSelectorCallback = null;
     }
 
@@ -1097,7 +1192,8 @@
         if (accessNetworkType == EUTRAN || accessNetworkType == NGRAN) {
             domain = NetworkRegistrationInfo.DOMAIN_PS;
         }
-        mWwanSelectorCallback.onDomainSelected(domain);
+        mWwanSelectorCallback.onDomainSelected(domain,
+                (domain == NetworkRegistrationInfo.DOMAIN_PS));
     }
 
     /**
@@ -1147,7 +1243,10 @@
             int simState = tm.getSimState(getSlotId());
             if (simState != TelephonyManager.SIM_STATE_READY) {
                 logi("allowEmergencyCalls not ready, simState=" + simState + ", iso=" + iso);
-                return false;
+                if (mCrossSimRedialingController.isThereOtherSlot()) {
+                    return false;
+                }
+                logi("allowEmergencyCalls there is no other slot available");
             }
         }
 
@@ -1156,7 +1255,18 @@
 
     private void terminateSelectionPermanentlyForSlot() {
         logi("terminateSelectionPermanentlyForSlot");
-        mTransportSelectorCallback.onSelectionTerminated(DisconnectCause.EMERGENCY_PERM_FAILURE);
+        terminateSelection(true);
+    }
+
+    private void terminateSelectionForCrossSimRedialing(boolean permanent) {
+        logi("terminateSelectionForCrossSimRedialing perm=" + permanent);
+        terminateSelection(permanent);
+    }
+
+    private void terminateSelection(boolean permanent) {
+        mTransportSelectorCallback.onSelectionTerminated(permanent
+                ? DisconnectCause.EMERGENCY_PERM_FAILURE
+                : DisconnectCause.EMERGENCY_TEMP_FAILURE);
 
         if (mIsScanRequested && mCancelSignal != null) {
             mCancelSignal.cancel();
@@ -1164,6 +1274,41 @@
         }
     }
 
+    /** Starts the cross stack timer. */
+    public void startCrossStackTimer() {
+        boolean inService = false;
+        boolean inRoaming = false;
+
+        if (mModemCount == 1) return;
+
+        EmergencyRegResult regResult = mSelectionAttributes.getEmergencyRegResult();
+        if (regResult != null) {
+            int regState = regResult.getRegState();
+
+            if ((regResult.getDomain() > 0)
+                    && (regState == REGISTRATION_STATE_HOME
+                            || regState == REGISTRATION_STATE_ROAMING)) {
+                inService = true;
+            }
+            inRoaming = (regState == REGISTRATION_STATE_ROAMING) || isInRoaming();
+        }
+
+        mCrossSimRedialingController.startTimer(mContext, this, mSelectionAttributes.getCallId(),
+                mSelectionAttributes.getNumber(), inService, inRoaming, mModemCount);
+    }
+
+    /** Notifies that the cross stack redilaing timer has been expired. */
+    public void notifyCrossStackTimerExpired() {
+        logi("notifyCrossStackTimerExpired");
+
+        mCrossStackTimerExpired = true;
+        if (mDomainSelected) {
+            // When reselecting domain, terminateSelection will be called.
+            return;
+        }
+        terminateSelectionForCrossSimRedialing(false);
+    }
+
     private static String arrayToString(int[] intArray, IntFunction<String> func) {
         int length = intArray.length;
         StringBuilder sb = new StringBuilder("{");
@@ -1234,6 +1379,7 @@
     public void destroy() {
         if (DBG) logd("destroy");
 
+        mCrossSimRedialingController.stopTimer();
         releaseWakeLock();
 
         mDestroyed = true;
@@ -1264,6 +1410,37 @@
         }
     }
 
+    private void selectDomainForTestEmergencyNumber() {
+        logi("selectDomainForTestEmergencyNumber");
+        if (isImsRegisteredWithVoiceCapability()) {
+            onWwanNetworkTypeSelected(EUTRAN);
+        } else {
+            onWwanNetworkTypeSelected(UTRAN);
+        }
+    }
+
+    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/NormalCallDomainSelector.java b/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
index 3da0044..f176d90 100644
--- a/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
@@ -168,7 +168,7 @@
         mStopDomainSelection = true;
         if (mImsStateTracker.isImsRegisteredOverWlan()) {
             logd("WLAN selected");
-            mTransportSelectorCallback.onWlanSelected();
+            mTransportSelectorCallback.onWlanSelected(false);
         } else {
             if (mWwanSelectorCallback == null) {
                 mTransportSelectorCallback.onWwanSelected((callback) -> {
@@ -184,7 +184,7 @@
     private void notifyPsSelectedInternal() {
         if (mWwanSelectorCallback != null) {
             logd("notifyPsSelected - onWwanSelected");
-            mWwanSelectorCallback.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS);
+            mWwanSelectorCallback.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS, false);
         } else {
             loge("wwanSelectorCallback is null");
             mTransportSelectorCallback.onSelectionTerminated(DisconnectCause.OUTGOING_FAILURE);
@@ -207,7 +207,7 @@
     private void notifyCsSelectedInternal() {
         if (mWwanSelectorCallback != null) {
             logd("wwanSelectorCallback -> onDomainSelected(DOMAIN_CS)");
-            mWwanSelectorCallback.onDomainSelected(NetworkRegistrationInfo.DOMAIN_CS);
+            mWwanSelectorCallback.onDomainSelected(NetworkRegistrationInfo.DOMAIN_CS, false);
         } else {
             loge("wwanSelectorCallback is null");
             mTransportSelectorCallback.onSelectionTerminated(DisconnectCause.OUTGOING_FAILURE);
diff --git a/src/com/android/services/telephony/domainselection/SmsDomainSelector.java b/src/com/android/services/telephony/domainselection/SmsDomainSelector.java
index e7c9ac5..6930b13 100644
--- a/src/com/android/services/telephony/domainselection/SmsDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/SmsDomainSelector.java
@@ -178,7 +178,7 @@
 
     protected void notifyWlanSelected() {
         logi("DomainSelected: WLAN");
-        mTransportSelectorCallback.onWlanSelected();
+        mTransportSelectorCallback.onWlanSelected(false);
         setDomainSelectionRequested(false);
     }
 
@@ -199,7 +199,7 @@
         logi("DomainSelected: WWAN/" + DomainSelectionService.getDomainName(domain));
 
         if (mWwanSelectorCallback != null) {
-            mWwanSelectorCallback.onDomainSelected(domain);
+            mWwanSelectorCallback.onDomainSelected(domain, false);
         } else {
             mTransportSelectorCallback.onSelectionTerminated(DisconnectCause.LOCAL);
         }
diff --git a/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionService.java b/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionService.java
index 13db06b..3a8fc86 100644
--- a/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionService.java
+++ b/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionService.java
@@ -70,7 +70,8 @@
         DomainSelectorBase create(Context context, int slotId, int subId,
                 @SelectorType int selectorType, boolean isEmergency, @NonNull Looper looper,
                 @NonNull ImsStateTracker imsStateTracker,
-                @NonNull DomainSelectorBase.DestroyListener listener);
+                @NonNull DomainSelectorBase.DestroyListener listener,
+                @NonNull CrossSimRedialingController crossSimRedialingController);
     }
 
     private static final class DefaultDomainSelectorFactory implements DomainSelectorFactory {
@@ -78,7 +79,8 @@
         public DomainSelectorBase create(Context context, int slotId, int subId,
                 @SelectorType int selectorType, boolean isEmergency, @NonNull Looper looper,
                 @NonNull ImsStateTracker imsStateTracker,
-                @NonNull DomainSelectorBase.DestroyListener listener) {
+                @NonNull DomainSelectorBase.DestroyListener listener,
+                @NonNull CrossSimRedialingController crossSimRedialingController) {
             DomainSelectorBase selector = null;
 
             logi("create-DomainSelector: slotId=" + slotId + ", subId=" + subId
@@ -89,7 +91,7 @@
                 case SELECTOR_TYPE_CALLING:
                     if (isEmergency) {
                         selector = new EmergencyCallDomainSelector(context, slotId, subId, looper,
-                                imsStateTracker, listener);
+                                imsStateTracker, listener, crossSimRedialingController);
                     } else {
                         selector = new NormalCallDomainSelector(context, slotId, subId, looper,
                                 imsStateTracker, listener);
@@ -192,6 +194,7 @@
     private final ImsStateTrackerFactory mImsStateTrackerFactory;
     private final DomainSelectorFactory mDomainSelectorFactory;
     private Handler mServiceHandler;
+    private CrossSimRedialingController mCrossSimRedialingController;
 
     public TelephonyDomainSelectionService(Context context) {
         this(context, ImsStateTracker::new, new DefaultDomainSelectorFactory());
@@ -221,6 +224,8 @@
             loge("Adding OnSubscriptionChangedListener failed");
         }
 
+        mCrossSimRedialingController = new CrossSimRedialingController(context, getLooper());
+
         logi("TelephonyDomainSelectionService created");
     }
 
@@ -258,6 +263,11 @@
             sm.removeOnSubscriptionsChangedListener(mSubscriptionsChangedListener);
         }
 
+        if (mCrossSimRedialingController != null) {
+            mCrossSimRedialingController.destroy();
+            mCrossSimRedialingController = null;
+        }
+
         if (mServiceHandler != null) {
             mServiceHandler.getLooper().quit();
             mServiceHandler = null;
@@ -279,7 +289,8 @@
         final boolean isEmergency = attr.isEmergency();
         ImsStateTracker ist = getImsStateTracker(slotId);
         DomainSelectorBase selector = mDomainSelectorFactory.create(mContext, slotId, subId,
-                selectorType, isEmergency, getLooper(), ist, mDestroyListener);
+                selectorType, isEmergency, getLooper(), ist, mDestroyListener,
+                mCrossSimRedialingController);
 
         if (selector != null) {
             // Ensures that ImsStateTracker is started before selecting the domain if not started
diff --git a/src/com/android/services/telephony/rcs/TelephonyRcsService.java b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
index 3a8ad62..f6ba40b 100644
--- a/src/com/android/services/telephony/rcs/TelephonyRcsService.java
+++ b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
@@ -366,16 +366,7 @@
     }
 
     private int getSubscriptionFromSlot(int slotId) {
-        SubscriptionManager manager = mContext.getSystemService(SubscriptionManager.class);
-        if (manager == null) {
-            Log.w(LOG_TAG, "Couldn't find SubscriptionManager for slotId=" + slotId);
-            return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-        }
-        int[] subIds = manager.getSubscriptionIds(slotId);
-        if (subIds != null && subIds.length > 0) {
-            return subIds[0];
-        }
-        return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+        return SubscriptionManager.getSubscriptionId(slotId);
     }
 
     /**
diff --git a/tests/src/com/android/phone/CarrierConfigLoaderTest.java b/tests/src/com/android/phone/CarrierConfigLoaderTest.java
index 45a53f7..f29c123 100644
--- a/tests/src/com/android/phone/CarrierConfigLoaderTest.java
+++ b/tests/src/com/android/phone/CarrierConfigLoaderTest.java
@@ -32,6 +32,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -65,6 +66,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -102,7 +104,7 @@
     @Before
     public void setUp() throws Exception {
         super.setUp();
-
+        MockitoAnnotations.initMocks(this);
         replaceInstance(SubscriptionManagerService.class, "sInstance", null,
                 mSubscriptionManagerService);
 
@@ -428,4 +430,21 @@
                 : TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS).when(
                 mockTelephonyManager).getCarrierPrivilegeStatus(anyInt());
     }
+
+    @Test
+    public void testMultiSimConfigChanged() throws Exception {
+        replaceInstance(TelephonyManager.class, "sInstance", null, mTelephonyManager);
+        mContext.grantPermission(STUB_PERMISSION_ENABLE_ALL);
+
+        // Changed from 1 to 2.
+        doReturn(2).when(mTelephonyManager).getActiveModemCount();
+        doReturn(true).when(mContext).bindService(
+                any(Intent.class), any(ServiceConnection.class), anyInt());
+        doNothing().when(mContext).sendBroadcastAsUser(any(Intent.class), any(UserHandle.class));
+        mHandler.sendMessage(mHandler.obtainMessage(17 /* EVENT_MULTI_SIM_CONFIG_CHANGED */));
+        mTestableLooper.processAllMessages();
+
+        mCarrierConfigLoader.updateConfigForPhoneId(1, IccCardConstants.INTENT_VALUE_ICC_ABSENT);
+        mTestableLooper.processAllMessages();
+    }
 }
diff --git a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
index 4cc793d..e702279 100644
--- a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
+++ b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
@@ -21,7 +21,6 @@
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
@@ -42,9 +41,10 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import com.android.TelephonyTestBase;
+import com.android.internal.telephony.IIntegerConsumer;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.RILConstants;
-import com.android.internal.telephony.IIntegerConsumer;
+import com.android.internal.telephony.subscription.SubscriptionManagerService;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -54,7 +54,7 @@
 import java.util.Locale;
 
 /**
- * Unit Test for CarrierConfigLoader.
+ * Unit Test for PhoneInterfaceManager.
  */
 @RunWith(AndroidJUnit4.class)
 public class PhoneInterfaceManagerTest extends TelephonyTestBase {
@@ -67,6 +67,9 @@
     @Mock
     Phone mPhone;
 
+    @Mock
+    private SubscriptionManagerService mSubscriptionManagerService;
+
     @Before
     @UiThreadTest
     public void setUp() throws Exception {
@@ -76,6 +79,9 @@
         // alive on a test devices. You must use the spy to mock behavior. Mocks stemming from the
         // passed context will remain unused.
         mPhoneInterfaceManager = spy(PhoneInterfaceManager.init(mPhoneGlobals));
+        doReturn(mSubscriptionManagerService).when(mPhoneInterfaceManager)
+                .getSubscriptionManagerService();
+        TelephonyManager.setupISubForTest(mSubscriptionManagerService);
         mSharedPreferences = mPhoneInterfaceManager.getSharedPreferences();
         mSharedPreferences.edit().remove(Phone.PREF_NULL_CIPHER_AND_INTEGRITY_ENABLED).commit();
         mIIntegerConsumer = mock(IIntegerConsumer.class);
diff --git a/tests/src/com/android/phone/PhoneUtilsTest.java b/tests/src/com/android/phone/PhoneUtilsTest.java
index b5ff0dc..3d7815c 100644
--- a/tests/src/com/android/phone/PhoneUtilsTest.java
+++ b/tests/src/com/android/phone/PhoneUtilsTest.java
@@ -82,8 +82,8 @@
     public void testMakePstnPhoneAccountHandleWithPrefix() throws Exception {
         PhoneAccountHandle phoneAccountHandleTest = new PhoneAccountHandle(
                 PSTN_CONNECTION_SERVICE_COMPONENT, mPhoneAccountHandleIdString);
-        assertEquals(phoneAccountHandleTest, PhoneUtils.makePstnPhoneAccountHandleWithPrefix(
-                mPhoneAccountHandleIdString, "", false, null));
+        assertEquals(phoneAccountHandleTest, PhoneUtils.makePstnPhoneAccountHandleWithId(
+                mPhoneAccountHandleIdString, null));
     }
 
     @Test
@@ -91,7 +91,7 @@
         UserHandle userHandle = new UserHandle(10);
         PhoneAccountHandle phoneAccountHandleTest = new PhoneAccountHandle(
                 PSTN_CONNECTION_SERVICE_COMPONENT, mPhoneAccountHandleIdString, userHandle);
-        assertEquals(phoneAccountHandleTest, PhoneUtils.makePstnPhoneAccountHandleWithPrefix(
-                mPhoneAccountHandleIdString, "", false, userHandle));
+        assertEquals(phoneAccountHandleTest, PhoneUtils.makePstnPhoneAccountHandleWithId(
+                mPhoneAccountHandleIdString, userHandle));
     }
 }
diff --git a/tests/src/com/android/phone/euicc/EuiccUiDispatcherActivityTest.java b/tests/src/com/android/phone/euicc/EuiccUiDispatcherActivityTest.java
index 8b0ac5c..817220c 100644
--- a/tests/src/com/android/phone/euicc/EuiccUiDispatcherActivityTest.java
+++ b/tests/src/com/android/phone/euicc/EuiccUiDispatcherActivityTest.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.service.euicc.EuiccService;
 import android.telephony.euicc.EuiccManager;
 
 import androidx.test.InstrumentationRegistry;
@@ -111,6 +112,24 @@
         assertEquals("bar", euiccUiIntent.getStringExtra("foo"));
     }
 
+    @Test
+    public void testTransferEmbeddedSubscriptionsAction() {
+        mIntent = new Intent(EuiccManager.ACTION_TRANSFER_EMBEDDED_SUBSCRIPTIONS);
+        Intent euiccUiIntent = mActivity.resolveEuiccUiIntent();
+        assertNotNull(euiccUiIntent);
+        assertEquals(EuiccService.ACTION_TRANSFER_EMBEDDED_SUBSCRIPTIONS,
+                euiccUiIntent.getAction());
+    }
+
+    @Test
+    public void testConvertToEmbeddedSubscriptionAction() {
+        mIntent = new Intent(EuiccManager.ACTION_CONVERT_TO_EMBEDDED_SUBSCRIPTION);
+        Intent euiccUiIntent = mActivity.resolveEuiccUiIntent();
+        assertNotNull(euiccUiIntent);
+        assertEquals(EuiccService.ACTION_CONVERT_TO_EMBEDDED_SUBSCRIPTION,
+                euiccUiIntent.getAction());
+    }
+
     class TestEuiccUiDispatcherActivity extends EuiccUiDispatcherActivity {
         public TestEuiccUiDispatcherActivity() {
             attachBaseContext(mMockContext);
diff --git a/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java b/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
index 921babb..544d7ea 100644
--- a/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
+++ b/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
@@ -715,7 +715,7 @@
         doReturn(TelephonyManager.NETWORK_TYPE_NR).when(mServiceState).getDataNetworkType();
         // entitlement check passed
         mEntitlementResponse.mEntitlementStatus =
-                PremiumNetworkEntitlementResponse.PREMIUM_NETWORK_ENTITLEMENT_STATUS_ENABLED;
+                PremiumNetworkEntitlementResponse.PREMIUM_NETWORK_ENTITLEMENT_STATUS_DISABLED;
 
         // send purchase request
         mSlicePurchaseController.purchasePremiumCapability(
diff --git a/tests/src/com/android/services/telephony/ImsConferenceControllerTest.java b/tests/src/com/android/services/telephony/ImsConferenceControllerTest.java
index 33c8b8a..a9207e6 100644
--- a/tests/src/com/android/services/telephony/ImsConferenceControllerTest.java
+++ b/tests/src/com/android/services/telephony/ImsConferenceControllerTest.java
@@ -24,7 +24,9 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.content.ComponentName;
 import android.os.Looper;
+import android.telecom.PhoneAccountHandle;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import org.junit.Before;
@@ -46,6 +48,14 @@
     @Mock
     private TelecomAccountRegistry mMockTelecomAccountRegistry;
 
+    private static final ComponentName TEST_COMPONENT_NAME = new ComponentName(
+            "com.android.phone.tests", ImsConferenceControllerTest.class.getName());
+    private static final String TEST_ACCOUNT_ID1 = "id1";
+    private static final String TEST_ACCOUNT_ID2 = "id2";
+    private static final PhoneAccountHandle PHONE_ACCOUNT_HANDLE_1 = new PhoneAccountHandle(
+            TEST_COMPONENT_NAME, TEST_ACCOUNT_ID1);
+    private static final PhoneAccountHandle PHONE_ACCOUNT_HANDLE_2 = new PhoneAccountHandle(
+            TEST_COMPONENT_NAME, TEST_ACCOUNT_ID2);
     private TestTelephonyConnection mTestTelephonyConnectionA;
     private TestTelephonyConnection mTestTelephonyConnectionB;
 
@@ -61,6 +71,9 @@
         mTestTelephonyConnectionA = new TestTelephonyConnection();
         mTestTelephonyConnectionB = new TestTelephonyConnection();
 
+        mTestTelephonyConnectionA.setPhoneAccountHandle(PHONE_ACCOUNT_HANDLE_1);
+        mTestTelephonyConnectionB.setPhoneAccountHandle(PHONE_ACCOUNT_HANDLE_1);
+
         mControllerTest = new ImsConferenceController(mTelecomAccountRegistry,
                 mMockTelephonyConnectionServiceProxy, () -> false);
     }
@@ -99,6 +112,27 @@
     }
 
     /**
+     * Behavior: add telephony connections A and B to conference controller;
+     * Assumption: Connection A and B have different PhoneAccountHandles, belong to different subs;
+     * Expected: Connection A and Connection B are not conferenceable with each other;
+     */
+    @Test
+    @SmallTest
+    public void testCallsOnDifferentSubsNotConferenceable() {
+        mTestTelephonyConnectionB.setPhoneAccountHandle(PHONE_ACCOUNT_HANDLE_2);
+        mControllerTest.add(mTestTelephonyConnectionA);
+        mControllerTest.add(mTestTelephonyConnectionB);
+
+        mTestTelephonyConnectionA.setActive();
+        mTestTelephonyConnectionB.setTelephonyConnectionOnHold();
+
+        assertFalse(mTestTelephonyConnectionA.getConferenceables()
+                .contains(mTestTelephonyConnectionB));
+        assertFalse(mTestTelephonyConnectionB.getConferenceables()
+                .contains(mTestTelephonyConnectionA));
+    }
+
+    /**
      * Behavior: add telephony connection B and A to conference controller,
      *           set status for merged connections
      * Assumption: after performing the behaviors, the status of Connection A is STATE_ACTIVE;
diff --git a/tests/src/com/android/services/telephony/ImsConferenceTest.java b/tests/src/com/android/services/telephony/ImsConferenceTest.java
index 9d2f5ac..5123858 100644
--- a/tests/src/com/android/services/telephony/ImsConferenceTest.java
+++ b/tests/src/com/android/services/telephony/ImsConferenceTest.java
@@ -590,7 +590,7 @@
 
         ImsConference imsConference = new ImsConference(mMockTelecomAccountRegistry,
                 mMockTelephonyConnectionServiceProxy, mConferenceHost,
-                null /* phoneAccountHandle */, () -> false /* featureFlagProxy */,
+                null /* phoneAccountHandle */, () -> true /* isUsingSinglePartyCallEmulation */,
                 new ImsConference.CarrierConfiguration.Builder()
                         .setShouldLocalDisconnectEmptyConference(true)
                         .build());
@@ -622,6 +622,109 @@
     }
 
     /**
+     * Preconditions: both single party emulation and local disconnect of empty conferences is
+     * enabled.
+     * Tests the case where we receive a repeat with the same single-party data that caused a
+     * conference to be treated as a single party; we need to verify that we do not disconnect the
+     * conference locally in this case.
+     * @throws Exception
+     */
+    @Test
+    @SmallTest
+    public void testNoLocalDisconnectSinglePartyConferenceOnRepeatedCep() throws Exception {
+        when(mMockTelecomAccountRegistry.isUsingSimCallManager(any(PhoneAccountHandle.class)))
+                .thenReturn(false);
+
+        ImsConference imsConference = new ImsConference(mMockTelecomAccountRegistry,
+                mMockTelephonyConnectionServiceProxy, mConferenceHost,
+                null /* phoneAccountHandle */, () -> true /* isUsingSinglePartyCallEmulation */,
+                new ImsConference.CarrierConfiguration.Builder()
+                        .setShouldLocalDisconnectEmptyConference(true)
+                        .build());
+
+        ConferenceParticipant participant1 = new ConferenceParticipant(
+                Uri.parse("tel:6505551212"),
+                "A",
+                Uri.parse("sip:[email protected]"),
+                Connection.STATE_ACTIVE,
+                Call.Details.DIRECTION_INCOMING);
+        ConferenceParticipant participant2 = new ConferenceParticipant(
+                Uri.parse("tel:6505551213"),
+                "A",
+                Uri.parse("sip:[email protected]"),
+                Connection.STATE_ACTIVE,
+                Call.Details.DIRECTION_INCOMING);
+        imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
+                Arrays.asList(participant1, participant2));
+        assertEquals(2, imsConference.getNumberOfParticipants());
+
+        // Drop to 1 participant which enters single party mode.
+        imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
+                Arrays.asList(participant1));
+        assertEquals(0, imsConference.getNumberOfParticipants());
+
+        // Get a repeat CEP with the same participant data; we should still be in single party mode
+        // but we should NOT disconnect the conference.
+        imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
+                Arrays.asList(participant1));
+        assertEquals(0, imsConference.getNumberOfParticipants());
+        verify(mConferenceHost.mMockCall, never()).hangup();
+    }
+
+    /**
+     * An extension of {@link #testNoLocalDisconnectSinglePartyConferenceOnRepeatedCep()} where we
+     * get a repeated CEP with the same single party state, but then finally get a CEP with no
+     * participants anymore.  In this case we do expect a local disconnect as the final state.
+     * @throws Exception
+     */
+    @Test
+    @SmallTest
+    public void testLocalDisconnectSinglePartyConferenceOnRepeatedCep() throws Exception {
+        when(mMockTelecomAccountRegistry.isUsingSimCallManager(any(PhoneAccountHandle.class)))
+                .thenReturn(false);
+
+        ImsConference imsConference = new ImsConference(mMockTelecomAccountRegistry,
+                mMockTelephonyConnectionServiceProxy, mConferenceHost,
+                null /* phoneAccountHandle */, () -> true /* isUsingSinglePartyCallEmulation */,
+                new ImsConference.CarrierConfiguration.Builder()
+                        .setShouldLocalDisconnectEmptyConference(true)
+                        .build());
+
+        ConferenceParticipant participant1 = new ConferenceParticipant(
+                Uri.parse("tel:6505551212"),
+                "A",
+                Uri.parse("sip:[email protected]"),
+                Connection.STATE_ACTIVE,
+                Call.Details.DIRECTION_INCOMING);
+        ConferenceParticipant participant2 = new ConferenceParticipant(
+                Uri.parse("tel:6505551213"),
+                "A",
+                Uri.parse("sip:[email protected]"),
+                Connection.STATE_ACTIVE,
+                Call.Details.DIRECTION_INCOMING);
+        imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
+                Arrays.asList(participant1, participant2));
+        assertEquals(2, imsConference.getNumberOfParticipants());
+
+        // Drop to 1 participant which enters single party mode.
+        imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
+                Arrays.asList(participant1));
+        assertEquals(0, imsConference.getNumberOfParticipants());
+
+        // Get a repeat CEP with the same participant data; we should still be in single party mode
+        // but we should NOT disconnect the conference.
+        imsConference.handleConferenceParticipantsUpdate(mConferenceHost,
+                Arrays.asList(participant1));
+        assertEquals(0, imsConference.getNumberOfParticipants());
+        verify(mConferenceHost.mMockCall, never()).hangup();
+
+        // Got another CEP that has no participants at all; we should disconnet in this case
+        imsConference.handleConferenceParticipantsUpdate(mConferenceHost, Collections.emptyList());
+        assertEquals(0, imsConference.getNumberOfParticipants());
+        verify(mConferenceHost.mMockCall).hangup();
+    }
+
+    /**
      * Tests a scenario where a handover connection arrives via
      * {@link TelephonyConnection#onOriginalConnectionRedialed(
      * com.android.internal.telephony.Connection)}.  During this process, the conference properties
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index ba064e5..f115a43 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -18,6 +18,7 @@
 
 import static android.telephony.DisconnectCause.EMERGENCY_PERM_FAILURE;
 import static android.telephony.DisconnectCause.EMERGENCY_TEMP_FAILURE;
+import static android.telephony.DisconnectCause.ERROR_UNSPECIFIED;
 import static android.telephony.DisconnectCause.NOT_DISCONNECTED;
 import static android.telephony.DomainSelectionService.SELECTOR_TYPE_CALLING;
 import static android.telephony.NetworkRegistrationInfo.DOMAIN_CS;
@@ -38,6 +39,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -53,10 +55,14 @@
 import android.os.AsyncResult;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Looper;
+import android.telecom.Conference;
+import android.telecom.Conferenceable;
 import android.telecom.ConnectionRequest;
 import android.telecom.DisconnectCause;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import android.telephony.CarrierConfigManager;
 import android.telephony.DomainSelectionService;
 import android.telephony.RadioAccessFamily;
 import android.telephony.ServiceState;
@@ -87,6 +93,7 @@
 import com.android.internal.telephony.emergency.EmergencyStateTracker;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
 import com.android.internal.telephony.imsphone.ImsPhone;
+import com.android.internal.telephony.satellite.SatelliteSOSMessageRecommender;
 
 import org.junit.After;
 import org.junit.Before;
@@ -97,6 +104,8 @@
 import org.mockito.Mockito;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -115,6 +124,8 @@
      */
     public static class SimpleTelephonyConnection extends TelephonyConnection {
         public boolean wasDisconnected = false;
+        public boolean wasUnheld = false;
+        public boolean wasHeld = false;
 
         @Override
         public TelephonyConnection cloneConnection() {
@@ -125,6 +136,29 @@
         public void hangup(int telephonyDisconnectCode) {
             wasDisconnected = true;
         }
+
+        @Override
+        public void onUnhold() {
+            wasUnheld = true;
+        }
+
+        @Override
+        public void onHold() {
+            wasHeld = true;
+        }
+    }
+
+    public static class SimpleConference extends Conference {
+        public boolean wasUnheld = false;
+
+        public SimpleConference(PhoneAccountHandle phoneAccountHandle) {
+            super(phoneAccountHandle);
+        }
+
+        @Override
+        public void onUnhold() {
+            wasUnheld = true;
+        }
     }
 
     private static final long TIMEOUT_MS = 100;
@@ -165,6 +199,8 @@
     @Mock EmergencyCallDomainSelectionConnection mEmergencyCallDomainSelectionConnection;
     @Mock NormalCallDomainSelectionConnection mNormalCallDomainSelectionConnection;
     @Mock ImsPhone mImsPhone;
+    @Mock
+    private SatelliteSOSMessageRecommender mSatelliteSOSMessageRecommender;
     private EmergencyStateTracker mEmergencyStateTracker;
     private Phone mPhone0;
     private Phone mPhone1;
@@ -191,6 +227,7 @@
     @Before
     public void setUp() throws Exception {
         super.setUp();
+        doReturn(Looper.getMainLooper()).when(mContext).getMainLooper();
         mTestConnectionService = new TestTelephonyConnectionService(mContext);
         mTestConnectionService.setPhoneFactoryProxy(mPhoneFactoryProxy);
         mTestConnectionService.setSubscriptionManagerProxy(mSubscriptionManagerProxy);
@@ -216,6 +253,11 @@
         mEmergencyStateTracker = Mockito.mock(EmergencyStateTracker.class);
         replaceInstance(TelephonyConnectionService.class, "mEmergencyStateTracker",
                 mTestConnectionService, mEmergencyStateTracker);
+        replaceInstance(TelephonyConnectionService.class, "mSatelliteSOSMessageRecommender",
+                mTestConnectionService, mSatelliteSOSMessageRecommender);
+        doNothing().when(mSatelliteSOSMessageRecommender).onEmergencyCallStarted(any(), any());
+        doNothing().when(mSatelliteSOSMessageRecommender).onEmergencyCallConnectionStateChanged(
+                anyString(), anyInt());
         doReturn(CompletableFuture.completedFuture(NOT_DISCONNECTED))
                 .when(mEmergencyStateTracker)
                 .startEmergencyCall(any(), anyString(), eq(false));
@@ -1159,6 +1201,222 @@
     }
 
     /**
+     * Test that the TelephonyConnectionService successfully performs a DDS switch before a call
+     * when we are not roaming and the carrier only supports SUPL over the data plane.
+     */
+    @Test
+    @SmallTest
+    public void testCreateOutgoingEmergencyConnection_delayDial_carrierconfig_dds() {
+        // Setup test to not support SUPL on the non-DDS subscription
+        doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
+        getTestContext().getCarrierConfig(0 /*subId*/).putStringArray(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
+                null);
+        getTestContext().getCarrierConfig(0 /*subId*/).putInt(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
+                CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY);
+        getTestContext().getCarrierConfig(0 /*subId*/).putString(
+                CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "150");
+
+        Phone testPhone = setupConnectionServiceForDelayDial(
+                false /* isRoaming */, false /* setOperatorName */, null /* operator long name*/,
+                        null /* operator short name */, null /* operator numeric name */);
+        verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(0) /*phoneId*/ ,
+                eq(150) /*extensionTime*/, any());
+    }
+
+    /**
+     * Test that the TelephonyConnectionService successfully turns radio on before placing the
+     * emergency call.
+     */
+    @Test
+    @SmallTest
+    public void testCreateOutgoingEmerge_exitingApm_disconnected() {
+        when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
+        Phone testPhone = setupConnectionServiceInApm();
+
+        ArgumentCaptor<RadioOnStateListener.Callback> callback =
+                ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
+        verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
+                eq(testPhone), eq(false));
+
+        assertFalse(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+        when(mSST.isRadioOn()).thenReturn(true);
+        assertTrue(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+
+        mConnection.setDisconnected(null);
+        callback.getValue().onComplete(null, true);
+        for (Phone phone : mPhoneFactoryProxy.getPhones()) {
+            verify(phone).setRadioPower(true, false, false, true);
+        }
+    }
+
+    /**
+     * Test that the TelephonyConnectionService successfully turns radio on before placing the
+     * emergency call.
+     */
+    @Test
+    @SmallTest
+    public void testCreateOutgoingEmergencyConnection_exitingApm_placeCall() {
+        when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
+        Phone testPhone = setupConnectionServiceInApm();
+
+        ArgumentCaptor<RadioOnStateListener.Callback> callback =
+                ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
+        verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
+                eq(testPhone), eq(false));
+
+        assertFalse(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+        when(mSST.isRadioOn()).thenReturn(true);
+        assertTrue(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+
+        callback.getValue().onComplete(null, true);
+
+        try {
+            doAnswer(invocation -> null).when(mContext).startActivity(any());
+            verify(testPhone).dial(anyString(), any(), any());
+        } catch (CallStateException e) {
+            // This shouldn't happen
+            fail();
+        }
+        verify(mSatelliteSOSMessageRecommender).onEmergencyCallStarted(any(), any());
+    }
+
+    /**
+     * Test that the TelephonyConnectionService does not perform a DDS switch when the carrier
+     * supports control-plane fallback.
+     */
+    @Test
+    @SmallTest
+    public void testCreateOutgoingEmergencyConnection_delayDial_nocarrierconfig() {
+        // Setup test to not support SUPL on the non-DDS subscription
+        doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
+        getTestContext().getCarrierConfig(0 /*subId*/).putStringArray(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
+                null);
+        getTestContext().getCarrierConfig(0 /*subId*/).putInt(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
+                CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK);
+        getTestContext().getCarrierConfig(0 /*subId*/).putString(
+                CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
+
+        Phone testPhone = setupConnectionServiceForDelayDial(
+                false /* isRoaming */, false /* setOperatorName */, null /* operator long name*/,
+                        null /* operator short name */, null /* operator numeric name */);
+        verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any());
+    }
+
+    /**
+     * Test that the TelephonyConnectionService does not perform a DDS switch when the carrier
+     * supports control-plane fallback.
+     */
+    @Test
+    @SmallTest
+    public void testCreateOutgoingEmergencyConnection_delayDial_supportsuplondds() {
+        // If the non-DDS supports SUPL, don't switch data
+        doReturn(false).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
+        getTestContext().getCarrierConfig(0 /*subId*/).putStringArray(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
+                null);
+        getTestContext().getCarrierConfig(0 /*subId*/).putInt(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
+                CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY);
+        getTestContext().getCarrierConfig(0 /*subId*/).putString(
+                CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
+
+        Phone testPhone = setupConnectionServiceForDelayDial(
+                false /* isRoaming */, false /* setOperatorName */, null /* operator long name*/,
+                         null /* operator short name */, null /* operator numeric name */);
+        verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any());
+    }
+
+    /**
+     * Test that the TelephonyConnectionService does not perform a DDS switch when the carrier does
+     * not support control-plane fallback CarrierConfig while roaming.
+     */
+    @Test
+    @SmallTest
+    public void testCreateOutgoingEmergencyConnection_delayDial_roaming_nocarrierconfig() {
+        // Setup test to not support SUPL on the non-DDS subscription
+        doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
+        getTestContext().getCarrierConfig(0 /*subId*/).putStringArray(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
+                null);
+        getTestContext().getCarrierConfig(0 /*subId*/).putInt(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
+                CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY);
+        getTestContext().getCarrierConfig(0 /*subId*/).putString(
+                CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
+
+        Phone testPhone = setupConnectionServiceForDelayDial(
+                true /* isRoaming */, false /* setOperatorName */, null /* operator long name*/,
+                         null /* operator short name */, null /* operator numeric name */);
+        verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any());
+    }
+
+    /**
+     * Test that the TelephonyConnectionService does perform a DDS switch even though the carrier
+     * supports control-plane fallback CarrierConfig and the roaming partner is configured to look
+     * like a home network.
+     */
+    @Test
+    @SmallTest
+    public void testCreateOutgoingEmergencyConnection_delayDial_roamingcarrierconfig() {
+        doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
+        // Setup voice roaming scenario
+        String testRoamingOperator = "001001";
+        // Setup test to not support SUPL on the non-DDS subscription
+        String[] roamingPlmns = new String[1];
+        roamingPlmns[0] = testRoamingOperator;
+        getTestContext().getCarrierConfig(0 /*subId*/).putStringArray(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
+                roamingPlmns);
+        getTestContext().getCarrierConfig(0 /*subId*/).putInt(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
+                CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK);
+        getTestContext().getCarrierConfig(0 /*subId*/).putString(
+                CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
+
+        Phone testPhone = setupConnectionServiceForDelayDial(
+                false /* isRoaming */, true /* setOperatorName */,
+                        "TestTel" /* operator long name*/, "TestTel" /* operator short name */,
+                                testRoamingOperator /* operator numeric name */);
+        verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(0) /*phoneId*/ ,
+                eq(0) /*extensionTime*/, any());
+    }
+
+    /**
+     * Test that the TelephonyConnectionService does perform a DDS switch even though the carrier
+     * supports control-plane fallback CarrierConfig if we are roaming and the roaming partner is
+     * configured to use data plane only SUPL.
+     */
+    @Test
+    @SmallTest
+    public void testCreateOutgoingEmergencyConnection_delayDial__roaming_roamingcarrierconfig() {
+        // Setup test to not support SUPL on the non-DDS subscription
+        doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
+        // Setup voice roaming scenario
+        String testRoamingOperator = "001001";
+        String[] roamingPlmns = new String[1];
+        roamingPlmns[0] = testRoamingOperator;
+        getTestContext().getCarrierConfig(0 /*subId*/).putStringArray(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
+                roamingPlmns);
+        getTestContext().getCarrierConfig(0 /*subId*/).putInt(
+                CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
+                CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK);
+        getTestContext().getCarrierConfig(0 /*subId*/).putString(
+                CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
+
+        Phone testPhone = setupConnectionServiceForDelayDial(
+                false /* isRoaming */, true /* setOperatorName */,
+                        "TestTel" /* operator long name*/, "TestTel" /* operator short name */,
+                                testRoamingOperator /* operator numeric name */);
+        verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(0) /*phoneId*/ ,
+                eq(0) /*extensionTime*/, any());
+    }
+
+    /**
      * Verifies for an incoming call on the same SIM that we don't set
      * {@link android.telecom.Connection#EXTRA_ANSWERING_DROPS_FG_CALL} on the incoming call extras.
      * @throws Exception
@@ -1364,6 +1622,85 @@
         assertFalse(tc1.wasDisconnected);
     }
 
+
+    /**
+     * For calls on the same sub, the Dialer implements the 'swap' functionality to perform hold and
+     * unhold, so we do not additionally unhold when 'hold' button is pressed.
+     */
+    @Test
+    @SmallTest
+    public void testDontUnholdOnSameSubForVirtualDsdaDevice() {
+        when(mTelephonyManagerProxy.isConcurrentCallsPossible()).thenReturn(true);
+
+        ArrayList<android.telecom.Connection> tcs = new ArrayList<>();
+        Collection<Conference> conferences = new ArrayList<>();
+        SimpleTelephonyConnection tc1 = createTestConnection(SUB1_HANDLE, 0, false);
+        tcs.add(tc1);
+        TelephonyConnectionService.maybeUnholdCallsOnOtherSubs(
+                tcs, conferences, SUB1_HANDLE, mTelephonyManagerProxy);
+        assertFalse(tc1.wasUnheld);
+    }
+
+    /**
+     * Triggering 'Hold' on 1 call will unhold the other call for DSDA or Virtual DSDA
+     * enabled devices, effectively constituting 'swap' functionality.
+     */
+    @Test
+    @SmallTest
+    public void testUnholdOnOtherSubForVirtualDsdaDevice() {
+        when(mTelephonyManagerProxy.isConcurrentCallsPossible()).thenReturn(true);
+
+        ArrayList<android.telecom.Connection> tcs = new ArrayList<>();
+        SimpleTelephonyConnection tc1 = createTestConnection(SUB1_HANDLE, 0, false);
+        tcs.add(tc1);
+        TelephonyConnectionService.maybeUnholdCallsOnOtherSubs(
+                tcs, new ArrayList<>(), SUB2_HANDLE, mTelephonyManagerProxy);
+        assertTrue(tc1.wasUnheld);
+    }
+
+    /**
+     * Verifies hold/unhold behavior for a conference on the other sub. It does not disturb the
+     * individual connections that participate in the conference.
+     */
+    @Test
+    @SmallTest
+    public void testUnholdConferenceOnOtherSubForVirtualDsdaDevice() {
+        when(mTelephonyManagerProxy.isConcurrentCallsPossible()).thenReturn(true);
+        SimpleTelephonyConnection tc1 =
+                createTestConnection(SUB1_HANDLE, 0, false);
+        SimpleTelephonyConnection tc2 =
+                createTestConnection(SUB1_HANDLE, 0, false);
+        List<android.telecom.Connection> conferenceParticipants = Arrays.asList(tc1, tc2);
+
+        SimpleConference testConference = createTestConference(SUB1_HANDLE, 0);
+        List<Conference> conferences = Arrays.asList(testConference);
+
+        TelephonyConnectionService.maybeUnholdCallsOnOtherSubs(
+                conferenceParticipants, conferences, SUB2_HANDLE, mTelephonyManagerProxy);
+
+        assertTrue(testConference.wasUnheld);
+        assertFalse(tc1.wasUnheld);
+        assertFalse(tc2.wasUnheld);
+    }
+
+    /**
+     * For DSDA devices, placing an outgoing call on a 2nd sub will hold the existing connection on
+     * the first sub.
+     */
+    @Test
+    @SmallTest
+    public void testHoldOnOtherSubForVirtualDsdaDevice() {
+        when(mTelephonyManagerProxy.isConcurrentCallsPossible()).thenReturn(true);
+
+        ArrayList<android.telecom.Connection> tcs = new ArrayList<>();
+        SimpleTelephonyConnection tc1 = createTestConnection(SUB1_HANDLE, 0, false);
+        tcs.add(tc1);
+        Conferenceable c = TelephonyConnectionService.maybeHoldCallsOnOtherSubs(
+                tcs, new ArrayList<>(), SUB2_HANDLE, mTelephonyManagerProxy);
+        assertTrue(c.equals(tc1));
+        assertTrue(tc1.wasHeld);
+    }
+
     /**
      * Verifies that TelephonyManager is used to determine whether a connection is Emergency when
      * creating an outgoing connection.
@@ -1398,6 +1735,7 @@
                 .getDomainSelectionConnection(eq(mPhone0), eq(SELECTOR_TYPE_CALLING), eq(true));
         verify(mEmergencyStateTracker)
                 .startEmergencyCall(eq(mPhone0), eq(TELECOM_CALL_ID1), eq(false));
+        verify(mSatelliteSOSMessageRecommender).onEmergencyCallStarted(any(), eq(mPhone0));
         verify(mEmergencyCallDomainSelectionConnection).createEmergencyConnection(any(), any());
 
         ArgumentCaptor<DialArgs> argsCaptor = ArgumentCaptor.forClass(DialArgs.class);
@@ -1427,6 +1765,7 @@
                 .getDomainSelectionConnection(eq(mPhone0), eq(SELECTOR_TYPE_CALLING), eq(true));
         verify(mEmergencyStateTracker)
                 .startEmergencyCall(eq(mPhone0), eq(TELECOM_CALL_ID1), eq(false));
+        verify(mSatelliteSOSMessageRecommender).onEmergencyCallStarted(any(), eq(mPhone0));
         verify(mEmergencyCallDomainSelectionConnection).createEmergencyConnection(any(), any());
 
         ArgumentCaptor<DialArgs> argsCaptor = ArgumentCaptor.forClass(DialArgs.class);
@@ -1457,6 +1796,7 @@
 
         verify(mEmergencyStateTracker, times(1))
                 .startEmergencyCall(eq(mPhone0), eq(TELECOM_CALL_ID1), eq(false));
+        verify(mSatelliteSOSMessageRecommender).onEmergencyCallStarted(any(), eq(mPhone0));
         verify(mDomainSelectionResolver, times(0))
                 .getDomainSelectionConnection(eq(mPhone0), eq(SELECTOR_TYPE_CALLING), eq(true));
         verify(mEmergencyCallDomainSelectionConnection, times(0))
@@ -1550,6 +1890,7 @@
         verify(mDomainSelectionResolver)
                 .getDomainSelectionConnection(eq(mPhone0), eq(SELECTOR_TYPE_CALLING), eq(false));
         verify(mNormalCallDomainSelectionConnection).createNormalConnection(any(), any());
+        verify(mSatelliteSOSMessageRecommender).onEmergencyCallStarted(any(), eq(mPhone0));
 
         ArgumentCaptor<DialArgs> argsCaptor = ArgumentCaptor.forClass(DialArgs.class);
 
@@ -1587,6 +1928,7 @@
                 .getDomainSelectionConnection(eq(mPhone0), eq(SELECTOR_TYPE_CALLING), eq(true));
         verify(mEmergencyStateTracker)
                 .startEmergencyCall(eq(mPhone0), eq(TELECOM_CALL_ID1), eq(false));
+        verify(mSatelliteSOSMessageRecommender).onEmergencyCallStarted(any(), eq(mPhone0));
         verify(mEmergencyCallDomainSelectionConnection).createEmergencyConnection(any(), any());
 
         ArgumentCaptor<DialArgs> argsCaptor = ArgumentCaptor.forClass(DialArgs.class);
@@ -1627,6 +1969,7 @@
                 .getDomainSelectionConnection(eq(mPhone0), eq(SELECTOR_TYPE_CALLING), eq(true));
         verify(mEmergencyStateTracker)
                 .startEmergencyCall(eq(mPhone0), eq(TELECOM_CALL_ID1), eq(false));
+        verify(mSatelliteSOSMessageRecommender).onEmergencyCallStarted(any(), eq(mPhone0));
         verify(mEmergencyCallDomainSelectionConnection).createEmergencyConnection(any(), any());
 
         ArgumentCaptor<DialArgs> argsCaptor = ArgumentCaptor.forClass(DialArgs.class);
@@ -1735,6 +2078,352 @@
     }
 
     @Test
+    public void testOnSelectionTerminatedUnspecified() throws Exception {
+        setupForCallTest();
+
+        doReturn(mEmergencyCallDomainSelectionConnection).when(mDomainSelectionResolver)
+                .getDomainSelectionConnection(any(), anyInt(), eq(true));
+        doReturn(mPhone0).when(mEmergencyCallDomainSelectionConnection).getPhone();
+        doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
+
+        doReturn(true).when(mDomainSelectionResolver).isDomainSelectionSupported();
+        doReturn(mImsPhone).when(mPhone0).getImsPhone();
+
+        mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
+                createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
+                        TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+
+        ArgumentCaptor<DomainSelectionConnection.DomainSelectionConnectionCallback> callbackCaptor =
+                ArgumentCaptor.forClass(
+                        DomainSelectionConnection.DomainSelectionConnectionCallback.class);
+
+        verify(mEmergencyCallDomainSelectionConnection).createEmergencyConnection(
+                any(), callbackCaptor.capture());
+
+        DomainSelectionConnection.DomainSelectionConnectionCallback callback =
+                callbackCaptor.getValue();
+
+        assertNotNull(callback);
+
+        callback.onSelectionTerminated(ERROR_UNSPECIFIED);
+
+        verify(mEmergencyCallDomainSelectionConnection).cancelSelection();
+        verify(mEmergencyStateTracker).endCall(eq(TELECOM_CALL_ID1));
+    }
+
+    @Test
+    public void testDomainSelectionLocalHangupStartEmergencyCall() throws Exception {
+        setupForCallTest();
+
+        int selectedDomain = DOMAIN_CS;
+
+        setupForDialForDomainSelection(mPhone0, selectedDomain, true);
+
+        CompletableFuture<Integer> future = new CompletableFuture<>();
+        doReturn(future).when(mEmergencyStateTracker)
+                .startEmergencyCall(any(), anyString(), eq(false));
+
+        mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
+                createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
+                        TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+
+        verify(mEmergencyStateTracker)
+                .startEmergencyCall(eq(mPhone0), eq(TELECOM_CALL_ID1), eq(false));
+
+        TelephonyConnection c = new TestTelephonyConnection();
+        c.setTelecomCallId(TELECOM_CALL_ID1);
+
+        // dialing is canceled
+        mTestConnectionService.onLocalHangup(c);
+
+        // startEmergencyCall has completed
+        future.complete(NOT_DISCONNECTED);
+
+        // verify that createEmergencyConnection is discarded
+        verify(mEmergencyCallDomainSelectionConnection, times(0))
+                .createEmergencyConnection(any(), any());
+    }
+
+    @Test
+    public void testDomainSelectionLocalHangupCreateEmergencyConnection() throws Exception {
+        setupForCallTest();
+
+        int selectedDomain = DOMAIN_CS;
+
+        setupForDialForDomainSelection(mPhone0, selectedDomain, true);
+
+        CompletableFuture<Integer> future = new CompletableFuture<>();
+        doReturn(future).when(mEmergencyCallDomainSelectionConnection)
+                .createEmergencyConnection(any(), any());
+
+        mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
+                createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
+                        TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+
+        verify(mEmergencyCallDomainSelectionConnection).createEmergencyConnection(any(), any());
+
+        TelephonyConnection c = new TestTelephonyConnection();
+        c.setTelecomCallId(TELECOM_CALL_ID1);
+
+        // dialing is canceled
+        mTestConnectionService.onLocalHangup(c);
+
+        // domain selection has completed
+        future.complete(selectedDomain);
+
+        // verify that dialing is discarded
+        verify(mPhone0, times(0)).dial(anyString(), any(), any());
+    }
+
+    @Test
+    public void testDomainSelectionRedialLocalHangupReselectDomain() throws Exception {
+        setupForCallTest();
+
+        int preciseDisconnectCause = com.android.internal.telephony.CallFailCause.ERROR_UNSPECIFIED;
+        int disconnectCause = android.telephony.DisconnectCause.ERROR_UNSPECIFIED;
+        int selectedDomain = DOMAIN_CS;
+
+        TestTelephonyConnection c = setupForReDialForDomainSelection(
+                mPhone0, selectedDomain, preciseDisconnectCause, disconnectCause, true);
+        c.setTelecomCallId(TELECOM_CALL_ID1);
+
+        CompletableFuture<Integer> future = new CompletableFuture<>();
+        doReturn(future).when(mEmergencyCallDomainSelectionConnection)
+                .reselectDomain(any());
+
+        assertTrue(mTestConnectionService.maybeReselectDomain(c, preciseDisconnectCause, null));
+        verify(mEmergencyCallDomainSelectionConnection).reselectDomain(any());
+
+        // dialing is canceled
+        mTestConnectionService.onLocalHangup(c);
+
+        // domain selection has completed
+        future.complete(selectedDomain);
+
+        // verify that dialing is discarded
+        verify(mPhone0, times(0)).dial(anyString(), any(), any());
+    }
+
+    @Test
+    public void testDomainSelectionNormalToEmergencyLocalHangupStartEmergencyCall()
+            throws Exception {
+        setupForCallTest();
+
+        int preciseDisconnectCause = com.android.internal.telephony.CallFailCause.ERROR_UNSPECIFIED;
+        int disconnectCause = android.telephony.DisconnectCause.ERROR_UNSPECIFIED;
+        int eccCategory = EMERGENCY_SERVICE_CATEGORY_POLICE;
+        int selectedDomain = DOMAIN_CS;
+
+        setupForDialForDomainSelection(mPhone0, selectedDomain, true);
+        doReturn(mPhone0).when(mImsPhone).getDefaultPhone();
+
+        TestTelephonyConnection c = setupForReDialForDomainSelection(
+                mImsPhone, selectedDomain, preciseDisconnectCause, disconnectCause, false);
+        c.setEmergencyServiceCategory(eccCategory);
+        c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
+        c.setTelecomCallId(TELECOM_CALL_ID1);
+
+        CompletableFuture<Integer> future = new CompletableFuture<>();
+        doReturn(future).when(mEmergencyStateTracker)
+                .startEmergencyCall(any(), anyString(), eq(false));
+
+        ImsReasonInfo reasonInfo = new ImsReasonInfo(CODE_SIP_ALTERNATE_EMERGENCY_CALL, 0, null);
+        assertTrue(mTestConnectionService.maybeReselectDomain(c,
+                  preciseDisconnectCause, reasonInfo));
+
+        verify(mEmergencyStateTracker)
+                .startEmergencyCall(eq(mPhone0), eq(TELECOM_CALL_ID1), eq(false));
+        verify(mSatelliteSOSMessageRecommender).onEmergencyCallStarted(any(), eq(mPhone0));
+
+        // dialing is canceled
+        mTestConnectionService.onLocalHangup(c);
+
+        // startEmergencyCall has completed
+        future.complete(NOT_DISCONNECTED);
+
+        // verify that createEmergencyConnection is discarded
+        verify(mEmergencyCallDomainSelectionConnection, times(0))
+                .createEmergencyConnection(any(), any());
+    }
+
+    @Test
+    public void testDomainSelectionNormalToEmergencyLocalHangupCreateEmergencyConnection()
+            throws Exception {
+        setupForCallTest();
+
+        int preciseDisconnectCause = com.android.internal.telephony.CallFailCause.ERROR_UNSPECIFIED;
+        int disconnectCause = android.telephony.DisconnectCause.ERROR_UNSPECIFIED;
+        int eccCategory = EMERGENCY_SERVICE_CATEGORY_POLICE;
+        int selectedDomain = DOMAIN_CS;
+
+        setupForDialForDomainSelection(mPhone0, selectedDomain, true);
+        doReturn(mPhone0).when(mImsPhone).getDefaultPhone();
+
+        TestTelephonyConnection c = setupForReDialForDomainSelection(
+                mImsPhone, selectedDomain, preciseDisconnectCause, disconnectCause, false);
+        c.setEmergencyServiceCategory(eccCategory);
+        c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
+        c.setTelecomCallId(TELECOM_CALL_ID1);
+
+        CompletableFuture<Integer> future = new CompletableFuture<>();
+        doReturn(future).when(mEmergencyCallDomainSelectionConnection)
+                .createEmergencyConnection(any(), any());
+
+        ImsReasonInfo reasonInfo = new ImsReasonInfo(CODE_SIP_ALTERNATE_EMERGENCY_CALL, 0, null);
+        assertTrue(mTestConnectionService.maybeReselectDomain(c,
+                  preciseDisconnectCause, reasonInfo));
+
+        verify(mEmergencyCallDomainSelectionConnection).createEmergencyConnection(any(), any());
+
+        // dialing is canceled
+        mTestConnectionService.onLocalHangup(c);
+
+        // domain selection has completed
+        future.complete(selectedDomain);
+
+        // verify that dialing is discarded
+        verify(mPhone0, times(0)).dial(anyString(), any(), any());
+    }
+
+    @Test
+    public void testDomainSelectionListenOriginalConnectionConfigChange() throws Exception {
+        setupForCallTest();
+
+        int selectedDomain = DOMAIN_PS;
+
+        setupForDialForDomainSelection(mPhone0, selectedDomain, true);
+
+        mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
+                createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
+                        TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+
+        verify(mDomainSelectionResolver)
+                .getDomainSelectionConnection(eq(mPhone0), eq(SELECTOR_TYPE_CALLING), eq(true));
+        verify(mEmergencyStateTracker)
+                .startEmergencyCall(eq(mPhone0), eq(TELECOM_CALL_ID1), eq(false));
+        verify(mSatelliteSOSMessageRecommender).onEmergencyCallStarted(any(), eq(mPhone0));
+        verify(mEmergencyCallDomainSelectionConnection).createEmergencyConnection(any(), any());
+        verify(mPhone0).dial(anyString(), any(), any());
+
+        TestTelephonyConnection c = new TestTelephonyConnection();
+        c.setTelecomCallId(TELECOM_CALL_ID1);
+        c.setIsImsConnection(true);
+        Connection orgConn = c.getOriginalConnection();
+        doReturn(PhoneConstants.PHONE_TYPE_IMS).when(orgConn).getPhoneType();
+
+        TelephonyConnection.TelephonyConnectionListener connectionListener =
+                mTestConnectionService.getEmergencyConnectionListener();
+        TelephonyConnection.TelephonyConnectionListener connectionSatelliteListener =
+                mTestConnectionService.getEmergencyConnectionSatelliteListener();
+
+        connectionListener.onOriginalConnectionConfigured(c);
+
+        verify(mEmergencyStateTracker, times(1)).onEmergencyCallDomainUpdated(
+                eq(PhoneConstants.PHONE_TYPE_IMS), eq(TELECOM_CALL_ID1));
+
+        verify(mEmergencyStateTracker, times(0)).onEmergencyCallStateChanged(
+                any(), eq(TELECOM_CALL_ID1));
+        verify(mSatelliteSOSMessageRecommender, times(0))
+                .onEmergencyCallConnectionStateChanged(eq(TELECOM_CALL_ID1), anyInt());
+
+        c.setActive();
+        doReturn(Call.State.ACTIVE).when(orgConn).getState();
+        connectionListener.onStateChanged(c, c.getState());
+        connectionSatelliteListener.onStateChanged(c, c.getState());
+
+        // ACTIVE sate is notified
+        verify(mEmergencyStateTracker, times(1)).onEmergencyCallStateChanged(
+                eq(Call.State.ACTIVE), eq(TELECOM_CALL_ID1));
+        verify(mSatelliteSOSMessageRecommender, times(1))
+                .onEmergencyCallConnectionStateChanged(eq(TELECOM_CALL_ID1),
+                        eq(android.telecom.Connection.STATE_ACTIVE));
+
+        // state change to HOLDING
+        c.setOnHold();
+        doReturn(Call.State.HOLDING).when(orgConn).getState();
+        connectionListener.onStateChanged(c, c.getState());
+        connectionSatelliteListener.onStateChanged(c, c.getState());
+
+        // state change not notified any more after CONNECTED once
+        verify(mEmergencyStateTracker, times(1)).onEmergencyCallStateChanged(
+                any(), eq(TELECOM_CALL_ID1));
+        verify(mSatelliteSOSMessageRecommender, times(1))
+                .onEmergencyCallConnectionStateChanged(eq(TELECOM_CALL_ID1), anyInt());
+
+        // state change to ACTIVE again
+        c.setActive();
+        doReturn(Call.State.ACTIVE).when(orgConn).getState();
+        connectionListener.onStateChanged(c, c.getState());
+        connectionSatelliteListener.onStateChanged(c, c.getState());
+
+        // state change not notified any more after CONNECTED once
+        verify(mEmergencyStateTracker, times(1)).onEmergencyCallStateChanged(
+                any(), eq(TELECOM_CALL_ID1));
+        verify(mSatelliteSOSMessageRecommender, times(1))
+                .onEmergencyCallConnectionStateChanged(eq(TELECOM_CALL_ID1), anyInt());
+
+        // SRVCC happens
+        c.setIsImsConnection(false);
+        orgConn = c.getOriginalConnection();
+        doReturn(PhoneConstants.PHONE_TYPE_GSM).when(orgConn).getPhoneType();
+        connectionListener.onOriginalConnectionConfigured(c);
+
+         // domain change notified
+        verify(mEmergencyStateTracker, times(1)).onEmergencyCallDomainUpdated(
+                eq(PhoneConstants.PHONE_TYPE_GSM), eq(TELECOM_CALL_ID1));
+
+        // state change to DISCONNECTED
+        c.setDisconnected(null);
+        doReturn(Call.State.DISCONNECTED).when(orgConn).getState();
+        connectionListener.onStateChanged(c, c.getState());
+        connectionSatelliteListener.onStateChanged(c, c.getState());
+
+        // state change not notified
+        verify(mEmergencyStateTracker, times(1)).onEmergencyCallStateChanged(
+                any(), eq(TELECOM_CALL_ID1));
+        verify(mSatelliteSOSMessageRecommender, times(1))
+                .onEmergencyCallConnectionStateChanged(eq(TELECOM_CALL_ID1), anyInt());
+    }
+
+    @Test
+    public void testDomainSelectionTempFailure() throws Exception {
+        setupForCallTest();
+
+        int preciseDisconnectCause =
+                com.android.internal.telephony.CallFailCause.EMERGENCY_TEMP_FAILURE;
+        int disconnectCause = android.telephony.DisconnectCause.EMERGENCY_TEMP_FAILURE;
+        int selectedDomain = DOMAIN_CS;
+
+        TestTelephonyConnection c = setupForReDialForDomainSelection(
+                mPhone0, selectedDomain, preciseDisconnectCause, disconnectCause, true);
+
+        doReturn(new CompletableFuture()).when(mEmergencyCallDomainSelectionConnection)
+                .reselectDomain(any());
+
+        assertTrue(mTestConnectionService.maybeReselectDomain(c, preciseDisconnectCause, null));
+        verify(mEmergencyCallDomainSelectionConnection).reselectDomain(any());
+    }
+
+    @Test
+    public void testDomainSelectionPermFailure() throws Exception {
+        setupForCallTest();
+
+        int preciseDisconnectCause =
+                com.android.internal.telephony.CallFailCause.EMERGENCY_PERM_FAILURE;
+        int disconnectCause = android.telephony.DisconnectCause.EMERGENCY_PERM_FAILURE;
+        int selectedDomain = DOMAIN_CS;
+
+        TestTelephonyConnection c = setupForReDialForDomainSelection(
+                mPhone0, selectedDomain, preciseDisconnectCause, disconnectCause, true);
+
+        doReturn(new CompletableFuture()).when(mEmergencyCallDomainSelectionConnection)
+                .reselectDomain(any());
+
+        assertTrue(mTestConnectionService.maybeReselectDomain(c, preciseDisconnectCause, null));
+        verify(mEmergencyCallDomainSelectionConnection).reselectDomain(any());
+    }
+
+    @Test
     public void testDomainSelectionWithMmiCode() {
         //UT domain selection should not be handled by new domain selector.
         doNothing().when(mContext).startActivity(any());
@@ -1758,6 +2447,7 @@
         verify(mDomainSelectionResolver)
                 .getDomainSelectionConnection(eq(mPhone0), eq(SELECTOR_TYPE_CALLING), eq(false));
         verify(mNormalCallDomainSelectionConnection).createNormalConnection(any(), any());
+        verify(mSatelliteSOSMessageRecommender, never()).onEmergencyCallStarted(any(), any());
 
         ArgumentCaptor<DialArgs> argsCaptor = ArgumentCaptor.forClass(DialArgs.class);
 
@@ -1782,6 +2472,7 @@
         verify(mDomainSelectionResolver)
                 .getDomainSelectionConnection(eq(mPhone0), eq(SELECTOR_TYPE_CALLING), eq(false));
         verify(mNormalCallDomainSelectionConnection).createNormalConnection(any(), any());
+        verify(mSatelliteSOSMessageRecommender, never()).onEmergencyCallStarted(any(), any());
 
         ArgumentCaptor<DialArgs> argsCaptor = ArgumentCaptor.forClass(DialArgs.class);
 
@@ -1862,6 +2553,12 @@
         return connection;
     }
 
+    private SimpleConference createTestConference(PhoneAccountHandle handle, int properties) {
+        SimpleConference conference = new SimpleConference(handle);
+        conference.setConnectionProperties(properties);
+        return conference;
+    }
+
     /**
      * Setup the mess of mocks for {@link #testSecondCallSameSubWontDisconnect()} and
      * {@link #testIncomingDoesntRequestDisconnect()}.
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionTest.java
index 758ded7..bf9fa01 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionTest.java
@@ -1,6 +1,9 @@
 package com.android.services.telephony;
 
 import static android.telecom.Connection.STATE_DISCONNECTED;
+import static android.telephony.ims.ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED;
+import static android.telephony.ims.ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL;
+import static android.telephony.ims.ImsReasonInfo.EXTRA_CODE_CALL_RETRY_EMERGENCY;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertNotNull;
@@ -23,6 +26,8 @@
 import android.telecom.Connection;
 import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
+import android.telephony.emergency.EmergencyNumber;
+import android.telephony.ims.ImsReasonInfo;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -39,6 +44,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
+
 @RunWith(AndroidJUnit4.class)
 public class TelephonyConnectionTest {
     @Mock
@@ -306,4 +313,58 @@
         assertNotEquals(STATE_DISCONNECTED, c.getState());
         assertTrue(c.isOriginalConnectionCleared());
     }
+
+    @Test
+    public void testDomainSelectionDisconnected_AlternateService() {
+        TestTelephonyConnection c = new TestTelephonyConnection();
+        c.setOriginalConnection(mImsPhoneConnection);
+        c.setIsImsConnection(true);
+        doReturn(Call.State.DISCONNECTED).when(mImsPhoneConnection)
+                .getState();
+        doReturn(new ImsReasonInfo(CODE_SIP_ALTERNATE_EMERGENCY_CALL, 0, null))
+                .when(mImsPhoneConnection).getImsReasonInfo();
+        doReturn(getEmergencyNumber(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE))
+                .when(mImsPhoneConnection).getEmergencyNumberInfo();
+        c.setTelephonyConnectionService(mTelephonyConnectionService);
+        doReturn(true).when(mTelephonyConnectionService)
+                .maybeReselectDomain(any(), anyInt(), any());
+        c.updateState();
+
+        Integer serviceCategory = c.getEmergencyServiceCategory();
+
+        assertNotNull(serviceCategory);
+        assertEquals(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE,
+                serviceCategory.intValue());
+    }
+
+    @Test
+    public void testDomainSelectionDisconnected_SilentRedialEmergency() {
+        TestTelephonyConnection c = new TestTelephonyConnection();
+        c.setOriginalConnection(mImsPhoneConnection);
+        c.setIsImsConnection(true);
+        doReturn(Call.State.DISCONNECTED).when(mImsPhoneConnection)
+                .getState();
+        doReturn(new ImsReasonInfo(CODE_LOCAL_CALL_CS_RETRY_REQUIRED,
+                        EXTRA_CODE_CALL_RETRY_EMERGENCY, null))
+                .when(mImsPhoneConnection).getImsReasonInfo();
+        doReturn(getEmergencyNumber(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE))
+                .when(mImsPhoneConnection).getEmergencyNumberInfo();
+        c.setTelephonyConnectionService(mTelephonyConnectionService);
+        doReturn(true).when(mTelephonyConnectionService)
+                .maybeReselectDomain(any(), anyInt(), any());
+        c.updateState();
+
+        Integer serviceCategory = c.getEmergencyServiceCategory();
+
+        assertNotNull(serviceCategory);
+        assertEquals(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE,
+                serviceCategory.intValue());
+    }
+
+    private EmergencyNumber getEmergencyNumber(int eccCategory) {
+        return new EmergencyNumber("", "", "", eccCategory,
+            new ArrayList<String>(),
+            EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING,
+            EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN);
+    }
 }
diff --git a/tests/src/com/android/services/telephony/domainselection/CrossSimRedialingControllerTest.java b/tests/src/com/android/services/telephony/domainselection/CrossSimRedialingControllerTest.java
new file mode 100644
index 0000000..a32329d
--- /dev/null
+++ b/tests/src/com/android/services/telephony/domainselection/CrossSimRedialingControllerTest.java
@@ -0,0 +1,494 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.services.telephony.domainselection;
+
+import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_CROSS_STACK_REDIAL_TIMER_SEC_INT;
+import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT;
+import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_START_QUICK_CROSS_STACK_REDIAL_TIMER_WHEN_REGISTERED_BOOL;
+import static android.telephony.CarrierConfigManager.ImsEmergency.REDIAL_TIMER_DISABLED;
+import static android.telephony.PreciseDisconnectCause.EMERGENCY_PERM_FAILURE;
+import static android.telephony.PreciseDisconnectCause.EMERGENCY_TEMP_FAILURE;
+
+import static com.android.services.telephony.domainselection.CrossSimRedialingController.MSG_CROSS_STACK_TIMEOUT;
+import static com.android.services.telephony.domainselection.CrossSimRedialingController.MSG_QUICK_CROSS_STACK_TIMEOUT;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+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.ArgumentMatchers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit tests for CrossSimRedialingController
+ */
+public class CrossSimRedialingControllerTest {
+    private static final String TAG = "CrossSimRedialingControllerTest";
+
+    private static final int SLOT_0 = 0;
+    private static final int SLOT_1 = 1;
+
+    private static final String TELECOM_CALL_ID1 = "TC1";
+    private static final String TEST_EMERGENCY_NUMBER = "911";
+
+    @Mock private CarrierConfigManager mCarrierConfigManager;
+    @Mock private TelephonyManager mTelephonyManager;
+    @Mock private EmergencyCallDomainSelector mEcds;
+    @Mock private CrossSimRedialingController.EmergencyNumberHelper mEmergencyNumberHelper;
+
+    private Context mContext;
+
+    private HandlerThread mHandlerThread;
+    private TestableLooper mLooper;
+    private CrossSimRedialingController mCsrController;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mContext = new TestContext() {
+            @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 "";
+            }
+        };
+
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+
+        mHandlerThread = new HandlerThread("CrossSimRedialingControllerTest");
+        mHandlerThread.start();
+
+        try {
+            mLooper = new TestableLooper(mHandlerThread.getLooper());
+        } catch (Exception e) {
+            logd("Unable to create looper from handler.");
+        }
+
+        mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+        when(mTelephonyManager.createForSubscriptionId(anyInt()))
+                .thenReturn(mTelephonyManager);
+        when(mTelephonyManager.getNetworkCountryIso()).thenReturn("");
+        doReturn(2).when(mTelephonyManager).getActiveModemCount();
+        doReturn(TelephonyManager.SIM_STATE_READY)
+                .when(mTelephonyManager).getSimState(anyInt());
+
+        mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
+        doReturn(getDefaultPersistableBundle()).when(mCarrierConfigManager)
+                .getConfigForSubId(anyInt(), ArgumentMatchers.<String>any());
+
+        doReturn(true).when(mEmergencyNumberHelper).isEmergencyNumber(anyInt(), anyString());
+
+        doReturn(SLOT_0).when(mEcds).getSlotId();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (mCsrController != null) {
+            mCsrController.destroy();
+            mCsrController = null;
+        }
+
+        if (mLooper != null) {
+            mLooper.destroy();
+            mLooper = null;
+        }
+    }
+
+    @Test
+    public void testDefaultStartTimerInService() throws Exception {
+        createController();
+
+        boolean inService = true;
+        boolean inRoaming = false;
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertFalse(mCsrController.hasMessages(MSG_QUICK_CROSS_STACK_TIMEOUT));
+        assertTrue(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+
+        mCsrController.sendEmptyMessage(MSG_CROSS_STACK_TIMEOUT);
+        processAllMessages();
+
+        verify(mEcds).notifyCrossStackTimerExpired();
+    }
+
+    @Test
+    public void testDefaultStartTimerInServiceRoaming() throws Exception {
+        createController();
+
+        boolean inService = true;
+        boolean inRoaming = true;
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertFalse(mCsrController.hasMessages(MSG_QUICK_CROSS_STACK_TIMEOUT));
+        assertTrue(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+    }
+
+    @Test
+    public void testDefaultStartTimerOutOfService() throws Exception {
+        createController();
+
+        boolean inService = false;
+        boolean inRoaming = false;
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertFalse(mCsrController.hasMessages(MSG_QUICK_CROSS_STACK_TIMEOUT));
+        assertTrue(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+    }
+
+    @Test
+    public void testDefaultStartTimerOutOfServiceRoaming() throws Exception {
+        createController();
+
+        boolean inService = false;
+        boolean inRoaming = true;
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertFalse(mCsrController.hasMessages(MSG_QUICK_CROSS_STACK_TIMEOUT));
+        assertTrue(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+    }
+
+    @Test
+    public void testQuickStartTimerInService() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putInt(KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT, 3);
+        doReturn(bundle).when(mCarrierConfigManager)
+                .getConfigForSubId(anyInt(), ArgumentMatchers.<String>any());
+
+        createController();
+
+        boolean inService = true;
+        boolean inRoaming = false;
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertTrue(mCsrController.hasMessages(MSG_QUICK_CROSS_STACK_TIMEOUT));
+        assertFalse(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+
+        mCsrController.sendEmptyMessage(MSG_QUICK_CROSS_STACK_TIMEOUT);
+        processAllMessages();
+
+        verify(mEcds).notifyCrossStackTimerExpired();
+    }
+
+    @Test
+    public void testQuickStartTimerInServiceRoaming() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putInt(KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT, 3);
+        doReturn(bundle).when(mCarrierConfigManager)
+                .getConfigForSubId(anyInt(), ArgumentMatchers.<String>any());
+
+        createController();
+
+        boolean inService = true;
+        boolean inRoaming = true;
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertFalse(mCsrController.hasMessages(MSG_QUICK_CROSS_STACK_TIMEOUT));
+        assertTrue(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+    }
+
+    @Test
+    public void testQuickStartTimerOutOfService() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putInt(KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT, 3);
+        doReturn(bundle).when(mCarrierConfigManager)
+                .getConfigForSubId(anyInt(), ArgumentMatchers.<String>any());
+
+        createController();
+
+        boolean inService = false;
+        boolean inRoaming = false;
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertTrue(mCsrController.hasMessages(MSG_QUICK_CROSS_STACK_TIMEOUT));
+        assertFalse(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+    }
+
+    @Test
+    public void testQuickStartTimerOutOfServiceRoaming() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putInt(KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT, 3);
+        doReturn(bundle).when(mCarrierConfigManager)
+                .getConfigForSubId(anyInt(), ArgumentMatchers.<String>any());
+
+        createController();
+
+        boolean inService = false;
+        boolean inRoaming = true;
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertFalse(mCsrController.hasMessages(MSG_QUICK_CROSS_STACK_TIMEOUT));
+        assertTrue(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+    }
+
+    @Test
+    public void testNoNormalStartTimerInService() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putInt(KEY_CROSS_STACK_REDIAL_TIMER_SEC_INT, REDIAL_TIMER_DISABLED);
+        doReturn(bundle).when(mCarrierConfigManager)
+                .getConfigForSubId(anyInt(), ArgumentMatchers.<String>any());
+
+        createController();
+
+        boolean inService = true;
+        boolean inRoaming = false;
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertFalse(mCsrController.hasMessages(MSG_QUICK_CROSS_STACK_TIMEOUT));
+        assertFalse(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+    }
+
+    @Test
+    public void testQuickWhenInServiceStartTimerOutOfService() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putInt(KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT, 3);
+        bundle.putBoolean(KEY_START_QUICK_CROSS_STACK_REDIAL_TIMER_WHEN_REGISTERED_BOOL, true);
+        doReturn(bundle).when(mCarrierConfigManager)
+                .getConfigForSubId(anyInt(), ArgumentMatchers.<String>any());
+
+        createController();
+
+        boolean inService = false;
+        boolean inRoaming = false;
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertFalse(mCsrController.hasMessages(MSG_QUICK_CROSS_STACK_TIMEOUT));
+        assertTrue(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+    }
+
+    @Test
+    public void testQuickNoNormalStartTimerInService() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putInt(KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT, 3);
+        bundle.putInt(KEY_CROSS_STACK_REDIAL_TIMER_SEC_INT, REDIAL_TIMER_DISABLED);
+        doReturn(bundle).when(mCarrierConfigManager)
+                .getConfigForSubId(anyInt(), ArgumentMatchers.<String>any());
+
+        createController();
+
+        boolean inService = true;
+        boolean inRoaming = false;
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertTrue(mCsrController.hasMessages(MSG_QUICK_CROSS_STACK_TIMEOUT));
+        assertFalse(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+    }
+
+    @Test
+    public void testDefaultSlot0ThenSlot1() throws Exception {
+        createController();
+
+        boolean inService = true;
+        boolean inRoaming = false;
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertTrue(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+
+        mCsrController.removeMessages(MSG_CROSS_STACK_TIMEOUT);
+        assertFalse(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+
+        doReturn(SLOT_1).when(mEcds).getSlotId();
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertTrue(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+    }
+
+    @Test
+    public void testDefaultSlot0PermThenSlot1Timeout() throws Exception {
+        createController();
+
+        boolean inService = true;
+        boolean inRoaming = false;
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertTrue(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+
+        mCsrController.notifyCallFailure(EMERGENCY_PERM_FAILURE);
+        mCsrController.stopTimer();
+        assertFalse(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+
+        doReturn(SLOT_1).when(mEcds).getSlotId();
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertTrue(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+
+        mCsrController.sendEmptyMessage(MSG_CROSS_STACK_TIMEOUT);
+        processAllMessages();
+
+        verify(mEcds, times(0)).notifyCrossStackTimerExpired();
+    }
+
+    @Test
+    public void testDefaultSlot0TempThenSlot1Timeout() throws Exception {
+        createController();
+
+        boolean inService = true;
+        boolean inRoaming = false;
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertTrue(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+
+        mCsrController.notifyCallFailure(EMERGENCY_TEMP_FAILURE);
+        mCsrController.stopTimer();
+        assertFalse(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+
+        doReturn(SLOT_1).when(mEcds).getSlotId();
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertTrue(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+
+        mCsrController.sendEmptyMessage(MSG_CROSS_STACK_TIMEOUT);
+        processAllMessages();
+
+        verify(mEcds).notifyCrossStackTimerExpired();
+    }
+
+    @Test
+    public void testDefaultSlot0TempThenSlot1TimeoutNotEmergencyNumber() throws Exception {
+        createController();
+
+        boolean inService = true;
+        boolean inRoaming = false;
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertTrue(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+
+        mCsrController.notifyCallFailure(EMERGENCY_TEMP_FAILURE);
+        mCsrController.stopTimer();
+        assertFalse(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+
+        doReturn(SLOT_1).when(mEcds).getSlotId();
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertTrue(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+
+        doReturn(false).when(mEmergencyNumberHelper).isEmergencyNumber(anyInt(), anyString());
+        mCsrController.sendEmptyMessage(MSG_CROSS_STACK_TIMEOUT);
+        processAllMessages();
+
+        verify(mEcds, times(0)).notifyCrossStackTimerExpired();
+    }
+
+    @Test
+    public void testDefaultSlot0TempThenSlot1TimeoutPinLocked() throws Exception {
+        createController();
+
+        boolean inService = true;
+        boolean inRoaming = false;
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertTrue(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+
+        mCsrController.notifyCallFailure(EMERGENCY_TEMP_FAILURE);
+        mCsrController.stopTimer();
+        assertFalse(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+
+        doReturn(SLOT_1).when(mEcds).getSlotId();
+        mCsrController.startTimer(mContext, mEcds, TELECOM_CALL_ID1,
+                TEST_EMERGENCY_NUMBER, inService, inRoaming, 2);
+
+        assertTrue(mCsrController.hasMessages(MSG_CROSS_STACK_TIMEOUT));
+
+        doReturn(TelephonyManager.SIM_STATE_PIN_REQUIRED)
+                .when(mTelephonyManager).getSimState(anyInt());
+        mCsrController.sendEmptyMessage(MSG_CROSS_STACK_TIMEOUT);
+        processAllMessages();
+
+        verify(mEcds, times(0)).notifyCrossStackTimerExpired();
+    }
+
+    private void createController() throws Exception {
+        mCsrController = new CrossSimRedialingController(mContext,
+                mHandlerThread.getLooper(), mEmergencyNumberHelper);
+    }
+
+    private static PersistableBundle getDefaultPersistableBundle() {
+        return getPersistableBundle(0, 120, false);
+    }
+
+    private static PersistableBundle getPersistableBundle(
+            int quickTimer, int timer, boolean startQuickInService) {
+        PersistableBundle bundle  = new PersistableBundle();
+        bundle.putInt(KEY_QUICK_CROSS_STACK_REDIAL_TIMER_SEC_INT, quickTimer);
+        bundle.putInt(KEY_CROSS_STACK_REDIAL_TIMER_SEC_INT, timer);
+        bundle.putBoolean(KEY_START_QUICK_CROSS_STACK_REDIAL_TIMER_WHEN_REGISTERED_BOOL,
+                startQuickInService);
+
+        return bundle;
+    }
+
+    private void processAllMessages() {
+        while (!mLooper.getLooper().getQueue().isIdle()) {
+            mLooper.processAllMessages();
+        }
+    }
+
+    private static void logd(String str) {
+        Log.d(TAG, str);
+    }
+}
diff --git a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
index 27b3f0a..0821943 100644
--- a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
@@ -18,6 +18,7 @@
 
 import static android.telephony.AccessNetworkConstants.AccessNetworkType.EUTRAN;
 import static android.telephony.AccessNetworkConstants.AccessNetworkType.GERAN;
+import static android.telephony.AccessNetworkConstants.AccessNetworkType.NGRAN;
 import static android.telephony.AccessNetworkConstants.AccessNetworkType.UNKNOWN;
 import static android.telephony.AccessNetworkConstants.AccessNetworkType.UTRAN;
 import static android.telephony.BarringInfo.BARRING_SERVICE_TYPE_EMERGENCY;
@@ -38,6 +39,8 @@
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT;
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT;
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL;
+import static android.telephony.CarrierConfigManager.ImsEmergency.SCAN_TYPE_FULL_SERVICE;
+import static android.telephony.CarrierConfigManager.ImsEmergency.SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE;
 import static android.telephony.CarrierConfigManager.ImsEmergency.SCAN_TYPE_NO_PREFERENCE;
 import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_NONE;
 import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_SETTING_ENABLED;
@@ -52,9 +55,12 @@
 import static com.android.services.telephony.domainselection.EmergencyCallDomainSelector.MSG_NETWORK_SCAN_TIMEOUT;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
 import static junit.framework.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;
@@ -85,6 +91,7 @@
 import android.telephony.DomainSelectionService.SelectionAttributes;
 import android.telephony.EmergencyRegResult;
 import android.telephony.NetworkRegistrationInfo;
+import android.telephony.PreciseDisconnectCause;
 import android.telephony.TelephonyManager;
 import android.telephony.TransportSelectorCallback;
 import android.telephony.WwanSelectorCallback;
@@ -128,6 +135,7 @@
     @Mock private ImsStateTracker mImsStateTracker;
     @Mock private DomainSelectorBase.DestroyListener mDestroyListener;
     @Mock private ProvisioningManager mProvisioningManager;
+    @Mock private CrossSimRedialingController mCsrdCtrl;
 
     private Context mContext;
 
@@ -138,6 +146,7 @@
     private @AccessNetworkConstants.RadioAccessNetworkType List<Integer> mAccessNetwork;
     private PowerManager mPowerManager;
     private ConnectivityManager.NetworkCallback mNetworkCallback;
+    private Consumer<EmergencyRegResult> mResultConsumer;
 
     @Before
     public void setUp() throws Exception {
@@ -236,6 +245,7 @@
             @Override
             public Void answer(InvocationOnMock invocation) throws Throwable {
                 mAccessNetwork = (List<Integer>) invocation.getArguments()[0];
+                mResultConsumer = (Consumer<EmergencyRegResult>) invocation.getArguments()[3];
                 return null;
             }
         }).when(mWwanSelectorCallback).onRequestEmergencyNetworkScan(
@@ -262,7 +272,7 @@
 
         verify(mWwanSelectorCallback, times(0)).onRequestEmergencyNetworkScan(
                 any(), anyInt(), any(), any());
-        verify(mWwanSelectorCallback, times(0)).onDomainSelected(anyInt());
+        verify(mWwanSelectorCallback, times(0)).onDomainSelected(anyInt(), eq(true));
     }
 
     @Test
@@ -300,6 +310,28 @@
     }
 
     @Test
+    public void testDefaultCombinedImsRegisteredSelectPsThenCsfb() 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();
+    }
+
+    @Test
     public void testDefaultCombinedImsNotRegisteredSelectCs() throws Exception {
         createSelector(SLOT_0_SUB_ID);
         unsolBarringInfoChanged(false);
@@ -955,13 +987,13 @@
         assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
 
         // Wi-Fi is not connected.
-        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected(anyBoolean());
 
         // Wi-Fi is connected.
         mNetworkCallback.onAvailable(null);
         mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
 
-        verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected(eq(true));
     }
 
     @Test
@@ -987,20 +1019,20 @@
         mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
 
         // Wi-Fi is not connected.
-        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected(anyBoolean());
 
         // Wi-Fi is connected. But Wi-Fi calling setting is disabled.
         mNetworkCallback.onAvailable(null);
         when(mMmTelManager.isVoWiFiRoamingSettingEnabled()).thenReturn(false);
         mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
 
-        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected(anyBoolean());
 
         // Wi-Fi is connected and Wi-Fi calling setting is enabled.
         when(mMmTelManager.isVoWiFiSettingEnabled()).thenReturn(true);
         mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
 
-        verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected(eq(true));
     }
 
     @Test
@@ -1026,19 +1058,19 @@
         mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
 
         // Wi-Fi is not connected.
-        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected(anyBoolean());
 
         // Wi-Fi is connected. But Wi-Fi calling s not activated.
         mNetworkCallback.onAvailable(null);
         mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
 
-        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected(anyBoolean());
 
         // Wi-Fi is connected and Wi-Fi calling is activated.
         doReturn("1").when(mProvisioningManager).getProvisioningStringValue(anyInt());
         mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
 
-        verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected(eq(true));
     }
 
     @Test
@@ -1059,19 +1091,19 @@
         mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
 
         // Wi-Fi is not connected.
-        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected(anyBoolean());
 
         // Wi-Fi is connected but IMS is not registered over Wi-Fi.
         mNetworkCallback.onAvailable(null);
         mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
 
-        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected(anyBoolean());
 
         // IMS is registered over Wi-Fi.
         bindImsService(true);
         mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
 
-        verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected(eq(false));
     }
 
     @Test
@@ -1098,13 +1130,13 @@
 
         mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
 
-        verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected(eq(false));
 
         // duplicated event
         mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
 
         // ignore duplicated callback, no change in interaction
-        verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected(anyBoolean());
     }
 
     @Test
@@ -1114,6 +1146,7 @@
         doReturn(2).when(mTelephonyManager).getActiveModemCount();
         doReturn(TelephonyManager.SIM_STATE_PIN_REQUIRED)
                 .when(mTelephonyManager).getSimState(anyInt());
+        doReturn(true).when(mCsrdCtrl).isThereOtherSlot();
 
         EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_UNKNOWN,
                 0, false, false, 0, 0, "", "", "jp");
@@ -1128,10 +1161,567 @@
                 .onSelectionTerminated(eq(DisconnectCause.EMERGENCY_PERM_FAILURE));
     }
 
+    @Test
+    public void testDualSimInvalidSubscriptionButNoOtherSlot() 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(false).when(mCsrdCtrl).isThereOtherSlot();
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_UNKNOWN,
+                0, false, false, 0, 0, "", "", "jp");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+        processAllMessages();
+
+        verify(mTransportSelectorCallback, times(0))
+                .onSelectionTerminated(eq(DisconnectCause.EMERGENCY_PERM_FAILURE));
+        verifyScanPsPreferred();
+    }
+
+    @Test
+    public void testEutranWithCsDomainOnly() throws Exception {
+        setupForHandleScanResult();
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, 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);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+        mResultConsumer = null;
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(true);
+
+        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(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
+                any(), eq(DomainSelectionService.SCAN_TYPE_FULL_SERVICE), any(), any());
+        assertNotNull(mResultConsumer);
+
+        mResultConsumer.accept(regResult);
+        processAllMessages();
+
+        verify(mWwanSelectorCallback, times(2)).onRequestEmergencyNetworkScan(
+                any(), eq(DomainSelectionService.SCAN_TYPE_FULL_SERVICE), any(), any());
+    }
+
+    @Test
+    public void testFullServiceThenLimtedService() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT,
+                SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+        mResultConsumer = null;
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(true);
+
+        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(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
+                any(), eq(DomainSelectionService.SCAN_TYPE_FULL_SERVICE), any(), any());
+        assertNotNull(mResultConsumer);
+
+        mResultConsumer.accept(regResult);
+        processAllMessages();
+
+        verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
+                any(), eq(DomainSelectionService.SCAN_TYPE_LIMITED_SERVICE), any(), any());
+    }
+
+    @Test
+    public void testCsThenPsPreference() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        int[] domainPreference = new int[] {
+                CarrierConfigManager.ImsEmergency.DOMAIN_CS,
+                CarrierConfigManager.ImsEmergency.DOMAIN_PS_3GPP,
+                };
+        bundle.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY, domainPreference);
+
+        setupForScanListTest(bundle);
+
+        verifyCsPreferredScanList(mDomainSelector.getNextPreferredNetworks(false, false));
+    }
+
+    @Test
+    public void testPsThenCsPreference() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        int[] domainPreference = new int[] {
+                CarrierConfigManager.ImsEmergency.DOMAIN_PS_3GPP,
+                CarrierConfigManager.ImsEmergency.DOMAIN_CS,
+                };
+        bundle.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY, domainPreference);
+
+        setupForScanListTest(bundle);
+
+        verifyPsPreferredScanList(mDomainSelector.getNextPreferredNetworks(false, false));
+    }
+
+    @Test
+    public void testPsOnlyPreference() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        int[] domainPreference = new int[] {
+                CarrierConfigManager.ImsEmergency.DOMAIN_PS_3GPP,
+                };
+        bundle.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY, domainPreference);
+        bundle.putIntArray(KEY_EMERGENCY_OVER_CS_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY,
+                new int[0]);
+
+        setupForScanListTest(bundle);
+
+        verifyPsOnlyScanList(mDomainSelector.getNextPreferredNetworks(false, false));
+    }
+
+    @Test
+    public void testCsOnlyPreference() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        int[] domainPreference = new int[] {
+                CarrierConfigManager.ImsEmergency.DOMAIN_CS,
+                };
+        bundle.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY, domainPreference);
+        bundle.putIntArray(KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY,
+                new int[0]);
+
+        setupForScanListTest(bundle);
+
+        verifyCsOnlyScanList(mDomainSelector.getNextPreferredNetworks(false, false));
+
+    }
+
+    @Test
+    public void testCsThenPsPreferenceCsPreferred() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        int[] domainPreference = new int[] {
+                CarrierConfigManager.ImsEmergency.DOMAIN_CS,
+                CarrierConfigManager.ImsEmergency.DOMAIN_PS_3GPP,
+                };
+        bundle.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY, domainPreference);
+
+        setupForScanListTest(bundle);
+
+        verifyCsPreferredScanList(mDomainSelector.getNextPreferredNetworks(true, false));
+    }
+
+    @Test
+    public void testPsThenCsPreferenceCsPreferred() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        int[] domainPreference = new int[] {
+                CarrierConfigManager.ImsEmergency.DOMAIN_PS_3GPP,
+                CarrierConfigManager.ImsEmergency.DOMAIN_CS,
+                };
+        bundle.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY, domainPreference);
+
+        setupForScanListTest(bundle);
+
+        verifyCsPreferredScanList(mDomainSelector.getNextPreferredNetworks(true, false));
+    }
+
+    @Test
+    public void testPsOnlyPreferenceCsPreferred() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        int[] domainPreference = new int[] {
+                CarrierConfigManager.ImsEmergency.DOMAIN_PS_3GPP,
+                CarrierConfigManager.ImsEmergency.DOMAIN_CS,
+                };
+        bundle.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY, domainPreference);
+        bundle.putIntArray(KEY_EMERGENCY_OVER_CS_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY,
+                new int[0]);
+
+        setupForScanListTest(bundle);
+
+        verifyPsOnlyScanList(mDomainSelector.getNextPreferredNetworks(true, false));
+    }
+
+    @Test
+    public void testCsOnlyPreferenceCsPreferred() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        int[] domainPreference = new int[] {
+                CarrierConfigManager.ImsEmergency.DOMAIN_CS,
+                };
+        bundle.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY, domainPreference);
+        bundle.putIntArray(KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY,
+                new int[0]);
+
+        setupForScanListTest(bundle);
+
+        verifyCsOnlyScanList(mDomainSelector.getNextPreferredNetworks(true, false));
+    }
+
+    @Test
+    public void testCsThenPsPreferencePsFail() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        int[] domainPreference = new int[] {
+                CarrierConfigManager.ImsEmergency.DOMAIN_CS,
+                CarrierConfigManager.ImsEmergency.DOMAIN_PS_3GPP,
+                };
+        bundle.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY, domainPreference);
+
+        setupForScanListTest(bundle, true);
+
+        bindImsService();
+        processAllMessages();
+
+        verifyCsPreferredScanList(mDomainSelector.getNextPreferredNetworks(false, false));
+    }
+
+    @Test
+    public void testPsThenCsPreferencePsFail() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        int[] domainPreference = new int[] {
+                CarrierConfigManager.ImsEmergency.DOMAIN_PS_3GPP,
+                CarrierConfigManager.ImsEmergency.DOMAIN_CS,
+                };
+        bundle.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY, domainPreference);
+
+        setupForScanListTest(bundle, true);
+
+        bindImsService();
+        processAllMessages();
+
+        verifyCsPreferredScanList(mDomainSelector.getNextPreferredNetworks(false, false));
+    }
+
+    @Test
+    public void testPsOnlyPreferencePsFail() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        int[] domainPreference = new int[] {
+                CarrierConfigManager.ImsEmergency.DOMAIN_PS_3GPP,
+                };
+        bundle.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY, domainPreference);
+        bundle.putIntArray(KEY_EMERGENCY_OVER_CS_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY,
+                new int[0]);
+
+        setupForScanListTest(bundle, true);
+
+        bindImsService();
+        processAllMessages();
+
+        verifyPsOnlyScanList(mDomainSelector.getNextPreferredNetworks(false, false));
+    }
+
+    @Test
+    public void testCsThenPsPreferencePsFailCsPreferred() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        int[] domainPreference = new int[] {
+                CarrierConfigManager.ImsEmergency.DOMAIN_CS,
+                CarrierConfigManager.ImsEmergency.DOMAIN_PS_3GPP,
+                };
+        bundle.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY, domainPreference);
+
+        setupForScanListTest(bundle, true);
+
+        bindImsService();
+        processAllMessages();
+
+        verifyCsPreferredScanList(mDomainSelector.getNextPreferredNetworks(true, false));
+    }
+
+    @Test
+    public void testPsThenCsPreferencePsFailCsPreferred() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        int[] domainPreference = new int[] {
+                CarrierConfigManager.ImsEmergency.DOMAIN_PS_3GPP,
+                CarrierConfigManager.ImsEmergency.DOMAIN_CS,
+                };
+        bundle.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY, domainPreference);
+
+        setupForScanListTest(bundle, true);
+
+        bindImsService();
+        processAllMessages();
+
+        verifyCsPreferredScanList(mDomainSelector.getNextPreferredNetworks(true, false));
+    }
+
+    @Test
+    public void testPsOnlyPreferencePsFailCsPreferred() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        int[] domainPreference = new int[] {
+                CarrierConfigManager.ImsEmergency.DOMAIN_PS_3GPP,
+                CarrierConfigManager.ImsEmergency.DOMAIN_CS,
+                };
+        bundle.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY, domainPreference);
+        bundle.putIntArray(KEY_EMERGENCY_OVER_CS_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY,
+                new int[0]);
+
+        setupForScanListTest(bundle, true);
+
+        bindImsService();
+        processAllMessages();
+
+        verifyPsOnlyScanList(mDomainSelector.getNextPreferredNetworks(true, false));
+    }
+
+    @Test
+    public void testEpsFallbackThenCsPreference() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        int[] domainPreference = new int[] {
+                CarrierConfigManager.ImsEmergency.DOMAIN_PS_3GPP,
+                CarrierConfigManager.ImsEmergency.DOMAIN_CS,
+                };
+        bundle.putIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY, domainPreference);
+        bundle.putIntArray(KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY,
+                    new int[] { NGRAN, EUTRAN });
+
+        setupForScanListTest(bundle);
+
+        List<Integer> networks = mDomainSelector.getNextPreferredNetworks(false, true);
+
+        assertFalse(networks.isEmpty());
+        assertTrue(networks.contains(EUTRAN));
+        assertTrue(networks.contains(NGRAN));
+        assertTrue(networks.contains(UTRAN));
+        assertTrue(networks.contains(GERAN));
+        assertTrue(networks.indexOf(EUTRAN) < networks.indexOf(UTRAN));
+        assertTrue(networks.indexOf(UTRAN) < networks.indexOf(GERAN));
+        assertTrue(networks.indexOf(GERAN) < networks.indexOf(NGRAN));
+    }
+
+    @Test
+    public void testStartCrossStackTimer() throws Exception {
+        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();
+
+        processAllMessages();
+        verify(mCsrdCtrl).startTimer(any(), eq(mDomainSelector), any(),
+                any(), anyBoolean(), anyBoolean(), anyInt());
+    }
+
+    @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);
+
+        mDomainSelector.finishSelection();
+
+        verify(mCsrdCtrl).stopTimer();
+    }
+
+    @Test
+    public void testCrossStackTimerTempFailure() throws Exception {
+        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();
+
+        attr = new SelectionAttributes.Builder(SLOT_0, SLOT_0_SUB_ID, SELECTOR_TYPE_CALLING)
+                .setEmergency(true)
+                .setEmergencyRegResult(regResult)
+                .setCsDisconnectCause(PreciseDisconnectCause.EMERGENCY_TEMP_FAILURE)
+                .build();
+
+        mDomainSelector.reselectDomain(attr);
+        processAllMessages();
+
+        verify(mCsrdCtrl).notifyCallFailure(eq(PreciseDisconnectCause.EMERGENCY_TEMP_FAILURE));
+    }
+
+    @Test
+    public void testCrossStackTimerPermFailure() throws Exception {
+        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();
+
+        attr = new SelectionAttributes.Builder(SLOT_0, SLOT_0_SUB_ID, SELECTOR_TYPE_CALLING)
+                .setEmergency(true)
+                .setEmergencyRegResult(regResult)
+                .setCsDisconnectCause(PreciseDisconnectCause.EMERGENCY_PERM_FAILURE)
+                .build();
+
+        mDomainSelector.reselectDomain(attr);
+        processAllMessages();
+
+        verify(mCsrdCtrl).notifyCallFailure(eq(PreciseDisconnectCause.EMERGENCY_PERM_FAILURE));
+    }
+
+    @Test
+    public void testCrossStackTimerExpired() throws Exception {
+        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();
+
+        verifyScanPsPreferred();
+
+        mDomainSelector.notifyCrossStackTimerExpired();
+
+        verify(mTransportSelectorCallback)
+                .onSelectionTerminated(eq(DisconnectCause.EMERGENCY_TEMP_FAILURE));
+    }
+
+    @Test
+    public void testCrossStackTimerExpiredAfterDomainSelected() throws Exception {
+        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();
+
+        mDomainSelector.notifyCrossStackTimerExpired();
+
+        verify(mTransportSelectorCallback, times(0))
+                .onSelectionTerminated(eq(DisconnectCause.EMERGENCY_TEMP_FAILURE));
+
+        mDomainSelector.reselectDomain(attr);
+        processAllMessages();
+
+        verify(mTransportSelectorCallback)
+                .onSelectionTerminated(eq(DisconnectCause.EMERGENCY_TEMP_FAILURE));
+    }
+
+    private void setupForScanListTest(PersistableBundle bundle) throws Exception {
+        setupForScanListTest(bundle, false);
+    }
+
+    private void setupForScanListTest(PersistableBundle bundle, boolean psFailed) throws Exception {
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_UNKNOWN,
+                0, false, false, 0, 0, "", "");
+        if (psFailed) {
+            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();
+    }
+
+    private void verifyCsPreferredScanList(List<Integer> networks) {
+        assertFalse(networks.isEmpty());
+        assertTrue(networks.contains(EUTRAN));
+        assertTrue(networks.contains(UTRAN));
+        assertTrue(networks.contains(GERAN));
+        assertTrue(networks.indexOf(UTRAN) < networks.indexOf(EUTRAN));
+    }
+
+    private void verifyPsPreferredScanList(List<Integer> networks) {
+        assertFalse(networks.isEmpty());
+        assertTrue(networks.contains(EUTRAN));
+        assertTrue(networks.contains(UTRAN));
+        assertTrue(networks.contains(GERAN));
+        assertTrue(networks.indexOf(EUTRAN) < networks.indexOf(UTRAN));
+    }
+
+    private void verifyPsOnlyScanList(List<Integer> networks) {
+        assertFalse(networks.isEmpty());
+        assertTrue(networks.contains(EUTRAN));
+        assertFalse(networks.contains(UTRAN));
+        assertFalse(networks.contains(GERAN));
+    }
+
+    private void verifyCsOnlyScanList(List<Integer> networks) {
+        assertFalse(networks.isEmpty());
+        assertFalse(networks.contains(EUTRAN));
+        assertTrue(networks.contains(UTRAN));
+        assertTrue(networks.contains(GERAN));
+    }
+
+    private void setupForHandleScanResult() throws Exception {
+        mResultConsumer = null;
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(true);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, 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(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
+                any(), anyInt(), any(), any());
+        assertNotNull(mResultConsumer);
+    }
+
     private void createSelector(int subId) throws Exception {
         mDomainSelector = new EmergencyCallDomainSelector(
                 mContext, SLOT_0, subId, mHandlerThread.getLooper(),
-                mImsStateTracker, mDestroyListener);
+                mImsStateTracker, mDestroyListener, mCsrdCtrl);
 
         replaceInstance(DomainSelectorBase.class,
                 "mWwanSelectorCallback", mDomainSelector, mWwanSelectorCallback);
@@ -1139,12 +1729,12 @@
 
     private void verifyCsDialed() {
         processAllMessages();
-        verify(mWwanSelectorCallback, times(1)).onDomainSelected(eq(DOMAIN_CS));
+        verify(mWwanSelectorCallback, times(1)).onDomainSelected(eq(DOMAIN_CS), eq(false));
     }
 
     private void verifyPsDialed() {
         processAllMessages();
-        verify(mWwanSelectorCallback, times(1)).onDomainSelected(eq(DOMAIN_PS));
+        verify(mWwanSelectorCallback, times(1)).onDomainSelected(eq(DOMAIN_PS), eq(true));
     }
 
     private void verifyScanPsPreferred() {
diff --git a/tests/src/com/android/services/telephony/domainselection/EmergencySmsDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/EmergencySmsDomainSelectorTest.java
index 8b63530..1d89071 100644
--- a/tests/src/com/android/services/telephony/domainselection/EmergencySmsDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencySmsDomainSelectorTest.java
@@ -210,7 +210,8 @@
 
         processAllMessages();
 
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS),
+                eq(false));
         assertFalse(mDomainSelector.isDomainSelectionRequested());
     }
 
@@ -413,7 +414,8 @@
 
         // onDomainSelected will be invoked only once
         // even though the domain selection was requested twice.
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS),
+                eq(false));
         assertFalse(mDomainSelector.isDomainSelectionRequested());
     }
 
@@ -430,7 +432,8 @@
         processAllMessages();
 
         // Expected: CS network
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS),
+                eq(false));
     }
 
     @Test
@@ -446,7 +449,8 @@
         processAllMessages();
 
         // Expected: CS network
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS),
+                eq(false));
     }
 
     @Test
@@ -462,7 +466,8 @@
         processAllMessages();
 
         // Expected: CS network
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS),
+                eq(false));
     }
 
     @Test
@@ -478,7 +483,8 @@
         processAllMessages();
 
         // Expected: PS network
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS),
+                eq(false));
     }
 
     @Test
@@ -494,7 +500,8 @@
         processAllMessages();
 
         // Expected: CS network
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS),
+                eq(false));
     }
 
     @Test
@@ -510,7 +517,8 @@
         processAllMessages();
 
         // Expected: CS network
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS),
+                eq(false));
     }
 
     @Test
@@ -526,7 +534,8 @@
         processAllMessages();
 
         // Expected: PS network
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS),
+                eq(false));
     }
 
     @Test
@@ -542,7 +551,8 @@
         processAllMessages();
 
         // Expected: CS network
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS),
+                eq(false));
     }
 
     @Test
@@ -558,7 +568,8 @@
         processAllMessages();
 
         // Expected: CS network
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS),
+                eq(false));
     }
 
     @Test
@@ -574,7 +585,8 @@
         processAllMessages();
 
         // Expected: PS network
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS),
+                eq(false));
     }
 
     @Test
@@ -590,7 +602,8 @@
         processAllMessages();
 
         // Expected: CS network
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS),
+                eq(false));
     }
 
     @Test
@@ -606,7 +619,8 @@
         processAllMessages();
 
         // Expected: CS network
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS),
+                eq(false));
     }
 
     @Test
@@ -622,7 +636,7 @@
         processAllMessages();
 
         // Expected: WLAN
-        verify(mTransportSelectorCallback).onWlanSelected();
+        verify(mTransportSelectorCallback).onWlanSelected(eq(false));
     }
 
     @Test
@@ -641,7 +655,8 @@
         // if the emergency SMS messages over IMS is enabled in the carrier configuration and
         // the PS network does not allow the emergency service, this MO SMS should be routed to
         // CS domain.
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS),
+                eq(false));
     }
 
     @Test
@@ -657,7 +672,8 @@
         processAllMessages();
 
         // Expected: PS network
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS),
+                eq(false));
     }
 
     private void setUpCarrierConfig(boolean supported) {
diff --git a/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java
index 8780f1f..4dd1f3c 100644
--- a/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java
@@ -436,7 +436,7 @@
         }
 
         @Override
-        public synchronized void onWlanSelected() {
+        public synchronized void onWlanSelected(boolean useEmergencyPdn) {
             Log.d(TAG, "onWlanSelected");
             mWlanSelected = true;
             notifyAll();
@@ -504,7 +504,8 @@
 
         }
 
-        public synchronized void onDomainSelected(@NetworkRegistrationInfo.Domain int domain) {
+        public synchronized void onDomainSelected(@NetworkRegistrationInfo.Domain int domain,
+                boolean useEmergencyPdn) {
             Log.i(TAG, "onDomainSelected - called");
             mSelectedDomain = domain;
             mDomainSelected = true;
diff --git a/tests/src/com/android/services/telephony/domainselection/SmsDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/SmsDomainSelectorTest.java
index 412d83d..785127c 100644
--- a/tests/src/com/android/services/telephony/domainselection/SmsDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/SmsDomainSelectorTest.java
@@ -142,7 +142,8 @@
 
         processAllMessages();
 
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS),
+                eq(false));
         assertFalse(mDomainSelector.isDomainSelectionRequested());
     }
 
@@ -184,7 +185,8 @@
 
         // onDomainSelected will be invoked only once
         // even though the domain selection was requested twice.
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS),
+                eq(false));
         assertFalse(mDomainSelector.isDomainSelectionRequested());
     }
 
@@ -230,7 +232,8 @@
 
         processAllMessages();
 
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS),
+                eq(false));
         assertFalse(mDomainSelector.isDomainSelectionRequested());
 
         mDomainSelector.reselectDomain(mSelectionAttributes);
@@ -239,7 +242,7 @@
 
         processAllMessages();
 
-        verify(mTransportSelectorCallback).onWlanSelected();
+        verify(mTransportSelectorCallback).onWlanSelected(eq(false));
         assertFalse(mDomainSelector.isDomainSelectionRequested());
     }
 
@@ -256,9 +259,10 @@
         mDomainSelector.reselectDomain(mSelectionAttributes);
         processAllMessages();
 
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS),
+                eq(false));
         assertFalse(mDomainSelector.isDomainSelectionRequested());
-        verify(mTransportSelectorCallback, never()).onWlanSelected();
+        verify(mTransportSelectorCallback, never()).onWlanSelected(eq(false));
         assertFalse(mDomainSelector.isDomainSelectionRequested());
     }
 
@@ -275,7 +279,8 @@
 
         processAllMessages();
 
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS),
+                eq(false));
         assertFalse(mDomainSelector.isDomainSelectionRequested());
     }
 
@@ -292,7 +297,8 @@
 
         processAllMessages();
 
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS),
+                eq(false));
         assertFalse(mDomainSelector.isDomainSelectionRequested());
     }
 
@@ -309,7 +315,8 @@
 
         processAllMessages();
 
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS),
+                eq(false));
         assertFalse(mDomainSelector.isDomainSelectionRequested());
     }
 
@@ -326,7 +333,8 @@
 
         processAllMessages();
 
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS),
+                eq(false));
         assertFalse(mDomainSelector.isDomainSelectionRequested());
     }
 
@@ -343,7 +351,8 @@
 
         processAllMessages();
 
-        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS));
+        verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_CS),
+                eq(false));
         assertFalse(mDomainSelector.isDomainSelectionRequested());
     }
 
@@ -358,9 +367,10 @@
         processAllMessages();
 
         if (accessNetworkType == AccessNetworkType.IWLAN) {
-            verify(mTransportSelectorCallback).onWlanSelected();
+            verify(mTransportSelectorCallback).onWlanSelected(eq(false));
         } else {
-            verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS));
+            verify(mWwanSelectorCallback).onDomainSelected(eq(NetworkRegistrationInfo.DOMAIN_PS),
+                    eq(false));
         }
         assertFalse(mDomainSelector.isDomainSelectionRequested());
     }
diff --git a/tests/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionServiceTest.java b/tests/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionServiceTest.java
index ace59e3..f340e94 100644
--- a/tests/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionServiceTest.java
@@ -77,7 +77,8 @@
                 public DomainSelectorBase create(Context context, int slotId, int subId,
                         @SelectorType int selectorType, boolean isEmergency,
                         @NonNull Looper looper, @NonNull ImsStateTracker imsStateTracker,
-                        @NonNull DomainSelectorBase.DestroyListener listener) {
+                        @NonNull DomainSelectorBase.DestroyListener listener,
+                        @NonNull CrossSimRedialingController crossSimRedialingController) {
                     switch (selectorType) {
                         case DomainSelectionService.SELECTOR_TYPE_CALLING: // fallthrough
                         case DomainSelectionService.SELECTOR_TYPE_SMS: // fallthrough
diff --git a/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java b/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java
index 39469b6..d575d77 100644
--- a/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java
+++ b/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java
@@ -25,17 +25,20 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.app.PropertyInvalidatedCache;
 import android.content.BroadcastReceiver;
 import android.content.Intent;
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
 
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.TelephonyTestBase;
 import com.android.ims.FeatureConnector;
 import com.android.ims.RcsFeatureManager;
+import com.android.internal.telephony.ISub;
 
 import org.junit.After;
 import org.junit.Before;
@@ -59,12 +62,26 @@
     @Mock RcsFeatureController.FeatureConnectorFactory<RcsFeatureManager> mFeatureConnectorFactory;
     @Mock FeatureConnector<RcsFeatureManager> mFeatureConnector;
 
+    @Mock
+    private ISub mISub;
+
+    @Mock
+    private TelephonyManager mTelephonyManager;
+
     private RcsFeatureController mFeatureControllerSlot0;
     private RcsFeatureController mFeatureControllerSlot1;
 
     @Before
     public void setUp() throws Exception {
         super.setUp();
+        TelephonyManager.setupISubForTest(mISub);
+        TelephonyManager.enableServiceHandleCaching();
+        PropertyInvalidatedCache.disableForTestMode();
+
+        //set up default slot-> sub ID mappings.
+        setSlotToSubIdMapping(0 /*slotId*/, 1/*subId*/);
+        setSlotToSubIdMapping(1 /*slotId*/, 2/*subId*/);
+
         doReturn(mFeatureConnector).when(mFeatureConnectorFactory).create(any(), anyInt(),
                 any(), any(), any());
         mFeatureControllerSlot0 = createFeatureController(0 /*slotId*/, 1 /*subId*/);
@@ -82,9 +99,9 @@
         doReturn(mMockSipTransportSlot1).when(mFeatureFactory).createSipTransportController(any(),
                 eq(1), anyInt());
         doReturn(true).when(mResourceProxy).getDeviceUceEnabled(any());
-        //set up default slot-> sub ID mappings.
-        setSlotToSubIdMapping(0 /*slotId*/, 1/*subId*/);
-        setSlotToSubIdMapping(1 /*slotId*/, 2/*subId*/);
+
+        replaceInstance(TelephonyManager.class, "sInstance", null, mTelephonyManager);
+        doReturn(2).when(mTelephonyManager).getActiveModemCount();
     }
 
     @After
@@ -341,11 +358,8 @@
         bundle.putBoolean(key, value);
     }
 
-    private void setSlotToSubIdMapping(int slotId, int loadedSubId) {
-        SubscriptionManager m = mContext.getSystemService(SubscriptionManager.class);
-        int [] subIds = new int[1];
-        subIds[0] = loadedSubId;
-        doReturn(subIds).when(m).getSubscriptionIds(eq(slotId));
+    private void setSlotToSubIdMapping(int slotId, int loadedSubId) throws Exception {
+        doReturn(loadedSubId).when(mISub).getSubId(slotId);
     }
 
     private TelephonyRcsService createRcsService(int numSlots) {