Merge "Revert "Temporary additional logging for debugging b/182326102."" into sc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 08facfe..a4b107b 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -38,6 +38,7 @@
     <protected-broadcast android:name="android.intent.action.ACTION_MDN_STATE_CHANGED" />
     <protected-broadcast android:name="android.telephony.action.SERVICE_PROVIDERS_UPDATED" />
     <protected-broadcast android:name="android.provider.Telephony.SIM_FULL" />
+    <protected-broadcast android:name="com.android.internal.telephony.carrier_key_download_alarm" />
     <protected-broadcast android:name="com.android.internal.telephony.data-restart-trysetup" />
     <protected-broadcast android:name="com.android.internal.telephony.data-stall" />
     <protected-broadcast android:name="com.android.internal.telephony.provisioning_apn_alarm" />
@@ -133,8 +134,6 @@
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
     <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
     <uses-permission android:name="android.permission.VIBRATE" />
-    <uses-permission android:name="android.permission.BLUETOOTH" />
-    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
     <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
     <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
     <uses-permission android:name="android.permission.REORDER_TASKS" />
diff --git a/res/layout/radio_info.xml b/res/layout/radio_info.xml
index 72627a3..68c67a3 100644
--- a/res/layout/radio_info.xml
+++ b/res/layout/radio_info.xml
@@ -153,6 +153,12 @@
             <TextView android:id="@+id/nr_frequency" style="@style/info_value" />
         </LinearLayout>
 
+        <!-- NR Frequency -->
+        <LinearLayout style="@style/RadioInfo_entry_layout" android:orientation="horizontal">
+            <TextView android:id="@+id/network_slicing_config_label" android:text="@string/radio_info_network_slicing_config" style="@style/info_label" />
+            <TextView android:id="@+id/network_slicing_config" style="@style/info_value" />
+        </LinearLayout>
+
         <!-- Physical Channel Config -->
         <LinearLayout style="@style/RadioInfo_entry_layout">
             <TextView android:text="@string/radio_info_phy_chan_config" style="@style/info_label" />
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 6e2ec3f..8484549 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Wagwoord is verkeerd. SIM is nou geblokkeer. Voer PUK2 in."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 is permanent geblokkeer."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Jy het <xliff:g id="NUMBER">%d</xliff:g> oorblywende pogings."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 is gesluit. Kontak diensverskaffer om te ontsluit."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 is nie meer geblokkeer nie"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Netwerk- of SIM-kaartfout"</string>
     <string name="doneButton" msgid="7371209609238460207">"Klaar"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 0227314..571af43 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"የይለፍ ቃል ልክ አይደለም። SIM አሁን ተቆልፏል። PUK2 ያስገቡ።"</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"ፒን2 በቋሚነት ታግዷል።"</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"እርስዎ <xliff:g id="NUMBER">%d</xliff:g> ቀሪ ሙከራዎች አልዎት።"</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 ተቆልፏል። ለማስከፈት የአገልግሎት አቅራቢን ያነጋግሩ።"</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 ከአሁን በኋላ አልታገደም"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"የአውታረ መረብ ወይም የሲም ካርድ ስህተት"</string>
     <string name="doneButton" msgid="7371209609238460207">"ተከናውኗል"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 2f86eb3..271ead8 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"‏كلمة المرور غير صحيحة. تم قفل شريحة SIM الآن. أدخل رمز PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"‏تم حظر PUK2 بشكل دائم."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"يتبقى لديك <xliff:g id="NUMBER">%d</xliff:g> من المحاولات."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"‏تم قفل شريحة SIM برمز PUK2. تواصَل مع مقدّم الخدمة لفتح قفل الشريحة."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"‏لم يعد رمز PIN2 محظورًا"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"‏حدث خطأ في الشبكة أو ببطاقة SIM"</string>
     <string name="doneButton" msgid="7371209609238460207">"تم"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index a02f38f..67a192f 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"ভুল পাছৱৰ্ড। এতিয়া ছিম লক কৰা হৈছে। PUK2 লিখক।"</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 স্থায়ীভাৱে অৱৰোধ কৰা হৈছে।"</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"আপোনাৰ হাতত <xliff:g id="NUMBER">%d</xliff:g>টা প্ৰয়াস বাকী আছে।"</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 লক কৰা আছে। আনলক কৰিবলৈ সেৱা প্ৰদানকাৰীৰ সৈতে যোগাযোগ কৰক।"</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 আৰু অৱৰোধ হৈ থকা নাই"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"নেটৱৰ্ক বা ছিম কাৰ্ডৰ আসোঁৱাহ।"</string>
     <string name="doneButton" msgid="7371209609238460207">"হ’ল"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index e0cbd2c..4149e71 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Parol səhvdir. SIM indi kilidlənib. PUK2-ni daxil et."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 həmişəlik qapadıldı."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Sizin <xliff:g id="NUMBER">%d</xliff:g> cəhdiniz qalıb."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 kilidlidir. Açmaq üçün xidmət provayderi ilə əlaqə saxlayın."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 artıq bloklanmayıb"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Şəbəkə və ya SIM kart xətası"</string>
     <string name="doneButton" msgid="7371209609238460207">"Tamam"</string>
@@ -700,7 +701,7 @@
     <string name="change_pin_enter_new_pin_header" msgid="4739465616733486118">"Yeni PIN kodu təyin edin"</string>
     <string name="change_pin_enter_new_pin_hint" msgid="2326038476516364210">"PIN <xliff:g id="MIN">%1$d</xliff:g>-<xliff:g id="MAX">%2$d</xliff:g> rəqəm olmalıdır."</string>
     <string name="change_pin_confirm_pin_header" msgid="2606303906320705726">"PİN kodunuzu təsdiq edin"</string>
-    <string name="change_pin_confirm_pins_dont_match" msgid="305164501222587215">"PIN kodlar üst-üstə düşmür"</string>
+    <string name="change_pin_confirm_pins_dont_match" msgid="305164501222587215">"PIN-lər eyni deyil"</string>
     <string name="change_pin_succeeded" msgid="2504705600693014403">"Səsli poçtun PIN kodu yeniləndi"</string>
     <string name="change_pin_system_error" msgid="7772788809875146873">"PIN kodu ayarlamaq olmur"</string>
     <string name="mobile_data_status_roaming_turned_off_subtext" msgid="6840673347416227054">"Data rominq deaktivdir"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 57aec7d..ffe6f86 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Lozinka nije tačna. SIM je sada blokiran. Unesite PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 je trajno blokiran."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Imate još <xliff:g id="NUMBER">%d</xliff:g> pokušaja."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 je zaključan. Za otključavanje se obratite dobavljaču usluge."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 više nije blokiran"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Greška na mreži ili SIM kartici"</string>
     <string name="doneButton" msgid="7371209609238460207">"Gotovo"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 8b15471..ff1e5e2 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -294,7 +294,7 @@
     <string name="limited_sim_function_notification_title" msgid="612715399099846281">"Абмежаваныя функцыі SIM-карты"</string>
     <string name="limited_sim_function_with_phone_num_notification_message" msgid="5928988883403677610">"Выклікі і перадача даных праз <xliff:g id="CARRIER_NAME">%1$s</xliff:g> могуць блакіравацца пры выкарыстанні нумара <xliff:g id="PHONE_NUMBER">%2$s</xliff:g>."</string>
     <string name="limited_sim_function_notification_message" msgid="5338638075496721160">"Выклікі і перадача даных праз <xliff:g id="CARRIER_NAME">%1$s</xliff:g> блакіруюцца пры выкарыстанні іншай SIM-карты."</string>
-    <string name="sip_accounts_removed_notification_title" msgid="3528076957535736095">"Знойдзены і выдалены ўстарэлыя ўліковыя запісы SIP"</string>
+    <string name="sip_accounts_removed_notification_title" msgid="3528076957535736095">"Знойдзены і выдалены састарэлыя ўліковыя запісы SIP"</string>
     <string name="sip_accounts_removed_notification_message" msgid="1916856744869791592">"На платформе Android больш не падтрымліваецца SIP-тэлефанія.\nВашы існуючыя ўліковыя запісы SIP (<xliff:g id="REMOVED_SIP_ACCOUNTS">%s</xliff:g>) выдалены.\nПацвердзіце стандартны ўліковы запіс для выклікаў."</string>
     <string name="sip_accounts_removed_notification_action" msgid="3772778402370555562">"Перайсці ў налады"</string>
     <string name="data_usage_title" msgid="8438592133893837464">"Выкарыстанне трафіка"</string>
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Пароль няправільны. Зараз SIM-карта заблакіравана. Увядзіце код PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"Код PUK2 заблакіраваны назаўжды."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"У вас засталося спроб: <xliff:g id="NUMBER">%d</xliff:g>."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"Код PUK2 заблакіраваны. Для разблакіроўкі звярніцеся да пастаўшчыка паслуг."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"Код PIN2 больш не заблакіраваны"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Памылка сеткі або SIM-карты"</string>
     <string name="doneButton" msgid="7371209609238460207">"Гатова"</string>
@@ -930,5 +931,5 @@
     <string name="trigger_carrier_provisioning" msgid="1301829588620638234">"Запусціць сінхранізацыю з аператарам"</string>
     <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="notification_channel_sip_account" msgid="1261816025156179637">"Састарэлыя ўліковыя запісы SIP"</string>
 </resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 2466ada..74c36e0 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Паролата е неправилна. SIM картата вече е заключена. Въведете PUK2 кода."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 е блокиран завинаги."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Остават ви <xliff:g id="NUMBER">%d</xliff:g> опита."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"Заключена с PUK2. За отключване се обърнете към оператора."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"ПИН2 кодът вече не е блокиран"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Грешка в мрежата или SIM картата"</string>
     <string name="doneButton" msgid="7371209609238460207">"Готово"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 085904f..3832903 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"পাসওয়ার্ডটি ভুল৷ সিম এখন অবরুদ্ধ৷ PUK2 লিখুন৷"</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 স্থায়ীভাবে অবরুদ্ধ করা হয়েছে৷"</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"আপনার কাছে <xliff:g id="NUMBER">%d</xliff:g>টি প্রচেষ্টা অবশিষ্ট রয়েছে৷"</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 লক করা আছে। আনলক করতে পরিষেবা প্রদানকারীর সাথে যোগাযোগ করুন।"</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 এখন আর অবরুদ্ধ নয়"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"নেটওয়ার্ক বা সিম কার্ড ত্রুটি৷"</string>
     <string name="doneButton" msgid="7371209609238460207">"সম্পন্ন হয়েছে"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index f962bea..0714fcb 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Lozinka je netačna. SIM je sada zaključan. Unesite PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 je trajno blokiran."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Broj preostalih pokušaja: <xliff:g id="NUMBER">%d</xliff:g>."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"SIM je zaključan kodom PUK2. Kontaktirajte pružaoca usluge da ga otključate."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 više nije blokiran"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Greška na mreži ili SIM kartici"</string>
     <string name="doneButton" msgid="7371209609238460207">"Gotovo"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 70e1c9e..8a906fb 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"La contrasenya no és correcta i la SIM s\'ha bloquejat. Introdueix el PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"El PUK2 s\'ha bloquejat permanentment."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Et queden <xliff:g id="NUMBER">%d</xliff:g> intents."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"El PUK2 s\'ha bloquejat. Contacta amb el proveïdor de serveis per desbloquejar-lo."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"El PIN2 ja no està bloquejat."</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Error de la xarxa o de targeta SIM"</string>
     <string name="doneButton" msgid="7371209609238460207">"Fet"</string>
@@ -574,7 +575,7 @@
     <string name="description_concat_format" msgid="2014471565101724088">"%1$s, %2$s"</string>
     <string name="dialerKeyboardHintText" msgid="1115266533703764049">"Utilitzeu el teclat per marcar"</string>
     <string name="onscreenHoldText" msgid="4025348842151665191">"Posa en espera"</string>
-    <string name="onscreenEndCallText" msgid="6138725377654842757">"Final"</string>
+    <string name="onscreenEndCallText" msgid="6138725377654842757">"Finalitza"</string>
     <string name="onscreenShowDialpadText" msgid="658465753816164079">"Teclat"</string>
     <string name="onscreenMuteText" msgid="5470306116733843621">"Silencia"</string>
     <string name="onscreenAddCallText" msgid="9075675082903611677">"Afegeix una trucada"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 63aac81..914c04d 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Nesprávné heslo. SIM karta je teď uzamčena. Zadejte kód PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 je trvale zablokován."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Počet zbývajících pokusů: <xliff:g id="NUMBER">%d</xliff:g>."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"Uzamčeno kódem PUK2. Se žádostí o odemknutí SIM karty se obraťte na poskytovatele služeb."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 již není blokován"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Došlo k chybě sítě nebo SIM karty."</string>
     <string name="doneButton" msgid="7371209609238460207">"Hotovo"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 392a72e..8b92d31 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Forkert adgangskode. SIM-kortet er nu låst. Angiv PUK-kode 2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 er permanent blokeret."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Du har <xliff:g id="NUMBER">%d</xliff:g> forsøg tilbage."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2-låst. Kontakt din udbyder for at låse op."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"Pinkode 2 er ikke længere blokeret"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Fejl i netværk eller SIM-kort"</string>
     <string name="doneButton" msgid="7371209609238460207">"Afslut"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 925bb75..758cc34 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Passwort falsch. SIM-Karte ist jetzt gesperrt. Bitte PUK2 eingeben."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 wurde endgültig gesperrt."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Du hast noch <xliff:g id="NUMBER">%d</xliff:g> Versuche."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 gesperrt. Wende dich zum Entsperren an den Mobilfunkanbieter."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 nicht mehr gesperrt"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Netzwerk- oder SIM-Kartenfehler"</string>
     <string name="doneButton" msgid="7371209609238460207">"Fertig"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index d7a8240..55975a1 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Ο κωδικός πρόσβασης είναι λανθασμένος. Η SIM κλειδώθηκε. Καταχωρίστε το PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"Ο κωδικός PUK2 έχει μπλοκαριστεί οριστικά."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Απομένουν <xliff:g id="NUMBER">%d</xliff:g> προσπάθειες."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"Το PUK2 κλειδώθηκε. Επικοινωνήστε με τον πάροχο υπηρεσιών για ξεκλείδωμα."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"Το PIN2 δεν είναι πλέον αποκλεισμένο"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Σφάλμα δικτύου ή κάρτας SIM"</string>
     <string name="doneButton" msgid="7371209609238460207">"Τέλος"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 208a6a1..5e676c3 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Password incorrect. SIM now locked. Enter PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 is permanently blocked."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"You have <xliff:g id="NUMBER">%d</xliff:g> remaining attempts."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 locked. Contact service provider to unlock."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 no longer blocked"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Network or SIM card error"</string>
     <string name="doneButton" msgid="7371209609238460207">"Done"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 348f940..bc4169e 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Password incorrect. SIM now locked. Enter PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 is permanently blocked."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"You have <xliff:g id="NUMBER">%d</xliff:g> remaining attempts."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 locked. Contact service provider to unlock."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 no longer blocked"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Network or SIM card error"</string>
     <string name="doneButton" msgid="7371209609238460207">"Done"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 208a6a1..5e676c3 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Password incorrect. SIM now locked. Enter PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 is permanently blocked."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"You have <xliff:g id="NUMBER">%d</xliff:g> remaining attempts."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 locked. Contact service provider to unlock."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 no longer blocked"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Network or SIM card error"</string>
     <string name="doneButton" msgid="7371209609238460207">"Done"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 208a6a1..5e676c3 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Password incorrect. SIM now locked. Enter PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 is permanently blocked."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"You have <xliff:g id="NUMBER">%d</xliff:g> remaining attempts."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 locked. Contact service provider to unlock."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 no longer blocked"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Network or SIM card error"</string>
     <string name="doneButton" msgid="7371209609238460207">"Done"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 9527701..e69d221 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‎‏‎‎‎‎‎‎‎‏‏‏‏‎‏‏‎‎‏‏‎‏‏‏‏‎‎‏‎‎‏‏‏‎‏‎‎Password incorrect. SIM now locked. Enter PUK2.‎‏‎‎‏‎"</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‏‎‏‎‎‎‎‎‎‏‎‏‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‎‎‏‎‎‎‏‎‎‏‎‎‎‎‎‎‏‏‎‎‏‏‏‎PUK2 is permanently blocked.‎‏‎‎‏‎"</string>
     <string name="pin2_attempts" msgid="5625178102026453023">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‏‎‎‎‎‏‎‏‎‎‏‎‏‏‎‏‎‏‏‏‎‎‎‏‎‏‎‎‏‏‎‎‏‎‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎You have ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%d</xliff:g>‎‏‎‎‏‏‏‎ remaining attempts.‎‏‎‎‏‎"</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‏‎‏‏‏‏‎‎‎‎‏‎‏‏‎‏‎‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‎‎‎‎‏‎‏‏‎‎‎‎‎‏‎PUK2 locked. Contact service provider to unlock.‎‏‎‎‏‎"</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‎‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‏‏‎‏‏‏‏‎‏‏‏‎PIN2 no longer blocked‎‏‎‎‏‎"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‏‎‎‎‏‏‎‎‎‏‎‏‏‏‎‏‏‎‏‏‎‎‎‎‎‏‏‎‏‏‎‏‎‏‎‎‎‎‎‏‏‏‎‏‎‏‏‎‎‏‎Network or SIM card error‎‏‎‎‏‎"</string>
     <string name="doneButton" msgid="7371209609238460207">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‏‏‏‏‎‎‏‏‎‎‎‎‎‏‎‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‏‎‏‏‏‏‎Done‎‏‎‎‏‎"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 0eb7c74..b3c8395 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Contraseña incorrecta. SIM bloqueada. Ingresa el PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"El código PUK2 se bloqueó de forma permanente."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Te quedan <xliff:g id="NUMBER">%d</xliff:g> intentos."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"SIM bloqueada con PUK2. Comunícate con el proveedor para desbloquearla."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"El PIN2 ya no está bloqueado."</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Error en la red o en la tarjeta SIM"</string>
     <string name="doneButton" msgid="7371209609238460207">"Finalizado"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 41876dc..d012d07 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -281,16 +281,16 @@
     <string name="data_enabled" msgid="22525832097434368">"Habilitar datos"</string>
     <string name="data_enable_summary" msgid="696860063456536557">"Permitir uso de datos"</string>
     <string name="dialog_alert_title" msgid="5260471806940268478">"Atención"</string>
-    <string name="roaming" msgid="1576180772877858949">"Itinerancia"</string>
-    <string name="roaming_enable" msgid="6853685214521494819">"Conectarse a servicios de datos en itinerancia"</string>
-    <string name="roaming_disable" msgid="8856224638624592681">"Conectarse a servicios de datos en itinerancia"</string>
-    <string name="roaming_reenable_message" msgid="1951802463885727915">"La itinerancia de datos está desactivada. Toca para activarla."</string>
-    <string name="roaming_enabled_message" msgid="9022249120750897">"Pueden aplicarse cargos de itinerancia. Toca para modificar este ajuste."</string>
+    <string name="roaming" msgid="1576180772877858949">"Roaming"</string>
+    <string name="roaming_enable" msgid="6853685214521494819">"Conectarse a servicios de datos en roaming"</string>
+    <string name="roaming_disable" msgid="8856224638624592681">"Conectarse a servicios de datos en roaming"</string>
+    <string name="roaming_reenable_message" msgid="1951802463885727915">"El roaming de datos está desactivado. Toca para activarla."</string>
+    <string name="roaming_enabled_message" msgid="9022249120750897">"Pueden aplicarse cargos de roaming. Toca para modificar este ajuste."</string>
     <string name="roaming_notification_title" msgid="3590348480688047320">"Se ha perdido la conexión de datos móviles"</string>
-    <string name="roaming_on_notification_title" msgid="7451473196411559173">"La itinerancia de datos está activada"</string>
+    <string name="roaming_on_notification_title" msgid="7451473196411559173">"El roaming de datos está activado"</string>
     <string name="roaming_warning" msgid="7855681468067171971">"El coste de este servicio puede ser significativo."</string>
     <string name="roaming_check_price_warning" msgid="8212484083990570215">"Ponte en contacto con tu proveedor de red para consultar el precio."</string>
-    <string name="roaming_alert_title" msgid="5689615818220960940">"¿Permitir itinerancia de datos?"</string>
+    <string name="roaming_alert_title" msgid="5689615818220960940">"¿Permitir roaming de datos?"</string>
     <string name="limited_sim_function_notification_title" msgid="612715399099846281">"Funcionalidad de SIM limitada"</string>
     <string name="limited_sim_function_with_phone_num_notification_message" msgid="5928988883403677610">"Puede los servicios de datos y llamadas de <xliff:g id="CARRIER_NAME">%1$s</xliff:g> se bloqueen mientras se utilice el <xliff:g id="PHONE_NUMBER">%2$s</xliff:g>."</string>
     <string name="limited_sim_function_notification_message" msgid="5338638075496721160">"Puede que los servicios de datos y llamadas de <xliff:g id="CARRIER_NAME">%1$s</xliff:g> se bloqueen al usar otra SIM."</string>
@@ -299,7 +299,7 @@
     <string name="sip_accounts_removed_notification_action" msgid="3772778402370555562">"Ir a Ajustes"</string>
     <string name="data_usage_title" msgid="8438592133893837464">"Uso de datos de la aplicación"</string>
     <string name="data_usage_template" msgid="6287906680674061783">"Se han usado <xliff:g id="ID_1">%1$s</xliff:g> en el periodo del <xliff:g id="ID_2">%2$s</xliff:g>"</string>
-    <string name="advanced_options_title" msgid="9208195294513520934">"Avanzado"</string>
+    <string name="advanced_options_title" msgid="9208195294513520934">"Ajustes avanzados"</string>
     <string name="carrier_settings_euicc" msgid="1190237227261337749">"Operador"</string>
     <string name="keywords_carrier_settings_euicc" msgid="8540160967922063745">"operador, esim, sim, euicc, cambiar de operador, añadir operador"</string>
     <string name="carrier_settings_euicc_summary" msgid="2027941166597330117">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>: <xliff:g id="PHONE_NUMBER">%2$s</xliff:g>"</string>
@@ -416,7 +416,7 @@
     <string name="network_4G" msgid="6800527815504223913">"4G (recomendado)"</string>
     <string name="network_global" msgid="3289646154407617631">"Mundial"</string>
     <string name="cdma_system_select_title" msgid="614165233552656431">"Selección del sistema"</string>
-    <string name="cdma_system_select_summary" msgid="3840420390242060407">"Cambiar el modo de itinerancia CDMA"</string>
+    <string name="cdma_system_select_summary" msgid="3840420390242060407">"Cambiar el modo de roaming CDMA"</string>
     <string name="cdma_system_select_dialogtitle" msgid="5524639510676501802">"Selección del sistema"</string>
   <string-array name="cdma_system_select_choices">
     <item msgid="462340042928284921">"Solo sistema doméstico"</item>
@@ -515,9 +515,10 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Contraseña incorrecta. SIM bloqueada. Introducir PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"El PUK2 se ha bloqueado de forma permanente."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Quedan <xliff:g id="NUMBER">%d</xliff:g> intentos."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 bloqueado. Ponte en contacto con tu proveedor de servicios para desbloquearlo."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 desbloqueado"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Error en la tarjeta SIM o en la red"</string>
-    <string name="doneButton" msgid="7371209609238460207">"Listo"</string>
+    <string name="doneButton" msgid="7371209609238460207">"Hecho"</string>
     <string name="voicemail_settings_number_label" msgid="1265118640154688162">"Número del buzón de voz"</string>
     <string name="card_title_dialing" msgid="8742182654254431781">"Llamando"</string>
     <string name="card_title_redialing" msgid="18130232613559964">"Marcando otra vez"</string>
@@ -595,7 +596,7 @@
     <string name="rtt_mode_title" msgid="3075948111362818043">"Llamada de texto en tiempo real (TTR)"</string>
     <string name="rtt_mode_summary" msgid="8631541375609989562">"Permitir mensajes en una llamada de voz"</string>
     <string name="rtt_mode_more_information" msgid="587500128658756318">"La función TTR (texto en tiempo real) ofrece asistencia a las personas sordas o con discapacidades auditivas, que tienen algún trastorno del habla o que necesitan una transcripción además de la voz para comunicarse.&lt;br&gt; &lt;a href=<xliff:g id="URL">http://support.google.com/mobile?p=telephony_rtt</xliff:g>&gt;Más información&lt;/a&gt;\n       &lt;br&gt;&lt;br&gt; - Las llamadas de TTR se guardan como la transcripción de un mensaje.\n       &lt;br&gt; - La función TTR no está disponible en videollamadas."</string>
-    <string name="no_rtt_when_roaming" msgid="5268008247378355389">"Nota: TTR no está disponible en itinerancia"</string>
+    <string name="no_rtt_when_roaming" msgid="5268008247378355389">"Nota: TTR no está disponible en roaming"</string>
   <string-array name="tty_mode_entries">
     <item msgid="3238070884803849303">"TTY desactivado"</item>
     <item msgid="1449091874731375214">"TTY completo"</item>
@@ -683,7 +684,7 @@
     <string name="status_hint_label_wifi_call" msgid="942993035689809853">"Llamada Wi-Fi"</string>
     <string name="emergency_action_launch_hint" msgid="2762016865340891314">"Toca de nuevo para abrir"</string>
     <string name="message_decode_error" msgid="1061856591500290887">"Se ha producido un error al decodificar el mensaje."</string>
-    <string name="callFailed_cdma_activation" msgid="5392057031552253550">"Una tarjeta SIM ha activado tu servicio y actualizado la función de itinerancia del teléfono."</string>
+    <string name="callFailed_cdma_activation" msgid="5392057031552253550">"Una tarjeta SIM ha activado tu servicio y actualizado la función de roaming del teléfono."</string>
     <string name="callFailed_cdma_call_limit" msgid="1074219746093031412">"Hay demasiadas llamadas activas. Finaliza o combina las llamadas que tienes antes de iniciar otra."</string>
     <string name="callFailed_imei_not_accepted" msgid="7257903653685147251">"No se puede establecer la conexión. Inserta una tarjeta SIM válida."</string>
     <string name="callFailed_wifi_lost" msgid="1788036730589163141">"Se ha perdido la conexión Wi-Fi. La llamada ha finalizado."</string>
@@ -703,16 +704,16 @@
     <string name="change_pin_confirm_pins_dont_match" msgid="305164501222587215">"Los PIN no coinciden"</string>
     <string name="change_pin_succeeded" msgid="2504705600693014403">"Se ha cambiado el PIN del buzón de voz"</string>
     <string name="change_pin_system_error" msgid="7772788809875146873">"No se ha podido configurar el PIN"</string>
-    <string name="mobile_data_status_roaming_turned_off_subtext" msgid="6840673347416227054">"Se ha desactivado la itinerancia de datos"</string>
-    <string name="mobile_data_status_roaming_turned_on_subtext" msgid="5615757897768777865">"Se ha activado la itinerancia de datos"</string>
-    <string name="mobile_data_status_roaming_without_plan_subtext" msgid="6536671968072284677">"En itinerancia actualmente, se necesita un plan de datos"</string>
-    <string name="mobile_data_status_roaming_with_plan_subtext" msgid="2576177169108123095">"En itinerancia actualmente, hay un plan de datos activo"</string>
+    <string name="mobile_data_status_roaming_turned_off_subtext" msgid="6840673347416227054">"Se ha desactivado el roaming de datos"</string>
+    <string name="mobile_data_status_roaming_turned_on_subtext" msgid="5615757897768777865">"Se ha activado el roaming de datos"</string>
+    <string name="mobile_data_status_roaming_without_plan_subtext" msgid="6536671968072284677">"En roaming actualmente, se necesita un plan de datos"</string>
+    <string name="mobile_data_status_roaming_with_plan_subtext" msgid="2576177169108123095">"En roaming actualmente, hay un plan de datos activo"</string>
     <string name="mobile_data_status_no_plan_subtext" msgid="170331026419263657">"No quedan datos móviles"</string>
     <string name="mobile_data_activate_prepaid" msgid="4276738964416795596">"No quedan datos móviles"</string>
     <string name="mobile_data_activate_prepaid_summary" msgid="6846085278531605925">"Añadir datos móviles a través de <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
-    <string name="mobile_data_activate_roaming_plan" msgid="922290995866269366">"No hay ningún plan de itinerancia"</string>
-    <string name="mobile_data_activate_roaming_plan_summary" msgid="5379228493306235969">"Añadir un plan de itinerancia a través de <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
-    <string name="mobile_data_activate_footer" msgid="7895874069807204548">"Puedes añadir datos móviles o un plan de itinerancia a través de tu operador, <xliff:g id="PROVIDER_NAME">%s</xliff:g>."</string>
+    <string name="mobile_data_activate_roaming_plan" msgid="922290995866269366">"No hay ningún plan de roaming"</string>
+    <string name="mobile_data_activate_roaming_plan_summary" msgid="5379228493306235969">"Añadir un plan de roaming a través de <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
+    <string name="mobile_data_activate_footer" msgid="7895874069807204548">"Puedes añadir datos móviles o un plan de roaming a través de tu operador, <xliff:g id="PROVIDER_NAME">%s</xliff:g>."</string>
     <string name="mobile_data_activate_diag_title" msgid="5401741936224757312">"¿Añadir datos?"</string>
     <string name="mobile_data_activate_diag_message" msgid="3527260988020415441">"Puede que tengas que añadir datos a través de <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
     <string name="mobile_data_activate_button" msgid="1139792516354374612">"AÑADIR DATOS"</string>
@@ -779,15 +780,15 @@
     <string name="call_barring_baoic" msgid="8668125428666851665">"Internacionales realizadas"</string>
     <string name="call_barring_baoic_enabled" msgid="1203758092657630123">"¿Quieres desbloquear las llamadas internacionales realizadas?"</string>
     <string name="call_barring_baoic_disabled" msgid="5656889339002997449">"¿Bloquear las llamadas internacionales realizadas?"</string>
-    <string name="call_barring_baoicr" msgid="8566167764432343487">"Itinerancia de llamadas internacionales realizadas"</string>
-    <string name="call_barring_baoicr_enabled" msgid="1615324165512798478">"¿Quieres desbloquear la itinerancia de las llamadas internacionales realizadas?"</string>
-    <string name="call_barring_baoicr_disabled" msgid="172010175248142831">"¿Bloquear la itinerancia de las llamadas internacionales realizadas?"</string>
+    <string name="call_barring_baoicr" msgid="8566167764432343487">"Roaming de llamadas internacionales realizadas"</string>
+    <string name="call_barring_baoicr_enabled" msgid="1615324165512798478">"¿Quieres desbloquear el roaming de las llamadas internacionales realizadas?"</string>
+    <string name="call_barring_baoicr_disabled" msgid="172010175248142831">"¿Bloquear el roaming de las llamadas internacionales realizadas?"</string>
     <string name="call_barring_baic" msgid="7941393541678658566">"Todas las entrantes"</string>
     <string name="call_barring_baic_enabled" msgid="4357332358020337470">"¿Quieres desbloquear todas las llamadas entrantes?"</string>
     <string name="call_barring_baic_disabled" msgid="2355945245938240958">"¿Bloquear todas las llamadas entrantes?"</string>
-    <string name="call_barring_baicr" msgid="8712249337313034226">"Itinerancia de llamadas internacionales entrantes"</string>
-    <string name="call_barring_baicr_enabled" msgid="64774270234828175">"¿Quieres desbloquear la itinerancia de las llamadas internacionales entrantes?"</string>
-    <string name="call_barring_baicr_disabled" msgid="3488129262744027262">"¿Bloquear la itinerancia de las llamadas internacionales entrantes?"</string>
+    <string name="call_barring_baicr" msgid="8712249337313034226">"Roaming de llamadas internacionales entrantes"</string>
+    <string name="call_barring_baicr_enabled" msgid="64774270234828175">"¿Quieres desbloquear el roaming de las llamadas internacionales entrantes?"</string>
+    <string name="call_barring_baicr_disabled" msgid="3488129262744027262">"¿Bloquear el roaming de las llamadas internacionales entrantes?"</string>
     <string name="call_barring_deactivate_all" msgid="7837931580047157328">"Desactivar todo"</string>
     <string name="call_barring_deactivate_all_description" msgid="4474119585042121604">"Desactivar todos los ajustes de bloqueo de llamadas"</string>
     <string name="call_barring_deactivate_success" msgid="3545644320298275337">"Se ha desactivado el bloqueo de llamadas"</string>
@@ -827,9 +828,9 @@
     <string name="callFailed_calling_disabled" msgid="5010992739401206283">"No se puede llamar porque se han inhabilitado las llamadas mediante la propiedad del sistema ro.telephony.disable-call."</string>
     <string name="callFailed_too_many_calls" msgid="5379426826618582180">"No se puede llamar porque ya hay dos llamadas en curso. Interrumpe una de ellas o combínalas en una conferencia para poder llamar de nuevo."</string>
     <string name="supp_service_over_ut_precautions" msgid="2145018231396701311">"Para utilizar <xliff:g id="SUPP_SERVICE">%s</xliff:g>, los datos móviles deben estar activados. Puedes cambiar esta opción en los ajustes de red móvil."</string>
-    <string name="supp_service_over_ut_precautions_roaming" msgid="670342104569972327">"Para utilizar <xliff:g id="SUPP_SERVICE">%s</xliff:g>, los datos móviles y la itinerancia de datos deben estar activados. Puedes cambiar estas opciones en los ajustes de red móvil."</string>
+    <string name="supp_service_over_ut_precautions_roaming" msgid="670342104569972327">"Para utilizar <xliff:g id="SUPP_SERVICE">%s</xliff:g>, los datos móviles y el roaming de datos deben estar activados. Puedes cambiar estas opciones en los ajustes de red móvil."</string>
     <string name="supp_service_over_ut_precautions_dual_sim" msgid="5166866975550910474">"Para utilizar <xliff:g id="SUPP_SERVICE">%1$s</xliff:g>, los datos móviles deben estar activados en la SIM <xliff:g id="SIM_NUMBER">%2$d</xliff:g>. Puedes cambiar esta opción en los ajustes de red móvil."</string>
-    <string name="supp_service_over_ut_precautions_roaming_dual_sim" msgid="6627654855191817965">"Para utilizar <xliff:g id="SUPP_SERVICE">%1$s</xliff:g>, los datos móviles y la itinerancia de datos deben estar activados en la SIM <xliff:g id="SIM_NUMBER">%2$d</xliff:g>. Puedes cambiar estas opciones en los ajustes de red móvil."</string>
+    <string name="supp_service_over_ut_precautions_roaming_dual_sim" msgid="6627654855191817965">"Para utilizar <xliff:g id="SUPP_SERVICE">%1$s</xliff:g>, los datos móviles y el roaming de datos deben estar activados en la SIM <xliff:g id="SIM_NUMBER">%2$d</xliff:g>. Puedes cambiar estas opciones en los ajustes de red móvil."</string>
     <string name="supp_service_over_ut_precautions_dialog_dismiss" msgid="5934541487903081652">"Cerrar"</string>
     <string name="radio_info_data_connection_enable" msgid="6183729739783252840">"Habilitar conexión de datos"</string>
     <string name="radio_info_data_connection_disable" msgid="6404751291511368706">"Inhabilitar conexión de datos"</string>
@@ -858,8 +859,8 @@
     <string name="radioInfo_service_out" msgid="287972405416142312">"Fuera de servicio"</string>
     <string name="radioInfo_service_emergency" msgid="4763879891415016848">"Solo llamadas de emergencia"</string>
     <string name="radioInfo_service_off" msgid="3456583511226783064">"Señal móvil desactivada"</string>
-    <string name="radioInfo_roaming_in" msgid="3156335577793145965">"Itinerancia"</string>
-    <string name="radioInfo_roaming_not" msgid="1904547918725478110">"Sin itinerancia"</string>
+    <string name="radioInfo_roaming_in" msgid="3156335577793145965">"Roaming"</string>
+    <string name="radioInfo_roaming_not" msgid="1904547918725478110">"Sin roaming"</string>
     <string name="radioInfo_phone_idle" msgid="2191653783170757819">"Inactivo"</string>
     <string name="radioInfo_phone_ringing" msgid="8100354169567413370">"Sonando"</string>
     <string name="radioInfo_phone_offhook" msgid="7564601639749936170">"Llamada en curso"</string>
@@ -882,7 +883,7 @@
     <string name="radio_info_cell_info_refresh_rate" msgid="670511448975997340">"Frecuencia de actualización de la información del teléfono:"</string>
     <string name="radio_info_cellinfo_label" msgid="8199062974670377659">"Información sobre las dimensiones de los teléfonos:"</string>
     <string name="radio_info_gprs_service_label" msgid="6819204246355412952">"Servicio de datos:"</string>
-    <string name="radio_info_roaming_label" msgid="6636932886446857120">"Itinerancia:"</string>
+    <string name="radio_info_roaming_label" msgid="6636932886446857120">"Roaming:"</string>
     <string name="radio_info_imei_label" msgid="8947899706930120368">"IMEI:"</string>
     <string name="radio_info_call_redirect_label" msgid="4526480903023362276">"Redirección de llamadas:"</string>
     <string name="radio_info_ppp_resets_label" msgid="9131901102339077661">"Número de PPP restablecido desde el inicio:"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index c9468d9..bdc5241 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Parool on vale. SIM on nüüd lukus. Sisestage PUK-kood 2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 on püsivalt blokeeritud."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Teil on veel <xliff:g id="NUMBER">%d</xliff:g> katset."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 on lukustatud. Avamiseks võtke ühendust teenusepakkujaga."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN-kood 2 ei ole enam blokeeritud"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Võrgu või SIM-kaardi viga"</string>
     <string name="doneButton" msgid="7371209609238460207">"Valmis"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 4d9cf49..8f02321 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -162,14 +162,14 @@
     <string name="no_change" msgid="3737264882821031892">"Ez da aldaketarik egin."</string>
     <string name="sum_voicemail_choose_provider" msgid="6750824719081403773">"Aukeratu erantzungailu-zerbitzua"</string>
     <string name="voicemail_default" msgid="6427575113775462077">"Operadorea"</string>
-    <string name="vm_change_pin_old_pin" msgid="7154951790929009241">"PIN kode zaharra"</string>
-    <string name="vm_change_pin_new_pin" msgid="2656200418481288069">"PIN kode berria"</string>
+    <string name="vm_change_pin_old_pin" msgid="7154951790929009241">"PIN zaharra"</string>
+    <string name="vm_change_pin_new_pin" msgid="2656200418481288069">"PIN berria"</string>
     <string name="vm_change_pin_progress_message" msgid="626015184502739044">"Itxaron, mesedez."</string>
-    <string name="vm_change_pin_error_too_short" msgid="1789139338449945483">"Laburregia da PIN kode berria."</string>
-    <string name="vm_change_pin_error_too_long" msgid="3634907034310018954">"Luzeegia da PIN kode berria."</string>
-    <string name="vm_change_pin_error_too_weak" msgid="8581892952627885719">"Ez da batere segurua PIN kode berria. Pasahitza segurua izan dadin, ez du izan behar zenbaki-segidarik edo errepikatutako zenbakirik."</string>
-    <string name="vm_change_pin_error_mismatch" msgid="5364847280026257331">"PIN kode zaharra ez dator bat."</string>
-    <string name="vm_change_pin_error_invalid" msgid="5230002671175580674">"Balio ez duten karaktereak ditu PIN kode berriak."</string>
+    <string name="vm_change_pin_error_too_short" msgid="1789139338449945483">"Laburregia da PIN berria."</string>
+    <string name="vm_change_pin_error_too_long" msgid="3634907034310018954">"Luzeegia da PIN berria."</string>
+    <string name="vm_change_pin_error_too_weak" msgid="8581892952627885719">"Ez da batere segurua PIN berria. Pasahitza segurua izan dadin, ez du izan behar zenbaki-segidarik edo errepikatutako zenbakirik."</string>
+    <string name="vm_change_pin_error_mismatch" msgid="5364847280026257331">"PIN zaharra ez dator bat."</string>
+    <string name="vm_change_pin_error_invalid" msgid="5230002671175580674">"Balio ez duten karaktereak ditu PIN berriak."</string>
     <string name="vm_change_pin_error_system_error" msgid="9116483527909681791">"Ezin da aldatu PIN kodea"</string>
     <string name="vvm_unsupported_message_format" msgid="4206402558577739713">"Ez dira onartzen mota honetako mezuak. Entzuteko, deitu <xliff:g id="NUMBER">%s</xliff:g> zenbakira."</string>
     <string name="network_settings_title" msgid="7560807107123171541">"Sare mugikorra"</string>
@@ -475,7 +475,7 @@
     <string name="delete_fdn_contact" msgid="7027405651994507077">"Ezabatu markatze finkoko zenbakia"</string>
     <string name="deleting_fdn_contact" msgid="6872320570844460428">"Markatze finkoko zenbakia ezabatzen…"</string>
     <string name="fdn_contact_deleted" msgid="1680714996763848838">"Markatze finkoko zenbakia ezabatu da."</string>
-    <string name="pin2_invalid" msgid="2313954262684494442">"Ez da eguneratu markatze finkoko zenbakia, PIN kode okerra idatzi duzulako."</string>
+    <string name="pin2_invalid" msgid="2313954262684494442">"Ez da eguneratu markatze finkoko zenbakia, PIN okerra idatzi duzulako."</string>
     <string name="fdn_invalid_number" msgid="9067189814657840439">"Ez da eguneratu markatze finkoko zenbakia, zenbakiak <xliff:g id="FDN_NUMBER_LIMIT_LENGTH">%d</xliff:g> digitu baino gehiago dituelako."</string>
     <string name="pin2_or_fdn_invalid" msgid="7542639487955868181">"Ez da eguneratu markatze finkoko zenbakia. PIN2 kodea ez da zuzena edo telefono-zenbakia baztertu da."</string>
     <string name="fdn_failed" msgid="216592346853420250">"Markatze finkoko zenbakiaren eragiketak huts egin du."</string>
@@ -488,8 +488,8 @@
     <string name="enter_pin_text" msgid="3182311451978663356">"SIM txartelaren PIN kodea:"</string>
     <string name="oldPinLabel" msgid="8618515202411987721">"PIN zaharra"</string>
     <string name="newPinLabel" msgid="3585899083055354732">"PIN berria"</string>
-    <string name="confirmPinLabel" msgid="7783531218662473778">"Berretsi PIN kode berria"</string>
-    <string name="badPin" msgid="4549286285015892321">"Idatzi duzun PIN kode zaharra ez da zuzena. Saiatu berriro."</string>
+    <string name="confirmPinLabel" msgid="7783531218662473778">"Berretsi PIN berria"</string>
+    <string name="badPin" msgid="4549286285015892321">"Idatzi duzun PIN zaharra ez da zuzena. Saiatu berriro."</string>
     <string name="mismatchPin" msgid="1467254768290323845">"Idatzi dituzun PIN kodeak ez datoz bat. Saiatu berriro."</string>
     <string name="invalidPin" msgid="7363723429414001979">"Idatzi 4 eta 8 zenbaki arteko PIN kodea."</string>
     <string name="disable_sim_pin" msgid="3112303905548613752">"Garbitu SIM txartelaren PIN kodea"</string>
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Pasahitza ez da zuzena. SIM txartela blokeatu egin da. Idatzi PUK2 kodea."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 kodea betiko blokeatu da."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"<xliff:g id="NUMBER">%d</xliff:g> saiakera gelditzen zaizkizu."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 kodearekin blokeatuta dago SIM txartela. Desblokeatzeko, jarri operadorearekin harremanetan."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 kodea desblokeatu da"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Sarearen edo SIM txartelaren errorea"</string>
     <string name="doneButton" msgid="7371209609238460207">"Eginda"</string>
@@ -695,9 +696,9 @@
     <string name="change_pin_continue_label" msgid="5177011752453506371">"Egin aurrera"</string>
     <string name="change_pin_cancel_label" msgid="2301711566758827936">"Utzi"</string>
     <string name="change_pin_ok_label" msgid="6861082678817785330">"Ados"</string>
-    <string name="change_pin_enter_old_pin_header" msgid="853151335217594829">"Berretsi PIN kode zaharra"</string>
+    <string name="change_pin_enter_old_pin_header" msgid="853151335217594829">"Berretsi PIN zaharra"</string>
     <string name="change_pin_enter_old_pin_hint" msgid="8801292976275169367">"Idatzi erantzungailuaren PIN kodea jarraitzeko."</string>
-    <string name="change_pin_enter_new_pin_header" msgid="4739465616733486118">"Ezarri PIN kode berria"</string>
+    <string name="change_pin_enter_new_pin_header" msgid="4739465616733486118">"Ezarri PIN berri bat"</string>
     <string name="change_pin_enter_new_pin_hint" msgid="2326038476516364210">"<xliff:g id="MIN">%1$d</xliff:g> eta <xliff:g id="MAX">%2$d</xliff:g> digituren artean izan behar ditu PIN kodeak."</string>
     <string name="change_pin_confirm_pin_header" msgid="2606303906320705726">"Berretsi PIN kodea"</string>
     <string name="change_pin_confirm_pins_dont_match" msgid="305164501222587215">"PINak ez datoz bat"</string>
@@ -874,7 +875,7 @@
     <string name="radioInfo_display_asu" msgid="2247752203249646956">"asu"</string>
     <string name="radioInfo_lac" msgid="3892986460272607013">"LAC"</string>
     <string name="radioInfo_cid" msgid="1423185536264406705">"CID"</string>
-    <string name="radio_info_subid" msgid="6839966868621703203">"Uneko azpiIDa:"</string>
+    <string name="radio_info_subid" msgid="6839966868621703203">"Oraingo azpiIDa:"</string>
     <string name="radio_info_dds" msgid="1122593144425697126">"Datu-konexioetarako SIM lehenetsiaren azpiIDa:"</string>
     <string name="radio_info_dl_kbps" msgid="2382922659525318726">"Deskargatzeko banda-zabalera (Kb/s):"</string>
     <string name="radio_info_ul_kbps" msgid="2102225400904799036">"Kargen banda-zabalera (Kb/s):"</string>
@@ -886,7 +887,7 @@
     <string name="radio_info_imei_label" msgid="8947899706930120368">"IMEI:"</string>
     <string name="radio_info_call_redirect_label" msgid="4526480903023362276">"Dei-desbideratzea:"</string>
     <string name="radio_info_ppp_resets_label" msgid="9131901102339077661">"PPP berrezarpen kopurua abiarazi ezkero:"</string>
-    <string name="radio_info_current_network_label" msgid="3052098695239642450">"Uneko sarea:"</string>
+    <string name="radio_info_current_network_label" msgid="3052098695239642450">"Oraingo sarea:"</string>
     <string name="radio_info_ppp_received_label" msgid="5753592451640644889">"Jasotako datuak:"</string>
     <string name="radio_info_gsm_service_label" msgid="6443348321714241328">"Ahots-deien zerbitzua:"</string>
     <string name="radio_info_signal_strength_label" msgid="5545444702102543260">"Seinalearen indarra:"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 10f2348..e64f3bc 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"‏گذرواژه نادرست است. اکنون سیم‌کارت قفل شده است. PUK2 را وارد کنید."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"‏PUK2 به صورت دائمی مسدود شده است."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"<xliff:g id="NUMBER">%d</xliff:g> تلاش باقی‌مانده دارید."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"‏PUK2 قفل است. برای باز کردن قفل، با ارائه دهنده خدمات تماس بگیرید."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"پین۲ دیگر مسدود نیست"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"خطای شبکه یا سیم‌کارت"</string>
     <string name="doneButton" msgid="7371209609238460207">"تمام"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index a0a6b2c..819186e 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Virheellinen salasana. SIM-kortti on lukittu. Anna PUK2-koodi."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2-koodi on pysyvästi estetty."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"<xliff:g id="NUMBER">%d</xliff:g> yritystä jäljellä."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 lukittu. Ota yhteyttä palveluntarjoajaan lukituksen avaamiseksi."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2-koodi ei ole enää estetty"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Verkko- tai SIM-korttivirhe"</string>
     <string name="doneButton" msgid="7371209609238460207">"Valmis"</string>
@@ -771,8 +772,8 @@
     <string name="clh_callFailed_protocol_Error_unspecified_txt" msgid="9203320572562697755">"Soittaminen epäonnistui. Virhekoodi 111."</string>
     <string name="clh_callFailed_interworking_unspecified_txt" msgid="7969686413930847182">"Soittaminen epäonnistui. Virhekoodi 127."</string>
     <string name="labelCallBarring" msgid="4180377113052853173">"Puhelujen esto"</string>
-    <string name="sum_call_barring_enabled" msgid="5184331188926370824">"Käytössä"</string>
-    <string name="sum_call_barring_disabled" msgid="5699448000600153096">"Pois käytöstä"</string>
+    <string name="sum_call_barring_enabled" msgid="5184331188926370824">"Päällä"</string>
+    <string name="sum_call_barring_disabled" msgid="5699448000600153096">"Pois päältä"</string>
     <string name="call_barring_baoc" msgid="7400892586336429326">"Kaikki lähtevät"</string>
     <string name="call_barring_baoc_enabled" msgid="3131509193386668182">"Poistetaanko kaikkien lähtevien puheluiden esto käytöstä?"</string>
     <string name="call_barring_baoc_disabled" msgid="8534224684091141509">"Estetäänkö kaikki lähtevät puhelut?"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 2b2cc38..a35f8dd 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Le mot de passe est erroné. La carte SIM a été verrouillée. Entrez  le code PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"Le code PUK2 est bloqué définitivement."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Il vous reste <xliff:g id="NUMBER">%d</xliff:g> tentatives."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"Verrouillage PUK2. Communiquez avec le fournisseur de services pour procéder au déverrouillage."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"Le NIP2 n\'est plus bloqué."</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Erreur de réseau ou de carte SIM"</string>
     <string name="doneButton" msgid="7371209609238460207">"Terminé"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index e13da5d..a056294 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Le mot de passe est erroné. La carte SIM est désormais verrouillée. Veuillez saisir le code PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"La clé PUK2 est bloquée de manière définitive."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Il vous reste <xliff:g id="NUMBER">%d</xliff:g> tentatives."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"Verrouillage par clé PUK2. Contactez votre fournisseur de services pour déverrouiller la carte SIM."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"Le code PIN2 n\'est plus bloqué."</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Erreur de réseau ou de carte SIM."</string>
     <string name="doneButton" msgid="7371209609238460207">"OK"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 57ac8de..2f6a0e3 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Contrasinal incorrecto. A SIM está bloqueada agora. Introduce o PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"O PUK2 está permanentemente bloqueado."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Quédanche <xliff:g id="NUMBER">%d</xliff:g> intentos."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 bloqueado. Contacta co fornecedor de servizo para desbloquealo."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"O PIN2 xa non está bloqueado"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Erro de rede ou de tarxeta SIM"</string>
     <string name="doneButton" msgid="7371209609238460207">"Feito"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 4b55ee6..b91ced3 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"પાસવર્ડ ખોટો છે, SIM હમણાં અવરોધિત છે. PUK2 દાખલ કરો."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 ને કાયમી રૂપે અવરોધિત કરેલ છે."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"તમારી પાસે <xliff:g id="NUMBER">%d</xliff:g> પ્રયાસ બાકી છે."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 વડે લૉક થયું છે. અનલૉક કરવા માટે સેવા પ્રદાતાનો સંપર્ક કરો."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 હવે અવરોધિત નથી"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"નેટવર્ક અથવા SIM કાર્ડ ભૂલ"</string>
     <string name="doneButton" msgid="7371209609238460207">"થઈ ગયું"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 54afa62..e18e557 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"पासवर्ड गलत है. सिम अब लॉक हो गई है. PUK2 डालें."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 स्थायी रूप से अवरोधित है."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"आपके पास <xliff:g id="NUMBER">%d</xliff:g> प्रयास शेष हैं."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"सिम कार्ड PUK2 से लॉक है. अनलॉक करने के लिए, सेवा देने वाली कंपनी से संपर्क करें."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 अब अवरोधित नहीं है"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"नेटवर्क या SIM कार्ड गड़बड़ी"</string>
     <string name="doneButton" msgid="7371209609238460207">"पूरा हो गया"</string>
@@ -676,7 +677,7 @@
     <string name="enable_video_calling_dialog_settings" msgid="8697890611305307110">"नेटवर्क सेटिंग"</string>
     <string name="enable_video_calling_dialog_close" msgid="4298929725917045270">"बंद करें"</string>
     <string name="sim_label_emergency_calls" msgid="9078241989421522310">"आपातकालीन कॉल"</string>
-    <string name="sim_description_emergency_calls" msgid="5146872803938897296">"केवल आपातकालीन कॉल"</string>
+    <string name="sim_description_emergency_calls" msgid="5146872803938897296">"सिर्फ़ आपातकालीन कॉल"</string>
     <string name="sim_description_default" msgid="7474671114363724971">"सिम कार्ड, स्‍लॉट: <xliff:g id="SLOT_ID">%s</xliff:g>"</string>
     <string name="accessibility_settings_activity_title" msgid="7883415189273700298">"सुलभता"</string>
     <string name="status_hint_label_incoming_wifi_call" msgid="2606052595898044071">"इससे वाई-फ़ाई कॉल"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 3ba6fd5..b15a054 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Zaporka nije točna. SIM je sada zaključan. Unesite PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 je trajno blokiran."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Imate još <xliff:g id="NUMBER">%d</xliff:g> pokušaja."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 zaključan. Obratite se davatelju usluga za otključavanje."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 više nije blokiran"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Pogreška mreže ili SIM kartice"</string>
     <string name="doneButton" msgid="7371209609238460207">"Gotovo"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index ce42169..d702818 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"A jelszó helytelen. SIM kártya zárolva. Adja meg a PUK2 kódot."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"A PUK2 végleg letiltva."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"<xliff:g id="NUMBER">%d</xliff:g> próbálkozási lehetősége maradt."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"A PUK2 zárolva van. A feloldás ügyében forduljon a szolgáltatóhoz."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 kód letiltása feloldva"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Hálózattal vagy SIM kártyával kapcsolatos hiba"</string>
     <string name="doneButton" msgid="7371209609238460207">"Kész"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 2503234..f005098 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -284,7 +284,7 @@
     <string name="roaming" msgid="1576180772877858949">"Ռոումինգ"</string>
     <string name="roaming_enable" msgid="6853685214521494819">"Միանալ տվյալների փոխանցման ծառայություններին ռոումինգում"</string>
     <string name="roaming_disable" msgid="8856224638624592681">"Միանալ տվյալների փոխանցման ծառայություններին ռոումինգում"</string>
-    <string name="roaming_reenable_message" msgid="1951802463885727915">"Ռոումինգում բջջային ինտերնետն անջատած է: Հպեք՝ միացնելու համար:"</string>
+    <string name="roaming_reenable_message" msgid="1951802463885727915">"Ռոումինգում բջջային ինտերնետն անջատված է: Հպեք՝ միացնելու համար:"</string>
     <string name="roaming_enabled_message" msgid="9022249120750897">"Ռոումինգի համար կարող է գումար գանձվել: Հպեք՝ փոփոխելու համար:"</string>
     <string name="roaming_notification_title" msgid="3590348480688047320">"Բջջային ինտերնետը կորավ"</string>
     <string name="roaming_on_notification_title" msgid="7451473196411559173">"Ինտերնետ ռոումինգը միացված է"</string>
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Գաղտնաբառը սխալ է: SIM քարտն այժմ կողպված է: Մուտքագրեք PUK2 կոդը:"</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2-ն ընդմիշտ արգելափակված է:"</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Ձեզ մնացել է <xliff:g id="NUMBER">%d</xliff:g> փորձ:"</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"Կողպված է PUK2-ով։ Ապակողպելու համար կապվեք ձեր օպերատորի հետ։"</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 կոդն այլևս արգելափակված չէ"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Ցանցի կամ SIM քարտի սխալ"</string>
     <string name="doneButton" msgid="7371209609238460207">"Պատրաստ է"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 3906196..47aa918 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Sandi salah. SIM kini dikunci. Masukkan PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 diblokir selamanya."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Tersisa <xliff:g id="NUMBER">%d</xliff:g> upaya lagi."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 terkunci. Hubungi penyedia layanan untuk membuka kunci."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 tidak lagi diblokir"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Kesalahan jaringan atau kartu SIM"</string>
     <string name="doneButton" msgid="7371209609238460207">"Selesai"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 5278fd2..cd40734 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Rangt aðgangsorð. SIM-kortinu var læst. Sláðu inn PUK2-númerið."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 er læst fyrir fullt og allt."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"<xliff:g id="NUMBER">%d</xliff:g> tilraunir eru eftir."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"Læst með PUK2. Hafðu samband við þjónustuaðila til að taka úr lás."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2-númer ekki lengur læst"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Villa í símkerfi eða á SIM-korti"</string>
     <string name="doneButton" msgid="7371209609238460207">"Lokið"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index cdbf7ce..78ea899 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Password errata. SIM bloccata. Inserisci codice PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 bloccato definitivamente."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Hai a disposizione ancora <xliff:g id="NUMBER">%d</xliff:g> tentativi."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 bloccato. Per sbloccarlo, contatta il fornitore di servizi."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 sbloccato"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Errore di rete o della SIM"</string>
     <string name="doneButton" msgid="7371209609238460207">"Fine"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index fc771cb..d7cee71 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -31,29 +31,29 @@
     <string name="ussdRunning" msgid="1163586813106772717">"‏קוד USSD פועל…"</string>
     <string name="mmiCancelled" msgid="5339191899200678272">"‏קוד MMI מבוטל"</string>
     <string name="cancel" msgid="8984206397635155197">"ביטול"</string>
-    <string name="enter_input" msgid="6193628663039958990">"‏הודעת USSD חייבת להיות באורך של <xliff:g id="MIN_LEN">%1$d</xliff:g> עד <xliff:g id="MAX_LEN">%2$d</xliff:g> תווים. נסה שוב."</string>
+    <string name="enter_input" msgid="6193628663039958990">"‏הודעת USSD חייבת להיות באורך של <xliff:g id="MIN_LEN">%1$d</xliff:g> עד <xliff:g id="MAX_LEN">%2$d</xliff:g> תווים. יש לנסות שוב."</string>
     <string name="manageConferenceLabel" msgid="8415044818156353233">"ניהול שיחת ועידה"</string>
     <string name="ok" msgid="7818974223666140165">"אישור"</string>
     <string name="audio_mode_speaker" msgid="243689733219312360">"רמקול"</string>
     <string name="audio_mode_earpiece" msgid="2823700267171134282">"אוזניה"</string>
-    <string name="audio_mode_wired_headset" msgid="5028010823105817443">"אוזניות קוויות"</string>
+    <string name="audio_mode_wired_headset" msgid="5028010823105817443">"אוזניות חוטיות"</string>
     <string name="audio_mode_bluetooth" msgid="25732183428018809">"Bluetooth"</string>
     <string name="wait_prompt_str" msgid="5136209532150094910">"לשלוח את הצלילים הבאים?\n"</string>
-    <string name="pause_prompt_str" msgid="2308897950360272213">"שולח צלילים\n"</string>
+    <string name="pause_prompt_str" msgid="2308897950360272213">"שליחת צלילים מתבצעת\n"</string>
     <string name="send_button" msgid="5070379600779031932">"שליחה"</string>
     <string name="pause_prompt_yes" msgid="8184132073048369575">"כן"</string>
     <string name="pause_prompt_no" msgid="2145264674774138579">"לא"</string>
     <string name="wild_prompt_str" msgid="5858910969703305375">"החלפת התו הכללי ב"</string>
     <string name="no_vm_number" msgid="6623853880546176930">"חסר מספר של דואר קולי"</string>
     <string name="no_vm_number_msg" msgid="5165161462411372504">"‏בכרטיס ה-SIM לא מאוחסן מספר של דואר קולי."</string>
-    <string name="add_vm_number_str" msgid="7368168964435881637">"הוסף מספר"</string>
+    <string name="add_vm_number_str" msgid="7368168964435881637">"הוספת מספר"</string>
     <string name="voice_number_setting_primary_user_only" msgid="3394706575741912843">"רק המשתמש הראשי יכול לשנות את ההגדרות של הדואר הקולי."</string>
-    <string name="puk_unlocked" msgid="4627340655215746511">"‏בוטלה החסימה של כרטיס SIM. מבטל את חסימת הטלפון..."</string>
-    <string name="label_ndp" msgid="7617392683877410341">"‏PIN לביטול נעילה של רשת SIM"</string>
+    <string name="puk_unlocked" msgid="4627340655215746511">"‏בוטלה החסימה של כרטיס SIM. ביטול חסימת הטלפון מתבצעת..."</string>
+    <string name="label_ndp" msgid="7617392683877410341">"‏קוד אימות לביטול נעילה של רשת SIM"</string>
     <string name="label_phoneid" msgid="8775611434123577808">"‏כרטיס ה-SIM נעול על ידי הספק הסלולרי"</string>
-    <string name="sim_ndp_unlock_text" msgid="7737338355451978338">"בטל נעילה"</string>
-    <string name="sim_ndp_dismiss_text" msgid="89667342248929777">"סגור"</string>
-    <string name="requesting_unlock" msgid="930512210309437741">"מבקש ביטול נעילת רשת..."</string>
+    <string name="sim_ndp_unlock_text" msgid="7737338355451978338">"ביטול נעילה"</string>
+    <string name="sim_ndp_dismiss_text" msgid="89667342248929777">"סגירה"</string>
+    <string name="requesting_unlock" msgid="930512210309437741">"בקשה לביטול נעילת הרשת מתבצעת..."</string>
     <string name="unlock_failed" msgid="7103543844840661366">"הבקשה לביטול נעילת הרשת נכשלה."</string>
     <string name="unlock_success" msgid="32681089371067565">"ביטול נעילת הרשת התבצע בהצלחה."</string>
     <string name="mobile_network_settings_not_available" msgid="8678168497517090039">"הגדרות של רשת סלולרית אינן זמינות עבור המשתמש הזה"</string>
@@ -64,17 +64,17 @@
     <string name="apn_settings" msgid="1978652203074756623">"שמות של נקודות גישה"</string>
     <string name="settings_label" msgid="9101778088412567956">"הגדרות רשת"</string>
     <string name="phone_accounts" msgid="1216879437523774604">"חשבונות להתקשרות"</string>
-    <string name="phone_accounts_make_calls_with" msgid="16747814788918145">"בצע שיחות באמצעות"</string>
-    <string name="phone_accounts_make_sip_calls_with" msgid="4691221006731847255">"‏בצע שיחות SIP באמצעות"</string>
-    <string name="phone_accounts_ask_every_time" msgid="6192347582666047168">"שאל לפני ביצוע"</string>
+    <string name="phone_accounts_make_calls_with" msgid="16747814788918145">"ביצוע שיחות באמצעות"</string>
+    <string name="phone_accounts_make_sip_calls_with" msgid="4691221006731847255">"‏ביצוע שיחות SIP באמצעות"</string>
+    <string name="phone_accounts_ask_every_time" msgid="6192347582666047168">"יש לשאול לפני ביצוע"</string>
     <string name="phone_accounts_default_account_label" msgid="5107598881335931101">"אין רשתות זמינות"</string>
     <string name="phone_accounts_settings_header" msgid="6296501692964706536">"הגדרות"</string>
-    <string name="phone_accounts_choose_accounts" msgid="4748805293314824974">"בחר חשבונות"</string>
+    <string name="phone_accounts_choose_accounts" msgid="4748805293314824974">"בחירת חשבונות"</string>
     <string name="phone_accounts_selection_header" msgid="2945830843104108440">"חשבונות טלפון"</string>
-    <string name="phone_accounts_add_sip_account" msgid="1437634802033309305">"‏הוסף חשבון SIP"</string>
-    <string name="phone_accounts_configure_account_settings" msgid="6622119715253196586">"קבע את הגדרות החשבון"</string>
+    <string name="phone_accounts_add_sip_account" msgid="1437634802033309305">"‏הוספת חשבון SIP"</string>
+    <string name="phone_accounts_configure_account_settings" msgid="6622119715253196586">"קביעת הגדרות החשבון"</string>
     <string name="phone_accounts_all_calling_accounts" msgid="1609600743500618823">"כל החשבונות לביצוע שיחות"</string>
-    <string name="phone_accounts_all_calling_accounts_summary" msgid="2214134955430107240">"בחר אילו חשבונות יכולים להתקשר"</string>
+    <string name="phone_accounts_all_calling_accounts_summary" msgid="2214134955430107240">"בחירת החשבונות שיכולים להתקשר"</string>
     <string name="wifi_calling" msgid="3650509202851355742">"‏שיחות ב-Wi-Fi"</string>
     <string name="connection_service_default_label" msgid="7332739049855715584">"שירות חיבור מובנה"</string>
     <string name="voicemail" msgid="7697769412804195032">"דואר קולי"</string>
@@ -93,7 +93,7 @@
     <string name="sum_cdma_call_settings" msgid="3185825305136993636">"‏הגדרות שיחה נוספות של CDMA בלבד"</string>
     <string name="labelNwService" msgid="6015891883487125120">"הגדרות שירות רשת"</string>
     <string name="labelCallerId" msgid="2090540744550903172">"שיחה מזוהה"</string>
-    <string name="sum_loading_settings" msgid="434063780286688775">"טוען הגדרות..."</string>
+    <string name="sum_loading_settings" msgid="434063780286688775">"טעינת ההגדרות מתבצעת..."</string>
     <string name="sum_hide_caller_id" msgid="131100328602371933">"המספר מוסתר בשיחות יוצאות"</string>
     <string name="sum_show_caller_id" msgid="3571854755324664591">"מספר המוצג בשיחות יוצאות"</string>
     <string name="sum_default_caller_id" msgid="1767070797135682959">"שימוש בהגדרות ברירת המחדל של המפעיל כדי להציג את המספר שלי בשיחות יוצאות"</string>
@@ -103,25 +103,25 @@
     <string name="call_forwarding_settings" msgid="8937130467468257671">"הגדרות של העברת שיחות"</string>
     <string name="call_forwarding_settings_with_label" msgid="2345432813399564272">"הגדרות של העברת שיחות (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
     <string name="labelCF" msgid="3578719437928476078">"העברת שיחות"</string>
-    <string name="labelCFU" msgid="8870170873036279706">"העבר תמיד"</string>
-    <string name="messageCFU" msgid="1361806450979589744">"השתמש תמיד במספר זה"</string>
-    <string name="sum_cfu_enabled_indicator" msgid="9030139213402432776">"מעביר את כל השיחות"</string>
-    <string name="sum_cfu_enabled" msgid="5806923046528144526">"מעביר את כל השיחות אל <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
+    <string name="labelCFU" msgid="8870170873036279706">"העברה תמיד"</string>
+    <string name="messageCFU" msgid="1361806450979589744">"יש להשתמש תמיד במספר זה"</string>
+    <string name="sum_cfu_enabled_indicator" msgid="9030139213402432776">"כל השיחות מועברות"</string>
+    <string name="sum_cfu_enabled" msgid="5806923046528144526">"כל השיחות מועברות אל <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
     <string name="sum_cfu_enabled_no_number" msgid="7287752761743377930">"המספר לא זמין"</string>
     <string name="sum_cfu_disabled" msgid="5010617134210809853">"כבוי"</string>
     <string name="labelCFB" msgid="615265213360512768">"כאשר לא פנוי"</string>
     <string name="messageCFB" msgid="1958017270393563388">"מספר כאשר לא פנוי"</string>
-    <string name="sum_cfb_enabled" msgid="332037613072049492">"מעביר אל <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
+    <string name="sum_cfb_enabled" msgid="332037613072049492">"העברה אל <xliff:g id="PHONENUMBER">{0}</xliff:g> מתבצעת"</string>
     <string name="sum_cfb_disabled" msgid="3589913334164866035">"כבוי"</string>
     <string name="disable_cfb_forbidden" msgid="4831494744351633961">"הספק שלך אינו תומך בהשבתה של העברת שיחות כאשר הטלפון תפוס."</string>
     <string name="labelCFNRy" msgid="3403533792248457946">"כאשר אין מענה"</string>
     <string name="messageCFNRy" msgid="7644434155765359009">"מספר לחיוג כשאין מענה"</string>
-    <string name="sum_cfnry_enabled" msgid="3000500837493854799">"מעביר אל <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
+    <string name="sum_cfnry_enabled" msgid="3000500837493854799">"העברה אל <xliff:g id="PHONENUMBER">{0}</xliff:g> מתבצעת"</string>
     <string name="sum_cfnry_disabled" msgid="1990563512406017880">"כבוי"</string>
     <string name="disable_cfnry_forbidden" msgid="3174731413216550689">"הספק אינו תומך בהשבתה של העברת שיחות כאשר אין מענה בטלפון."</string>
     <string name="labelCFNRc" msgid="4163399350778066013">"כאשר לא נגיש"</string>
     <string name="messageCFNRc" msgid="6980340731313007250">"המספר לחיוג כשלא ניתן להשיג"</string>
-    <string name="sum_cfnrc_enabled" msgid="1799069234006073477">"מעביר אל <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
+    <string name="sum_cfnrc_enabled" msgid="1799069234006073477">"העברה אל <xliff:g id="PHONENUMBER">{0}</xliff:g> מתבצעת"</string>
     <string name="sum_cfnrc_disabled" msgid="739289696796917683">"כבוי"</string>
     <string name="disable_cfnrc_forbidden" msgid="775348748084726890">"הספק שלך לא תומך בהשבתה של העברת שיחות כאשר הטלפון כבוי."</string>
     <string name="registration_cf_forbidden" msgid="4386482610771190420">"הספק הסלולרי שלך לא תומך בהעברת שיחות."</string>
@@ -135,9 +135,9 @@
     <string name="call_settings_admin_user_only" msgid="7238947387649986286">"רק מנהל המערכת יכול לשנות הגדרות שיחה."</string>
     <string name="call_settings_with_label" msgid="8460230435361579511">"הגדרות (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
     <string name="error_updating_title" msgid="2024290892676808965">"שגיאה בהגדרות שיחה"</string>
-    <string name="reading_settings" msgid="1605904432450871183">"קורא הגדרות…"</string>
-    <string name="updating_settings" msgid="3650396734816028808">"מעדכן הגדרות..."</string>
-    <string name="reverting_settings" msgid="7378668837291012205">"מאחזר הגדרות הקודמות…"</string>
+    <string name="reading_settings" msgid="1605904432450871183">"קריאת ההגדרות מתבצעת…"</string>
+    <string name="updating_settings" msgid="3650396734816028808">"עדכון ההגדרות מתבצע..."</string>
+    <string name="reverting_settings" msgid="7378668837291012205">"אחזור ההגדרות הקודמות מתבצע…"</string>
     <string name="response_error" msgid="3904481964024543330">"תגובה לא צפויה מהרשת."</string>
     <string name="exception_error" msgid="330994460090467">"‏שגיאת רשת או שגיאה של כרטיס SIM."</string>
     <string name="stk_cc_ss_to_dial_error" msgid="5147693491690618704">"‏בקשת SS שונתה לשיחה רגילה"</string>
@@ -145,41 +145,41 @@
     <string name="stk_cc_ss_to_ss_error" msgid="8297155544652134278">"‏היה שינוי לבקשת SS חדשה"</string>
     <string name="stk_cc_ss_to_dial_video_error" msgid="4255261231466032505">"‏בקשת SS שונתה לשיחת וידאו"</string>
     <string name="fdn_check_failure" msgid="1833769746374185247">"הגדרת מספרי החיוג הקבועים של אפליקציית הטלפון שלך מופעלת. כתוצאה מכך, חלק מהתכונות הקשורות לשיחות לא פועלות."</string>
-    <string name="radio_off_error" msgid="8321564164914232181">"הפעל את הרדיו לפני ההצגה של הגדרות אלה."</string>
+    <string name="radio_off_error" msgid="8321564164914232181">"יש להפעיל את הרדיו לפני ההצגה של הגדרות אלה."</string>
     <string name="close_dialog" msgid="1074977476136119408">"אישור"</string>
     <string name="enable" msgid="2636552299455477603">"הפעלה"</string>
-    <string name="disable" msgid="1122698860799462116">"כבה"</string>
-    <string name="change_num" msgid="6982164494063109334">"עדכן"</string>
+    <string name="disable" msgid="1122698860799462116">"כיבוי"</string>
+    <string name="change_num" msgid="6982164494063109334">"עדכון"</string>
   <string-array name="clir_display_values">
     <item msgid="8477364191403806960">"רשת ברירת מחדל"</item>
-    <item msgid="6813323051965618926">"הסתר מספר"</item>
-    <item msgid="9150034130629852635">"הצג מספר"</item>
+    <item msgid="6813323051965618926">"הסתרת מספר"</item>
+    <item msgid="9150034130629852635">"הצגת מספר"</item>
   </string-array>
     <string name="vm_changed" msgid="4739599044379692505">"המספר של הדואר הקולי השתנה."</string>
-    <string name="vm_change_failed" msgid="7877733929455763566">"לא ניתן לשנות את מספר הגישה לדואר הקולי.\nאם הבעיה נמשכת, פנה לספק."</string>
-    <string name="fw_change_failed" msgid="9179241823460192148">"לא ניתן לשנות את מספר ההעברה.\nאם הבעיה נמשכת, פנה לספק."</string>
+    <string name="vm_change_failed" msgid="7877733929455763566">"לא ניתן לשנות את מספר הגישה לדואר הקולי.\nאם הבעיה נמשכת, יש לפנות לספק."</string>
+    <string name="fw_change_failed" msgid="9179241823460192148">"לא ניתן לשנות את מספר ההעברה.\nאם הבעיה נמשכת, יש לפנות לספק."</string>
     <string name="fw_get_in_vm_failed" msgid="2432678237218183844">"לא ניתן לאחזר ולשמור את הגדרות מספר ההעברה הנוכחי.\nלעבור בכל זאת לספק החדש?"</string>
     <string name="no_change" msgid="3737264882821031892">"לא בוצעו שינויים."</string>
-    <string name="sum_voicemail_choose_provider" msgid="6750824719081403773">"בחר שירות של דואר קולי"</string>
+    <string name="sum_voicemail_choose_provider" msgid="6750824719081403773">"בחירת שירות דואר קולי"</string>
     <string name="voicemail_default" msgid="6427575113775462077">"הספק שלך"</string>
     <string name="vm_change_pin_old_pin" msgid="7154951790929009241">"קוד גישה ישן"</string>
     <string name="vm_change_pin_new_pin" msgid="2656200418481288069">"קוד גישה חדש"</string>
-    <string name="vm_change_pin_progress_message" msgid="626015184502739044">"אנא המתן."</string>
+    <string name="vm_change_pin_progress_message" msgid="626015184502739044">"יש להמתין."</string>
     <string name="vm_change_pin_error_too_short" msgid="1789139338449945483">"קוד הגישה החדש קצר מדי."</string>
     <string name="vm_change_pin_error_too_long" msgid="3634907034310018954">"קוד הגישה החדש ארוך מדי."</string>
     <string name="vm_change_pin_error_too_weak" msgid="8581892952627885719">"קוד הגישה החדש חלש מדי. בסיסמה חזקה אסור שיהיו ספרות ברצף מספרי או ספרות שחוזרות על עצמן."</string>
     <string name="vm_change_pin_error_mismatch" msgid="5364847280026257331">"קוד הגישה הישן אינו תואם."</string>
     <string name="vm_change_pin_error_invalid" msgid="5230002671175580674">"קוד הגישה החדש מכיל תווים לא חוקיים."</string>
     <string name="vm_change_pin_error_system_error" msgid="9116483527909681791">"לא ניתן לשנות את קוד הגישה"</string>
-    <string name="vvm_unsupported_message_format" msgid="4206402558577739713">"סוג ההודעה לא נתמך. התקשר למספר <xliff:g id="NUMBER">%s</xliff:g> כדי להאזין לה."</string>
+    <string name="vvm_unsupported_message_format" msgid="4206402558577739713">"סוג ההודעה לא נתמך. יש להתקשר למספר <xliff:g id="NUMBER">%s</xliff:g> כדי להאזין לה."</string>
     <string name="network_settings_title" msgid="7560807107123171541">"רשת סלולרית"</string>
     <string name="label_available" msgid="1316084116670821258">"רשתות זמינות"</string>
-    <string name="load_networks_progress" msgid="4051433047717401683">"מחפש..."</string>
+    <string name="load_networks_progress" msgid="4051433047717401683">"החיפוש מתבצע..."</string>
     <string name="empty_networks_list" msgid="9216418268008582342">"לא נמצאו רשתות."</string>
     <string name="network_query_error" msgid="3862515805115145124">"לא נמצאו רשתות. אפשר לנסות שוב."</string>
-    <string name="register_on_network" msgid="4194770527833960423">"נרשם ב-<xliff:g id="NETWORK">%s</xliff:g>…"</string>
+    <string name="register_on_network" msgid="4194770527833960423">"ההרשמה ב-<xliff:g id="NETWORK">%s</xliff:g> מתבצעת…"</string>
     <string name="not_allowed" msgid="8541221928746104798">"‏כרטיס ה-SIM לא מאפשר חיבור לרשת זו."</string>
-    <string name="connect_later" msgid="1950138106010005425">"לא ניתן להתחבר לרשת זו כעת. נסה שוב מאוחר יותר."</string>
+    <string name="connect_later" msgid="1950138106010005425">"לא ניתן להתחבר לרשת זו כעת. יש לנסות שוב מאוחר יותר."</string>
     <string name="registration_done" msgid="5337407023566953292">"רשום ברשת."</string>
     <string name="already_auto" msgid="8607068290733079336">"הבחירה האוטומטית כבר מופעלת."</string>
     <string name="select_automatically" msgid="779750291257872651">"בחירה אוטומטית של הרשת"</string>
@@ -187,7 +187,7 @@
     <string name="network_select_title" msgid="4117305053881611988">"רשת"</string>
     <string name="register_automatically" msgid="3907580547590554834">"רישום אוטומטי..."</string>
     <string name="preferred_network_mode_title" msgid="5253395265169539830">"סוג רשת מועדף"</string>
-    <string name="preferred_network_mode_summary" msgid="3787989000044330064">"שנה את מצב ההפעלה של הרשת"</string>
+    <string name="preferred_network_mode_summary" msgid="3787989000044330064">"שינוי מצב ההפעלה של הרשת"</string>
     <string name="preferred_network_mode_dialogtitle" msgid="2781447433514459696">"סוג רשת מועדף"</string>
     <string name="forbidden_network" msgid="5081729819561333023">"(אסור)"</string>
     <string name="choose_network_title" msgid="5335832663422653082">"בחירת רשת"</string>
@@ -239,25 +239,25 @@
     <string name="preferred_network_mode_cdma_evdo_summary" msgid="3629440709757307077">"‏מצב רשת מועדפת: CDMA / EvDo"</string>
     <string name="preferred_network_mode_cdma_only_summary" msgid="211164451887102568">"‏מצב רשת מועדפת: CDMA בלבד"</string>
     <string name="preferred_network_mode_evdo_only_summary" msgid="939116631952132878">"‏מצב רשת מועדפת: EvDo בלבד"</string>
-    <string name="preferred_network_mode_cdma_evdo_gsm_wcdma_summary" msgid="7891131456022601976">"‏מצב רשת מועדף: CDMA/EvDo/GSM/WCDMA"</string>
-    <string name="preferred_network_mode_lte_summary" msgid="8050539466545797149">"‏מצב רשת מועדף: LTE"</string>
-    <string name="preferred_network_mode_lte_gsm_wcdma_summary" msgid="2217794334331254936">"‏מצב רשת מועדף: GSM/WCDMA/LTE"</string>
-    <string name="preferred_network_mode_lte_cdma_evdo_summary" msgid="5559198623419981805">"‏מצב רשת מועדף: CDMA+LTE/EVDO"</string>
+    <string name="preferred_network_mode_cdma_evdo_gsm_wcdma_summary" msgid="7891131456022601976">"‏מצב רשת מועדפת: CDMA/EvDo/GSM/WCDMA"</string>
+    <string name="preferred_network_mode_lte_summary" msgid="8050539466545797149">"‏מצב רשת מועדפת: LTE"</string>
+    <string name="preferred_network_mode_lte_gsm_wcdma_summary" msgid="2217794334331254936">"‏מצב רשת מועדפת: GSM/WCDMA/LTE"</string>
+    <string name="preferred_network_mode_lte_cdma_evdo_summary" msgid="5559198623419981805">"‏מצב רשת מועדפת: CDMA+LTE/EVDO"</string>
     <string name="preferred_network_mode_lte_cdma_evdo_gsm_wcdma_summary" msgid="6707224437925495615">"‏מצב רשת מועדפת: LTE‏/CDMA‏/EvDo‏/GSM‏/WCDMA"</string>
     <string name="preferred_network_mode_global_summary" msgid="3847086258439582411">"מצב רשת מועדף: גלובלי"</string>
-    <string name="preferred_network_mode_lte_wcdma_summary" msgid="7001804022020813865">"‏מצב רשת מועדף: LTE / WCDMA"</string>
-    <string name="preferred_network_mode_lte_gsm_umts_summary" msgid="6484203890156282179">"‏מצב רשת מועדף: LTE / GSM / UMTS"</string>
+    <string name="preferred_network_mode_lte_wcdma_summary" msgid="7001804022020813865">"‏מצב רשת מועדפת: LTE / WCDMA"</string>
+    <string name="preferred_network_mode_lte_gsm_umts_summary" msgid="6484203890156282179">"‏מצב רשת מועדפת: LTE / GSM / UMTS"</string>
     <string name="preferred_network_mode_lte_cdma_summary" msgid="8187929456614068518">"‏מצב רשת מועדפת: LTE / CDMA"</string>
-    <string name="preferred_network_mode_tdscdma_summary" msgid="3602127224234207206">"‏מצב רשת מועדף: TDSCDMA"</string>
-    <string name="preferred_network_mode_tdscdma_wcdma_summary" msgid="7076968749402201123">"‏מצב רשת מועדף: TDSCDMA / WCDMA"</string>
-    <string name="preferred_network_mode_lte_tdscdma_summary" msgid="3001058390866953624">"‏מצב רשת מועדף: LTE / TDSCDMA"</string>
-    <string name="preferred_network_mode_tdscdma_gsm_summary" msgid="1716983444872465309">"‏מצב רשת מועדף: TDSCDMA / GSM"</string>
-    <string name="preferred_network_mode_lte_tdscdma_gsm_summary" msgid="1349057007230669585">"‏מצב רשת מועדף: LTE/GSM/TDSCDMA"</string>
-    <string name="preferred_network_mode_tdscdma_gsm_wcdma_summary" msgid="2092262901885164194">"‏מצב רשת מועדף: TDSCDMA/GSM/WCDMA"</string>
-    <string name="preferred_network_mode_lte_tdscdma_wcdma_summary" msgid="56422129430744466">"‏מצב רשת מועדף: LTE/TDSCDMA/WCDMA"</string>
-    <string name="preferred_network_mode_lte_tdscdma_gsm_wcdma_summary" msgid="2993923113350341106">"‏מצב רשת מועדף: LTE/TDSCDMA/GSM/WCDMA"</string>
-    <string name="preferred_network_mode_tdscdma_cdma_evdo_gsm_wcdma_summary" msgid="2779089629254220257">"‏מצב רשת מועדף: TDSCDMA/CDMA/EvDo/GSM/WCDMA"</string>
-    <string name="preferred_network_mode_lte_tdscdma_cdma_evdo_gsm_wcdma_summary" msgid="9065672185435798587">"‏מצב רשת מועדף: LTE/TDSCDMA/CDMA/EvDo/GSM/WCDMA"</string>
+    <string name="preferred_network_mode_tdscdma_summary" msgid="3602127224234207206">"‏מצב רשת מועדפת: TDSCDMA"</string>
+    <string name="preferred_network_mode_tdscdma_wcdma_summary" msgid="7076968749402201123">"‏מצב רשת מועדפת: TDSCDMA / WCDMA"</string>
+    <string name="preferred_network_mode_lte_tdscdma_summary" msgid="3001058390866953624">"‏מצב רשת מועדפת: LTE / TDSCDMA"</string>
+    <string name="preferred_network_mode_tdscdma_gsm_summary" msgid="1716983444872465309">"‏מצב רשת מועדפת: TDSCDMA / GSM"</string>
+    <string name="preferred_network_mode_lte_tdscdma_gsm_summary" msgid="1349057007230669585">"‏מצב רשת מועדפת: LTE/GSM/TDSCDMA"</string>
+    <string name="preferred_network_mode_tdscdma_gsm_wcdma_summary" msgid="2092262901885164194">"‏מצב רשת מועדפת: TDSCDMA/GSM/WCDMA"</string>
+    <string name="preferred_network_mode_lte_tdscdma_wcdma_summary" msgid="56422129430744466">"‏מצב רשת מועדפת: LTE/TDSCDMA/WCDMA"</string>
+    <string name="preferred_network_mode_lte_tdscdma_gsm_wcdma_summary" msgid="2993923113350341106">"‏מצב רשת מועדפת: LTE/TDSCDMA/GSM/WCDMA"</string>
+    <string name="preferred_network_mode_tdscdma_cdma_evdo_gsm_wcdma_summary" msgid="2779089629254220257">"‏מצב רשת מועדפת: TDSCDMA/CDMA/EvDo/GSM/WCDMA"</string>
+    <string name="preferred_network_mode_lte_tdscdma_cdma_evdo_gsm_wcdma_summary" msgid="9065672185435798587">"‏מצב רשת מועדפת: LTE/TDSCDMA/CDMA/EvDo/GSM/WCDMA"</string>
     <string name="preferred_network_mode_nr_only_summary" msgid="1467452233297987391">"‏מצב רשת מועדפת: NR בלבד"</string>
     <string name="preferred_network_mode_nr_lte_summary" msgid="5890170406507535976">"‏מצב רשת מועדפת: NR ‏/ LTE"</string>
     <string name="preferred_network_mode_nr_lte_cdma_evdo_summary" msgid="5507940227264296616">"‏מצב רשת מועדפת: NR‏/LTE‏/CDMA‏/EvDo"</string>
@@ -273,17 +273,17 @@
     <string name="network_operator_category" msgid="4992217193732304680">"רשת"</string>
     <string name="enhanced_4g_lte_mode_title" msgid="4213420368777080540">"‏מצב 4G LTE משופר"</string>
     <!-- no translation found for enhanced_4g_lte_mode_title_variant:0 (7240155150166394308) -->
-    <string name="enhanced_4g_lte_mode_summary" msgid="7725708511804143638">"‏השתמש בשירותי LTE כדי לשפר את הקול ודרכי תקשורת אחרות (מומלץ)"</string>
+    <string name="enhanced_4g_lte_mode_summary" msgid="7725708511804143638">"‏שימוש בשירותי LTE כדי לשפר את הקול ודרכי תקשורת אחרות (מומלץ)"</string>
     <string name="enhanced_4g_lte_mode_summary_o2" msgid="2521108446409016542">"‏שימוש בשירותי 4G כדי לשפר את הקול ודרכי תקשורת אחרות (מומלץ)"</string>
     <!-- no translation found for enhanced_4g_lte_mode_sumary_variant:0 (2943982616649705147) -->
     <!-- no translation found for enhanced_4g_lte_mode_sumary_variant:1 (5262249464504131443) -->
     <!-- no translation found for enhanced_4g_lte_mode_sumary_variant:2 (6356974241850241718) -->
     <string name="data_enabled" msgid="22525832097434368">"נתונים מופעלים"</string>
-    <string name="data_enable_summary" msgid="696860063456536557">"התר שימוש בנתונים"</string>
+    <string name="data_enable_summary" msgid="696860063456536557">"התרת שימוש בחבילת הגלישה"</string>
     <string name="dialog_alert_title" msgid="5260471806940268478">"זהירות"</string>
     <string name="roaming" msgid="1576180772877858949">"נדידה"</string>
-    <string name="roaming_enable" msgid="6853685214521494819">"התחבר לשירותי נתונים בעת נדידה"</string>
-    <string name="roaming_disable" msgid="8856224638624592681">"התחבר לשירותי נתונים בעת נדידה"</string>
+    <string name="roaming_enable" msgid="6853685214521494819">"יש להתחבר לשירותי נתונים בעת נדידה"</string>
+    <string name="roaming_disable" msgid="8856224638624592681">"יש להתחבר לשירותי נתונים בעת נדידה"</string>
     <string name="roaming_reenable_message" msgid="1951802463885727915">"הנדידה מושבתת. אפשר להקיש כדי להפעיל אותה."</string>
     <string name="roaming_enabled_message" msgid="9022249120750897">"ייתכנו חיובי נדידה. יש להקיש כדי לשנות."</string>
     <string name="roaming_notification_title" msgid="3590348480688047320">"המכשיר התנתק מחבילת הגלישה"</string>
@@ -355,7 +355,7 @@
     <string name="international_enable" msgid="8943466745792690340">"חדשות פנים מופעלות"</string>
     <string name="international_disable" msgid="4803498658100318265">"חדשות בינלאומיות מושבתות"</string>
     <string name="list_language_title" msgid="1850167908665485738">"שפה"</string>
-    <string name="list_language_summary" msgid="7921756070782277559">"בחר את שפת החדשות"</string>
+    <string name="list_language_summary" msgid="7921756070782277559">"בחירת שפת החדשות"</string>
   <string-array name="list_language_entries">
     <item msgid="2347238508726934281">"אנגלית"</item>
     <item msgid="5172468397620875174">"צרפתית"</item>
@@ -416,7 +416,7 @@
     <string name="network_4G" msgid="6800527815504223913">"‏4G (מומלץ)"</string>
     <string name="network_global" msgid="3289646154407617631">"גלובלי"</string>
     <string name="cdma_system_select_title" msgid="614165233552656431">"בחירת מערכת"</string>
-    <string name="cdma_system_select_summary" msgid="3840420390242060407">"‏שנה את מצב נדידת CDMA"</string>
+    <string name="cdma_system_select_summary" msgid="3840420390242060407">"‏שינוי מצב נדידת CDMA"</string>
     <string name="cdma_system_select_dialogtitle" msgid="5524639510676501802">"בחירת מערכת"</string>
   <string-array name="cdma_system_select_choices">
     <item msgid="462340042928284921">"בית בלבד"</item>
@@ -433,8 +433,8 @@
     <item msgid="2953825013895327785">"0"</item>
     <item msgid="7970797749269738435">"1"</item>
   </string-array>
-    <string name="cdma_activate_device" msgid="5914720276140097632">"הפעל מכשיר"</string>
-    <string name="cdma_lte_data_service" msgid="359786441782404562">"הגדר שירות נתונים"</string>
+    <string name="cdma_activate_device" msgid="5914720276140097632">"הפעלת המכשיר"</string>
+    <string name="cdma_lte_data_service" msgid="359786441782404562">"הגדרת שירות נתונים"</string>
     <string name="carrier_settings_title" msgid="6292869148169850220">"הגדרות ספק"</string>
     <string name="fdn" msgid="2545904344666098749">"מספרי חיוג קבועים"</string>
     <string name="fdn_with_label" msgid="6412087553365709494">"מספרי חיוג קבועים (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
@@ -445,7 +445,7 @@
     <string name="fdn_disabled" msgid="6696468878037736600">"מספרי חיוג קבועים מושבתים"</string>
     <string name="enable_fdn" msgid="4830555730418033723">"הפעלת מספרי חיוג קבועים"</string>
     <string name="disable_fdn" msgid="3918794950264647541">"השבתת מספרי חיוג קבועים"</string>
-    <string name="change_pin2" msgid="3110844547237754871">"‏שינוי PIN2"</string>
+    <string name="change_pin2" msgid="3110844547237754871">"שינוי קוד אימות 2"</string>
     <string name="enable_fdn_ok" msgid="5080925177369329827">"השבת מספרי חיוג קבועים"</string>
     <string name="disable_fdn_ok" msgid="3745475926874838676">"הפעלה של מספרי חיוג קבועים"</string>
     <string name="sum_fdn" msgid="6152246141642323582">"ניהול מספרי חיוג קבועים"</string>
@@ -454,95 +454,96 @@
     <string name="voice_privacy" msgid="7346935172372181951">"פרטיות קול"</string>
     <string name="voice_privacy_summary" msgid="3556460926168473346">"הפעלת מצב פרטיות משופרת"</string>
     <string name="tty_mode_option_title" msgid="3843817710032641703">"‏מצב TTY"</string>
-    <string name="tty_mode_option_summary" msgid="4770510287236494371">"‏הגדר מצב TTY"</string>
+    <string name="tty_mode_option_summary" msgid="4770510287236494371">"‏הגדרת מצב TTY"</string>
     <string name="auto_retry_mode_title" msgid="2985801935424422340">"ניסיון חוזר אוטומטי"</string>
     <string name="auto_retry_mode_summary" msgid="2863919925349511402">"הפעלת מצב \'ניסיון חוזר\'."</string>
     <string name="tty_mode_not_allowed_video_call" msgid="6551976083652752815">"‏שינוי מצב TTY אינו מותר במהלך שיחת וידאו"</string>
-    <string name="menu_add" msgid="5616487894975773141">"הוסף איש קשר"</string>
-    <string name="menu_edit" msgid="3593856941552460706">"ערוך איש קשר"</string>
-    <string name="menu_delete" msgid="6326861853830546488">"מחק איש קשר"</string>
+    <string name="menu_add" msgid="5616487894975773141">"הוספת איש קשר"</string>
+    <string name="menu_edit" msgid="3593856941552460706">"עריכת איש קשר"</string>
+    <string name="menu_delete" msgid="6326861853830546488">"מחיקת איש קשר"</string>
     <string name="menu_dial" msgid="4178537318419450012">"חיוג לאיש הקשר"</string>
-    <string name="get_pin2" msgid="4221654606863196332">"‏הקלד PIN2"</string>
+    <string name="get_pin2" msgid="4221654606863196332">"יש להקליד קוד אימות 2"</string>
     <string name="name" msgid="1347432469852527784">"שם"</string>
     <string name="number" msgid="1564053487748491000">"מספר"</string>
-    <string name="save" msgid="983805790346099749">"שמור"</string>
-    <string name="add_fdn_contact" msgid="1169713422306640887">"הוסף מספר חיוג קבוע"</string>
-    <string name="adding_fdn_contact" msgid="3112531600824361259">"מוסיף מספר חיוג קבוע..."</string>
+    <string name="save" msgid="983805790346099749">"שמירה"</string>
+    <string name="add_fdn_contact" msgid="1169713422306640887">"הוספת מספר חיוג קבוע"</string>
+    <string name="adding_fdn_contact" msgid="3112531600824361259">"הוספת מספר חיוג קבוע מתבצעת..."</string>
     <string name="fdn_contact_added" msgid="2840016151693394596">"מספר חיוג קבוע נוסף."</string>
-    <string name="edit_fdn_contact" msgid="6030829994819587408">"ערוך מספר חיוג קבוע"</string>
-    <string name="updating_fdn_contact" msgid="6989341376868227150">"מעדכן מספר חיוג קבוע..."</string>
+    <string name="edit_fdn_contact" msgid="6030829994819587408">"עריכת מספר חיוג קבוע"</string>
+    <string name="updating_fdn_contact" msgid="6989341376868227150">"עדכון מספר החיוג הקבוע מתבצע..."</string>
     <string name="fdn_contact_updated" msgid="6876330243323118937">"מספר חיוג קבוע עודכן."</string>
-    <string name="delete_fdn_contact" msgid="7027405651994507077">"מחק מספר חיוג קבוע"</string>
-    <string name="deleting_fdn_contact" msgid="6872320570844460428">"מוחק מספר חיוג קבוע..."</string>
+    <string name="delete_fdn_contact" msgid="7027405651994507077">"מחיקת מספר חיוג קבוע"</string>
+    <string name="deleting_fdn_contact" msgid="6872320570844460428">"מחיקת מספר חיוג קבוע מתבצעת..."</string>
     <string name="fdn_contact_deleted" msgid="1680714996763848838">"מספר חיוג קבוע נמחק."</string>
     <string name="pin2_invalid" msgid="2313954262684494442">"רשימת מספרי חיוג קבועים לא עודכנה מכיוון שקוד הגישה שגוי."</string>
     <string name="fdn_invalid_number" msgid="9067189814657840439">"‏מספר ה-FDN לא עודכן כי הוא מכיל יותר מ-<xliff:g id="FDN_NUMBER_LIMIT_LENGTH">%d</xliff:g> ספרות."</string>
     <string name="pin2_or_fdn_invalid" msgid="7542639487955868181">"רשימת מספרי החיוג הקבועים לא עודכנה. קוד הגישה היה שגוי או שמספר הטלפון נדחה."</string>
     <string name="fdn_failed" msgid="216592346853420250">"‏פעולת FDN נכשלה."</string>
-    <string name="simContacts_emptyLoading" msgid="4989040293858675483">"‏קורא מכרטיס SIM…"</string>
+    <string name="simContacts_emptyLoading" msgid="4989040293858675483">"‏קריאה מכרטיס SIM מתבצעת…"</string>
     <string name="simContacts_empty" msgid="1135632055473689521">"‏אין אנשי קשר בכרטיס ה-SIM."</string>
-    <string name="simContacts_title" msgid="2714029230160136647">"בחר אנשי קשר לייבוא"</string>
-    <string name="simContacts_airplaneMode" msgid="4654884030631503808">"‏בטל את מצב טיסה כדי לייבא אנשי קשר מכרטיס ה-SIM."</string>
-    <string name="enable_pin" msgid="967674051730845376">"‏הפעלה/השבתה של ה-PIN של SIM"</string>
-    <string name="change_pin" msgid="3657869530942905790">"‏שנה PIN של SIM"</string>
-    <string name="enter_pin_text" msgid="3182311451978663356">"‏PIN של SIM:"</string>
-    <string name="oldPinLabel" msgid="8618515202411987721">"‏PIN ישן"</string>
-    <string name="newPinLabel" msgid="3585899083055354732">"‏PIN חדש"</string>
-    <string name="confirmPinLabel" msgid="7783531218662473778">"‏אשר PIN חדש"</string>
-    <string name="badPin" msgid="4549286285015892321">"‏ה-PIN הישן שהקלדת שגוי. נסה שוב."</string>
-    <string name="mismatchPin" msgid="1467254768290323845">"‏קודי ה-PIN שהקלדת אינם תואמים. נסה שוב."</string>
-    <string name="invalidPin" msgid="7363723429414001979">"‏הקלד PIN שאורכו 4 עד 8 ספרות."</string>
+    <string name="simContacts_title" msgid="2714029230160136647">"בחירת אנשי קשר לייבוא"</string>
+    <string name="simContacts_airplaneMode" msgid="4654884030631503808">"‏יש לבטל את מצב טיסה כדי לייבא אנשי קשר מכרטיס ה-SIM."</string>
+    <string name="enable_pin" msgid="967674051730845376">"‏הפעלה/השבתה של קוד האימות של SIM"</string>
+    <string name="change_pin" msgid="3657869530942905790">"‏שינוי קוד אימות של SIM"</string>
+    <string name="enter_pin_text" msgid="3182311451978663356">"‏קוד אימות של SIM:"</string>
+    <string name="oldPinLabel" msgid="8618515202411987721">"קוד אימות ישן"</string>
+    <string name="newPinLabel" msgid="3585899083055354732">"קוד אימות חדש"</string>
+    <string name="confirmPinLabel" msgid="7783531218662473778">"אישור קוד אימות חדש"</string>
+    <string name="badPin" msgid="4549286285015892321">"קוד האימות הישן שהקלדת שגוי. יש לנסות שוב."</string>
+    <string name="mismatchPin" msgid="1467254768290323845">"קודי האימות שהקלדת לא תואמים. יש לנסות שוב."</string>
+    <string name="invalidPin" msgid="7363723429414001979">"יש להקליד קוד אימות שאורכו 4 עד 8 ספרות."</string>
     <string name="disable_sim_pin" msgid="3112303905548613752">"‏ניקוי PIN עבור SIM"</string>
-    <string name="enable_sim_pin" msgid="445461050748318980">"‏הגדרת PIN עבור SIM"</string>
-    <string name="enable_in_progress" msgid="4135305985717272592">"‏מגדיר PIN…"</string>
-    <string name="enable_pin_ok" msgid="2877428038280804256">"‏PIN הוגדר"</string>
-    <string name="disable_pin_ok" msgid="888505244389647754">"‏ה-PIN נוקה"</string>
-    <string name="pin_failed" msgid="4527347792881939652">"‏PIN2 שגוי"</string>
-    <string name="pin_changed" msgid="7291153750090452808">"‏PIN עודכן"</string>
-    <string name="puk_requested" msgid="2061337960609806851">"‏סיסמה שגויה. PIN נעול כעת. יש להזין PUK."</string>
-    <string name="enter_pin2_text" msgid="7266379426804295979">"PIN2"</string>
-    <string name="oldPin2Label" msgid="4648543187859997203">"‏PIN2 ישן"</string>
-    <string name="newPin2Label" msgid="1840905981784453939">"‏PIN2 חדש"</string>
-    <string name="confirmPin2Label" msgid="4336025914667593762">"‏אשר PIN2 חדש"</string>
-    <string name="badPuk2" msgid="6438182906645832235">"‏PUK2 שגוי. נסה שוב."</string>
-    <string name="badPin2" msgid="2760917538643074635">"‏PIN2 הישן שגוי. נסה שוב."</string>
-    <string name="mismatchPin2" msgid="4952718725266700631">"‏קודי PIN2 לא תואמים. נסה שוב."</string>
-    <string name="invalidPin2" msgid="6467957903056379343">"‏הזן PIN2 שאורכו בין 4 ל-8 ספרות."</string>
-    <string name="invalidPuk2" msgid="713729511903849544">"‏הזן PUK2 שאורכו 8 ספרות."</string>
-    <string name="pin2_changed" msgid="5710551850481287821">"‏PIN2 עודכן"</string>
-    <string name="label_puk2_code" msgid="2852217004288085562">"‏הזן קוד PUK2"</string>
-    <string name="fdn_enable_puk2_requested" msgid="5793652792131588041">"‏סיסמה שגויה. PIN2 חסום כעת. כדי לנסות שוב, יש לשנות את PIN 2."</string>
-    <string name="puk2_requested" msgid="6992374450720307514">"‏סיסמה שגויה. ה-SIM נעול כעת. הזן PUK2."</string>
+    <string name="enable_sim_pin" msgid="445461050748318980">"‏הגדרת קוד אימות של SIM"</string>
+    <string name="enable_in_progress" msgid="4135305985717272592">"הגדרת קוד האימות מתבצעת…"</string>
+    <string name="enable_pin_ok" msgid="2877428038280804256">"קוד אימות הוגדר"</string>
+    <string name="disable_pin_ok" msgid="888505244389647754">"קוד האימות נמחק"</string>
+    <string name="pin_failed" msgid="4527347792881939652">"קוד אימות 2 שגוי"</string>
+    <string name="pin_changed" msgid="7291153750090452808">"קוד אימות עודכן"</string>
+    <string name="puk_requested" msgid="2061337960609806851">"‏סיסמה שגויה. קוד האימות נעול כעת. יש להזין PUK."</string>
+    <string name="enter_pin2_text" msgid="7266379426804295979">"קוד אימות 2"</string>
+    <string name="oldPin2Label" msgid="4648543187859997203">"קוד אימות 2 ישן"</string>
+    <string name="newPin2Label" msgid="1840905981784453939">"קוד אימות 2 חדש"</string>
+    <string name="confirmPin2Label" msgid="4336025914667593762">"אישור קוד אימות 2 חדש"</string>
+    <string name="badPuk2" msgid="6438182906645832235">"‏PUK2 שגוי. יש לנסות שוב."</string>
+    <string name="badPin2" msgid="2760917538643074635">"קוד אימות 2 הישן שגוי. יש לנסות שוב."</string>
+    <string name="mismatchPin2" msgid="4952718725266700631">"קודי אימות 2 לא תואמים. יש לנסות שוב."</string>
+    <string name="invalidPin2" msgid="6467957903056379343">"יש להזין קוד אימות 2 שאורכו בין 4 ל-8 ספרות."</string>
+    <string name="invalidPuk2" msgid="713729511903849544">"‏יש להזין PUK2 שאורכו 8 ספרות."</string>
+    <string name="pin2_changed" msgid="5710551850481287821">"קוד אימות 2 עודכן"</string>
+    <string name="label_puk2_code" msgid="2852217004288085562">"‏הזנת קוד PUK2"</string>
+    <string name="fdn_enable_puk2_requested" msgid="5793652792131588041">"‏סיסמה שגויה. קוד אימות 2 חסום כעת. כדי לנסות שוב, יש לשנות את PIN 2."</string>
+    <string name="puk2_requested" msgid="6992374450720307514">"‏סיסמה שגויה. ה-SIM נעול כעת. יש להזין PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"‏PUK2 נחסם לצמיתות."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"נותרו לך עוד <xliff:g id="NUMBER">%d</xliff:g> ניסיונות."</string>
-    <string name="pin2_unblocked" msgid="4481107908727789303">"‏PIN2 אינו חסום עוד"</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"‏נעילת PUK2. כדי לבטל את הנעילה, צריך לפנות לספק השירות."</string>
+    <string name="pin2_unblocked" msgid="4481107908727789303">"קוד אימות 2 אינו חסום עוד"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"‏שגיאת רשת או כרטיס SIM"</string>
     <string name="doneButton" msgid="7371209609238460207">"סיום"</string>
     <string name="voicemail_settings_number_label" msgid="1265118640154688162">"המספר של הדואר הקולי"</string>
-    <string name="card_title_dialing" msgid="8742182654254431781">"מחייג"</string>
-    <string name="card_title_redialing" msgid="18130232613559964">"מחייג שוב"</string>
+    <string name="card_title_dialing" msgid="8742182654254431781">"החיוג מתבצע"</string>
+    <string name="card_title_redialing" msgid="18130232613559964">"חיוג חוזר מתבצע"</string>
     <string name="card_title_conf_call" msgid="901197309274457427">"שיחת ועידה"</string>
     <string name="card_title_incoming_call" msgid="881424648458792430">"שיחה נכנסת"</string>
     <string name="card_title_call_ended" msgid="650223980095026340">"השיחה הסתיימה"</string>
     <string name="card_title_on_hold" msgid="9028319436626975207">"בהמתנה"</string>
-    <string name="card_title_hanging_up" msgid="814874106866647871">"מנתק"</string>
+    <string name="card_title_hanging_up" msgid="814874106866647871">"הניתוק מתבצע"</string>
     <string name="card_title_in_call" msgid="8231896539567594265">"בשיחה"</string>
     <string name="notification_voicemail_title" msgid="3932876181831601351">"דואר קולי חדש"</string>
     <string name="notification_voicemail_title_count" msgid="2806950319222327082">"דואר קולי חדש (<xliff:g id="COUNT">%d</xliff:g>)"</string>
-    <string name="notification_voicemail_text_format" msgid="5720947141702312537">"‏חייג ‎<xliff:g id="VOICEMAIL_NUMBER">%s</xliff:g>‎"</string>
+    <string name="notification_voicemail_text_format" msgid="5720947141702312537">"‏חיוג ל-‎<xliff:g id="VOICEMAIL_NUMBER">%s</xliff:g>‎"</string>
     <string name="notification_voicemail_no_vm_number" msgid="3423686009815186750">"המספר של הדואר הקולי אינו ידוע"</string>
     <string name="notification_network_selection_title" msgid="255595526707809121">"אין שירות"</string>
     <string name="notification_network_selection_text" msgid="553288408722427659">"הרשת שנבחרה (<xliff:g id="OPERATOR_NAME">%s</xliff:g>) לא זמינה"</string>
     <string name="incall_error_power_off" product="watch" msgid="7191184639454113633">"עליך להפעיל את הרשת הסלולרית, להשבית את מצב הטיסה או להשבית את מצב החיסכון בסוללה כדי להתקשר."</string>
-    <string name="incall_error_power_off" product="default" msgid="8131672264311208673">"בטל את מצב טיסה כדי לבצע שיחה."</string>
-    <string name="incall_error_power_off_wfc" msgid="9125661184694727052">"בטל את מצב טיסה או התחבר לרשת אלחוטית כדי לבצע שיחה."</string>
+    <string name="incall_error_power_off" product="default" msgid="8131672264311208673">"יש לבטל את מצב טיסה כדי לבצע שיחה."</string>
+    <string name="incall_error_power_off_wfc" msgid="9125661184694727052">"יש לבטל את מצב טיסה או להתחבר לרשת אלחוטית כדי לבצע שיחה."</string>
     <string name="incall_error_ecm_emergency_only" msgid="5622379058883722080">"עליך לצאת ממצב חירום של התקשרות חזרה כדי לבצע שיחות שאינן שיחות חירום."</string>
     <string name="incall_error_emergency_only" msgid="8786127461027964653">"לא רשום ברשת."</string>
     <string name="incall_error_out_of_service" msgid="1927265196942672791">"הרשת הסלולרית אינה זמינה."</string>
     <string name="incall_error_out_of_service_wfc" msgid="4497663185857190885">"הרשת הסלולרית לא זמינה. עליך להתחבר לרשת אלחוטית כדי להתקשר."</string>
-    <string name="incall_error_no_phone_number_supplied" msgid="8680831089508851894">"כדי להתקשר, הזן מספר טלפון חוקי."</string>
+    <string name="incall_error_no_phone_number_supplied" msgid="8680831089508851894">"כדי להתקשר, יש להזין מספר טלפון חוקי."</string>
     <string name="incall_error_call_failed" msgid="393508653582682539">"השיחה נכשלה."</string>
-    <string name="incall_error_cannot_add_call" msgid="5425764862628655443">"לא ניתן להוסיף את השיחה כרגע. ניתן לנסות לשלוח הודעה."</string>
+    <string name="incall_error_cannot_add_call" msgid="5425764862628655443">"לא ניתן להוסיף את השיחה כרגע. אפשר לנסות לשלוח הודעה."</string>
     <string name="incall_error_supp_service_unknown" msgid="8751177117194592623">"שירות לא נתמך"</string>
     <string name="incall_error_supp_service_switch" msgid="5272822448189448479">"לא ניתן לעבור בין שיחות."</string>
     <string name="incall_error_supp_service_resume" msgid="1276861499306817035">"לא ניתן להמשיך את השיחה."</string>
@@ -552,8 +553,8 @@
     <string name="incall_error_supp_service_reject" msgid="3044363092441655912">"לא ניתן לדחות שיחה."</string>
     <string name="incall_error_supp_service_hangup" msgid="836524952243836735">"לא ניתן לשחרר שיחות."</string>
     <string name="incall_error_supp_service_hold" msgid="8535056414643540997">"לא ניתן להחזיק שיחות."</string>
-    <string name="incall_error_wfc_only_no_wireless_network" msgid="5860742792811400109">"התחבר לרשת אלחוטית כדי לבצע שיחה."</string>
-    <string name="incall_error_promote_wfc" msgid="9164896813931363415">"‏הפעל את \'שיחות Wi-Fi\' כדי להתקשר."</string>
+    <string name="incall_error_wfc_only_no_wireless_network" msgid="5860742792811400109">"יש להתחבר לרשת אלחוטית כדי לבצע שיחה."</string>
+    <string name="incall_error_promote_wfc" msgid="9164896813931363415">"‏יש להפעיל את \'שיחות Wi-Fi\' כדי להתקשר."</string>
     <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>
@@ -561,19 +562,19 @@
     <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>
-    <string name="emergency_enable_radio_dialog_message" msgid="1695305158151408629">"מפעיל את הרדיו…"</string>
-    <string name="emergency_enable_radio_dialog_retry" msgid="4329131876852608587">"אין שירות. מנסה שוב..."</string>
+    <string name="emergency_enable_radio_dialog_message" msgid="1695305158151408629">"הפעלת הרדיו מתבצעת…"</string>
+    <string name="emergency_enable_radio_dialog_retry" msgid="4329131876852608587">"אין שירות. ניסיון חוזר מתבצע..."</string>
     <string name="radio_off_during_emergency_call" msgid="8011154134040481609">"אי אפשר לעבור למצב טיסה בזמן שיחת חירום."</string>
     <string name="dial_emergency_error" msgid="825822413209026039">"לא ניתן להתקשר. <xliff:g id="NON_EMERGENCY_NUMBER">%s</xliff:g> אינו מספר חירום."</string>
-    <string name="dial_emergency_empty_error" msgid="2785803395047793634">"לא ניתן להתקשר. חייג למספר חירום."</string>
+    <string name="dial_emergency_empty_error" msgid="2785803395047793634">"לא ניתן להתקשר. יש לחייג למספר חירום."</string>
     <string name="dial_emergency_calling_not_available" msgid="6485846193794727823">"אי אפשר לבצע שיחות חירום"</string>
     <string name="pin_puk_system_user_only" msgid="1045147220686867922">"‏רק הבעלים של המכשיר יכול להזין קודי אימות/PUK."</string>
     <string name="police_type_description" msgid="2819533883972081757">"משטרה"</string>
     <string name="ambulance_type_description" msgid="6798237503553180461">"אמבולנס"</string>
     <string name="fire_type_description" msgid="6565200468934914930">"אש"</string>
     <string name="description_concat_format" msgid="2014471565101724088">"‏%1$s,‏ %2$s"</string>
-    <string name="dialerKeyboardHintText" msgid="1115266533703764049">"השתמש במקלדת כדי לחייג"</string>
-    <string name="onscreenHoldText" msgid="4025348842151665191">"השהה"</string>
+    <string name="dialerKeyboardHintText" msgid="1115266533703764049">"שימוש במקלדת כדי לחייג"</string>
+    <string name="onscreenHoldText" msgid="4025348842151665191">"השהיה"</string>
     <string name="onscreenEndCallText" msgid="6138725377654842757">"סיום"</string>
     <string name="onscreenShowDialpadText" msgid="658465753816164079">"לוח חיוג"</string>
     <string name="onscreenMuteText" msgid="5470306116733843621">"השתקה"</string>
@@ -584,10 +585,10 @@
     <string name="onscreenManageConferenceText" msgid="4700574060601755137">"ניהול שיחת ועידה"</string>
     <string name="onscreenAudioText" msgid="7224226735052019986">"אודיו"</string>
     <string name="onscreenVideoCallText" msgid="1743992456126258698">"שיחת וידאו"</string>
-    <string name="importSimEntry" msgid="3892354284082689894">"ייבא"</string>
-    <string name="importAllSimEntries" msgid="2628391505643564007">"ייבא הכל"</string>
-    <string name="importingSimContacts" msgid="4995457122107888932">"‏מייבא אנשי קשר מ-SIM"</string>
-    <string name="importToFDNfromContacts" msgid="5068664870738407341">"ייבא מאנשי קשר"</string>
+    <string name="importSimEntry" msgid="3892354284082689894">"ייבוא"</string>
+    <string name="importAllSimEntries" msgid="2628391505643564007">"ייבוא הכול"</string>
+    <string name="importingSimContacts" msgid="4995457122107888932">"‏ייבוא אנשי קשר מ-SIM מתבצע"</string>
+    <string name="importToFDNfromContacts" msgid="5068664870738407341">"ייבוא מאנשי קשר"</string>
     <string name="singleContactImportedMsg" msgid="3619804066300998934">"איש הקשר יובא"</string>
     <string name="failedToImportSingleContactMsg" msgid="228095510489830266">"ייבוא איש הקשר נכשל"</string>
     <string name="hac_mode_title" msgid="4127986689621125468">"מכשירי שמיעה"</string>
@@ -603,16 +604,16 @@
     <item msgid="2131559553795606483">"TTY VCO"</item>
   </string-array>
     <string name="dtmf_tones_title" msgid="7874845461117175236">"‏צלילי DTMF"</string>
-    <string name="dtmf_tones_summary" msgid="2294822239899471201">"‏הגדר את האורך של צלילי DTMF"</string>
+    <string name="dtmf_tones_summary" msgid="2294822239899471201">"‏הגדרת האורך של צלילי DTMF"</string>
   <string-array name="dtmf_tone_entries">
     <item msgid="2271798469250155310">"רגיל"</item>
     <item msgid="6044210222666533564">"ארוך"</item>
   </string-array>
     <string name="network_info_message" msgid="7599413947016532355">"הודעת רשת"</string>
     <string name="network_error_message" msgid="4271579424089326618">"הודעת שגיאה"</string>
-    <string name="ota_title_activate" msgid="4049645324841263423">"הפעל את הטלפון"</string>
-    <string name="ota_touch_activate" msgid="838764494319694754">"יש לבצע שיחה מיוחדת כדי להפעיל את השירות לטלפון. \n\nלאחר הלחיצה על \'הפעל\', הקשב להוראות להפעלת הטלפון."</string>
-    <string name="ota_hfa_activation_title" msgid="3300556778212729671">"מפעיל..."</string>
+    <string name="ota_title_activate" msgid="4049645324841263423">"הפעלת הטלפון"</string>
+    <string name="ota_touch_activate" msgid="838764494319694754">"יש לבצע שיחה מיוחדת כדי להפעיל את השירות לטלפון. \n\nלאחר הלחיצה על \'הפעלה\', יש להקשיב להוראות להפעלת הטלפון."</string>
+    <string name="ota_hfa_activation_title" msgid="3300556778212729671">"ההפעלה מתבצעת..."</string>
     <string name="ota_hfa_activation_dialog_message" msgid="7921718445773342996">"הטלפון מפעיל את שירותי הנתונים שלך לנייד.\n\nהתהליך עשוי לארוך עד 5 דקות."</string>
     <string name="ota_skip_activation_dialog_title" msgid="7666611236789203797">"לדלג על ההפעלה?"</string>
     <string name="ota_skip_activation_dialog_message" msgid="6691722887019708713">"‏אם מדלגים על ההפעלה, אי אפשר להתקשר או להתחבר לרשתות נתונים לנייד (אך אפשר להתחבר לרשתות Wi-Fi). עד להפעלת הטלפון תופיע הודעה שמבקשת לבצע את ההפעלה בכל פעם שמדליקים את הטלפון."</string>
@@ -620,26 +621,26 @@
     <string name="ota_activate" msgid="7939695753665438357">"הפעלה"</string>
     <string name="ota_title_activate_success" msgid="1272135024761004889">"הטלפון מופעל."</string>
     <string name="ota_title_problem_with_activation" msgid="7019745985413368726">"בעיה בהפעלה"</string>
-    <string name="ota_listen" msgid="2772252405488894280">"בצע את ההוראות הנאמרות עד שתשמע שההפעלה הושלמה."</string>
+    <string name="ota_listen" msgid="2772252405488894280">"יש לבצע את ההוראות הנאמרות עד ששומעים שההפעלה הושלמה."</string>
     <string name="ota_speaker" msgid="1086766980329820528">"רמקול"</string>
-    <string name="ota_progress" msgid="8837259285255700132">"מתכנת את הטלפון שלך…"</string>
+    <string name="ota_progress" msgid="8837259285255700132">"התכנות של הטלפון שלך מתבצע…"</string>
     <string name="ota_failure" msgid="5674217489921481576">"לא ניתן היה לתכנת את הטלפון שלך"</string>
-    <string name="ota_successful" msgid="1106825981548107774">"הטלפון שלך מופעל כעת. ייתכן שתמתין עד 15 דקות להפעלת השירות."</string>
+    <string name="ota_successful" msgid="1106825981548107774">"הטלפון שלך מופעל כעת. ייתכן שיהיה צורך להמתין עד 15 דקות להפעלת השירות."</string>
     <string name="ota_unsuccessful" msgid="8531037653803955754">"הטלפון שלך לא הופעל. \nייתכן שעליך למצוא מקום שהקליטה בו טובה יותר (ליד חלון או בחוץ). \n\nנסה שוב או התקשר לשירות לקוחות לקבלת אפשרויות נוספות."</string>
     <string name="ota_spc_failure" msgid="904092035241370080">"‏כשלים מרובים של SPC"</string>
     <string name="ota_call_end" msgid="8657746378290737034">"הקודם"</string>
-    <string name="ota_try_again" msgid="6914781945599998550">"נסו שוב"</string>
+    <string name="ota_try_again" msgid="6914781945599998550">"יש לנסות שוב"</string>
     <string name="ota_next" msgid="2041016619313475914">"הבא"</string>
     <string name="ecm_exit_dialog" msgid="4200691880721429078">"EcmExitDialog"</string>
-    <string name="phone_entered_ecm_text" msgid="8431238297843035842">"נכנס למצב חירום של התקשרות חזרה"</string>
+    <string name="phone_entered_ecm_text" msgid="8431238297843035842">"מתבצע מעבר למצב חירום של התקשרות חזרה"</string>
     <string name="phone_in_ecm_notification_title" msgid="6825016389926367946">"מצב חירום של התקשרות חזרה"</string>
     <string name="phone_in_ecm_call_notification_text" msgid="653972232922670335">"חיבור נתונים מושבת"</string>
     <string name="phone_in_ecm_notification_complete_time" msgid="7341624337163082759">"אין חיבור לרשת נתונים עד <xliff:g id="COMPLETETIME">%s</xliff:g>"</string>
     <plurals name="alert_dialog_exit_ecm" formatted="false" msgid="5425906903766466743">
-      <item quantity="two">הטלפון יהיה במצב חירום של התקשרות חזרה למשך <xliff:g id="COUNT_1">%s</xliff:g> דקות. בזמן שהטלפון במצב הזה, לא ניתן להשתמש באפליקציות הזקוקות לחיבור נתונים. האם ברצונך לצאת כעת?</item>
-      <item quantity="many">הטלפון יהיה במצב חירום של התקשרות חזרה למשך <xliff:g id="COUNT_1">%s</xliff:g> דקות. בזמן שהטלפון במצב הזה, לא ניתן להשתמש באפליקציות הזקוקות לחיבור נתונים. האם ברצונך לצאת כעת?</item>
-      <item quantity="other">הטלפון יהיה במצב חירום של התקשרות חזרה למשך <xliff:g id="COUNT_1">%s</xliff:g> דקות. בזמן שהטלפון במצב הזה, לא ניתן להשתמש באפליקציות הזקוקות לחיבור נתונים. האם ברצונך לצאת כעת?</item>
-      <item quantity="one">הטלפון יהיה במצב חירום של התקשרות חזרה למשך דקה <xliff:g id="COUNT_0">%s</xliff:g>. בזמן שהטלפון במצב הזה, לא ניתן להשתמש באפליקציות הזקוקות לחיבור נתונים. האם ברצונך לצאת כעת?</item>
+      <item quantity="two">הטלפון יהיה במצב חירום של התקשרות חזרה למשך <xliff:g id="COUNT_1">%s</xliff:g> דקות. בזמן שהטלפון במצב הזה, לא ניתן להשתמש באפליקציות הזקוקות לחבילת גלישה. האם ברצונך לצאת כעת?</item>
+      <item quantity="many">הטלפון יהיה במצב חירום של התקשרות חזרה למשך <xliff:g id="COUNT_1">%s</xliff:g> דקות. בזמן שהטלפון במצב הזה, לא ניתן להשתמש באפליקציות הזקוקות לחבילת גלישה. האם ברצונך לצאת כעת?</item>
+      <item quantity="other">הטלפון יהיה במצב חירום של התקשרות חזרה למשך <xliff:g id="COUNT_1">%s</xliff:g> דקות. בזמן שהטלפון במצב הזה, לא ניתן להשתמש באפליקציות הזקוקות לחבילת גלישה. האם ברצונך לצאת כעת?</item>
+      <item quantity="one">הטלפון יהיה במצב חירום של התקשרות חזרה למשך דקה <xliff:g id="COUNT_0">%s</xliff:g>. בזמן שהטלפון במצב הזה, לא ניתן להשתמש באפליקציות הזקוקות לחבילת גלישה. האם ברצונך לצאת כעת?</item>
     </plurals>
     <plurals name="alert_dialog_not_avaialble_in_ecm" formatted="false" msgid="1152682528741457004">
       <item quantity="two">הפעולה הנבחרת אינה זמינה במצב חירום של התקשרות חזרה. הטלפון יהיה במצב זה למשך <xliff:g id="COUNT_1">%s</xliff:g> דקות. האם ברצונך לצאת כעת?</item>
@@ -651,7 +652,7 @@
     <string name="progress_dialog_exiting_ecm" msgid="9159080081676927217">"יציאה ממצב התקשרות חזרה בחירום"</string>
     <string name="alert_dialog_yes" msgid="3532525979632841417">"כן"</string>
     <string name="alert_dialog_no" msgid="1075632654085988420">"לא"</string>
-    <string name="alert_dialog_dismiss" msgid="1336356286354517054">"סגור"</string>
+    <string name="alert_dialog_dismiss" msgid="1336356286354517054">"סגירה"</string>
     <string name="phone_in_ecm_call_notification_text_without_data_restriction_hint" msgid="3747860785153531225">"הטלפון במצב \'התקשרות בחזרה בחירום\'"</string>
     <string name="phone_in_ecm_notification_complete_time_without_data_restriction_hint" msgid="3690292264812050858">"עד <xliff:g id="COMPLETETIME">%s</xliff:g>"</string>
     <plurals name="alert_dialog_exit_ecm_without_data_restriction_hint" formatted="false" msgid="6477733043040328640">
@@ -666,10 +667,10 @@
     <string name="other_settings" msgid="8895088007393598447">"הגדרות שיחה אחרות"</string>
     <string name="calling_via_template" msgid="1791323450703751750">"שיחה באמצעות <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
     <string name="contactPhoto" msgid="7885089213135154834">"תמונה של איש קשר"</string>
-    <string name="goPrivate" msgid="4645108311382209551">"עבור לשיחה פרטית"</string>
-    <string name="selectContact" msgid="1527612842599767382">"בחר איש קשר"</string>
+    <string name="goPrivate" msgid="4645108311382209551">"מעבר לשיחה פרטית"</string>
+    <string name="selectContact" msgid="1527612842599767382">"בחירת איש קשר"</string>
     <string name="not_voice_capable" msgid="2819996734252084253">"חיוג קולי אינו נתמך"</string>
-    <string name="description_dial_button" msgid="8614631902795087259">"חייג"</string>
+    <string name="description_dial_button" msgid="8614631902795087259">"חויג"</string>
     <string name="description_dialpad_button" msgid="7395114120463883623">"הצגת לוח החיוג"</string>
     <string name="pane_title_emergency_dialpad" msgid="3627372514638694401">"לוח חיוג לחירום"</string>
     <string name="voicemail_visual_voicemail_switch_title" msgid="6610414098912832120">"דואר קולי ויזואלי"</string>
@@ -677,10 +678,10 @@
     <string name="voicemail_change_pin_dialog_title" msgid="4633077715231764435">"שינוי קוד הגישה"</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_title" msgid="7246600931634161830">"הפעלת שיחות וידאו"</string>
     <string name="enable_video_calling_dialog_msg" msgid="7141478720386203540">"‏כדי להפעיל שיחת וידאו, עליך להפעיל את \'מצב 4G LTE משופר\' ב\'הגדרות רשת\'."</string>
     <string name="enable_video_calling_dialog_settings" msgid="8697890611305307110">"הגדרות רשת"</string>
-    <string name="enable_video_calling_dialog_close" msgid="4298929725917045270">"סגור"</string>
+    <string name="enable_video_calling_dialog_close" msgid="4298929725917045270">"סגירה"</string>
     <string name="sim_label_emergency_calls" msgid="9078241989421522310">"שיחות חירום"</string>
     <string name="sim_description_emergency_calls" msgid="5146872803938897296">"שיחות חירום בלבד"</string>
     <string name="sim_description_default" msgid="7474671114363724971">"‏כרטיס SIM, חריץ: <xliff:g id="SLOT_ID">%s</xliff:g>"</string>
@@ -691,7 +692,7 @@
     <string name="message_decode_error" msgid="1061856591500290887">"אירעה שגיאה בעת פענוח ההודעה."</string>
     <string name="callFailed_cdma_activation" msgid="5392057031552253550">"‏כרטיס SIM הפעיל את השירות שלך ועדכן את יכולות הנדידה של הטלפון."</string>
     <string name="callFailed_cdma_call_limit" msgid="1074219746093031412">"יש יותר מדי שיחות פעילות. כדי להתחיל שיחה חדשה עליך לסיים או למזג חלק מהשיחות הפעילות."</string>
-    <string name="callFailed_imei_not_accepted" msgid="7257903653685147251">"‏לא ניתן להתחבר. הכנס כרטיס SIM תקין."</string>
+    <string name="callFailed_imei_not_accepted" msgid="7257903653685147251">"‏לא ניתן להתחבר. יש להכניס כרטיס SIM תקין."</string>
     <string name="callFailed_wifi_lost" msgid="1788036730589163141">"‏השיחה הסתיימה כי החיבור לרשת ה-Wi-Fi נותק."</string>
     <string name="dialFailed_low_battery" msgid="6857904237423407056">"אי אפשר לבצע את שיחת הווידאו מכיוון שהסוללה חלשה."</string>
     <string name="callFailed_low_battery" msgid="4056828320214416182">"שיחת הווידאו הסתיימה מכיוון שהסוללה חלשה."</string>
@@ -701,12 +702,12 @@
     <string name="change_pin_continue_label" msgid="5177011752453506371">"המשך"</string>
     <string name="change_pin_cancel_label" msgid="2301711566758827936">"ביטול"</string>
     <string name="change_pin_ok_label" msgid="6861082678817785330">"אישור"</string>
-    <string name="change_pin_enter_old_pin_header" msgid="853151335217594829">"אשר את קוד הגישה הישן"</string>
-    <string name="change_pin_enter_old_pin_hint" msgid="8801292976275169367">"הזן את קוד הגישה לדואר הקולי כדי להמשיך."</string>
-    <string name="change_pin_enter_new_pin_header" msgid="4739465616733486118">"הגדר קוד גישה חדש"</string>
+    <string name="change_pin_enter_old_pin_header" msgid="853151335217594829">"אישור קוד הגישה הישן"</string>
+    <string name="change_pin_enter_old_pin_hint" msgid="8801292976275169367">"יש להזין את קוד הגישה לדואר הקולי כדי להמשיך."</string>
+    <string name="change_pin_enter_new_pin_header" msgid="4739465616733486118">"הגדרת קוד גישה חדש"</string>
     <string name="change_pin_enter_new_pin_hint" msgid="2326038476516364210">"האורך של קוד הגישה חייב להיות <xliff:g id="MAX">%2$d</xliff:g>-<xliff:g id="MIN">%1$d</xliff:g> ספרות."</string>
-    <string name="change_pin_confirm_pin_header" msgid="2606303906320705726">"אשר את קוד הגישה"</string>
-    <string name="change_pin_confirm_pins_dont_match" msgid="305164501222587215">"קודי הגישה אינם תואמים"</string>
+    <string name="change_pin_confirm_pin_header" msgid="2606303906320705726">"אישור קוד הגישה"</string>
+    <string name="change_pin_confirm_pins_dont_match" msgid="305164501222587215">"קודי הגישה לא תואמים"</string>
     <string name="change_pin_succeeded" msgid="2504705600693014403">"קוד הגישה לדואר הקולי עודכן"</string>
     <string name="change_pin_system_error" msgid="7772788809875146873">"לא ניתן להגדיר את קוד הגישה"</string>
     <string name="mobile_data_status_roaming_turned_off_subtext" msgid="6840673347416227054">"חבילת הגלישה בנדידה הושבתה"</string>
@@ -905,7 +906,7 @@
     <string name="radio_info_data_network_type_label" msgid="8886597029237501929">"סוג רשת נתונים:"</string>
     <string name="phone_index_label" msgid="6222406512768964268">"בחירת אינדקס טלפון"</string>
     <string name="radio_info_set_perferred_label" msgid="7408131389363136210">"הגדרת סוג רשת מועדף:"</string>
-    <string name="radio_info_ping_hostname_v4" msgid="6951237885381284790">"‏נדנד לשם המארח (www.google.com) מסוג IPv4:"</string>
+    <string name="radio_info_ping_hostname_v4" msgid="6951237885381284790">"‏נדנוד לשם המארח (www.google.com) מסוג IPv4:"</string>
     <string name="radio_info_ping_hostname_v6" msgid="2748637889486554603">"‏נדנוד לשם המארח (www.google.com) מסוג IPv6:"</string>
     <string name="radio_info_http_client_test" msgid="1329583721088428238">"‏בדיקת לקוח HTTP:"</string>
     <string name="ping_test_label" msgid="448617502935719694">"הפעלת בדיקת פינג"</string>
@@ -920,10 +921,10 @@
     <string name="radio_info_nr_state" msgid="1337571996788535356">"‏מצב 5G NR:"</string>
     <string name="radio_info_nr_frequency" msgid="1201156032796584128">"‏תדירות 5G NR:"</string>
     <string name="band_mode_title" msgid="7988822920724576842">"הגדרת מצב תדרים של רדיו"</string>
-    <string name="band_mode_loading" msgid="795923726636735967">"טוען רשימת תדרים…"</string>
+    <string name="band_mode_loading" msgid="795923726636735967">"הטעינה של רשימת התדרים מתבצעת…"</string>
     <string name="band_mode_set" msgid="6657819412803771421">"הגדרה"</string>
     <string name="band_mode_failed" msgid="1707488541847192924">"נכשל"</string>
-    <string name="band_mode_succeeded" msgid="2230018000534761063">"עבר בהצלחה"</string>
+    <string name="band_mode_succeeded" msgid="2230018000534761063">"המעבר הצליח"</string>
     <string name="phone_info_label" product="tablet" msgid="7477478709388477397">"פרטי טאבלט"</string>
     <string name="phone_info_label" product="default" msgid="1784175881556791433">"פרטי טלפון"</string>
     <string name="carrier_provisioning" msgid="2668065041869578376">"פרטי ניהול תצורה של ספק סלולרי"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index ad85ba6..2a98036 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"パスワードが正しくありません。SIMはロックされました。PUK2を入力してください。"</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2は完全にブロックされています。"</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"入力できるのはあと<xliff:g id="NUMBER">%d</xliff:g>回です。"</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 でロックされています。ロックを解除するには、サービス プロバイダにお問い合わせください。"</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2はブロックされなくなりました"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"ネットワークまたはSIMカードのエラー"</string>
     <string name="doneButton" msgid="7371209609238460207">"完了"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 21a17ea..d37e85b 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"პაროლი არასწორია. SIM ახლა დაბლოკილია. შეიყვანეთ PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 სამუდამოდ დაიბლოკა."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n" თქვენ გაქვთ <xliff:g id="NUMBER">%d</xliff:g> დარჩენილი მცდელობა."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 ჩაკეტილია. განსაბლოკად დაუკავშირდით სერვისის პროვაიდერს."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 აღარ არის დაბლოკილი"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"ქსელის ან SIM ბარათის შეცდომა"</string>
     <string name="doneButton" msgid="7371209609238460207">"დასრულდა"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 3360d56..9122726 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Құпия сөз дұрыс емес. SIM қазір бекітілген. PUK2 кодын енгізіңіз."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 уақытша бөгелген."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"<xliff:g id="NUMBER">%d</xliff:g> әрекет қалды."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 құлыптаулы. Құлпын ашу үшін қызмет көрсетушіге хабарласыңыз."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 енді бөгелмеген"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Желі немесе SIM картасының қатесі"</string>
     <string name="doneButton" msgid="7371209609238460207">"Дайын"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 9386b65..b0fad81 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"ពាក្យសម្ងាត់មិនត្រឹមត្រូវ។ ឥឡូវនេះស៊ីមកាតត្រូវបានចាក់សោ។ បញ្ចូល PUK2។"</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"លេខ​កូដ PUK2 ត្រូវ​បាន​​ទប់ស្កាត់​ជា​អចិន្ត្រៃយ៍។"</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"អ្នកនៅសល់ការព្យាយាមបញ្ចូល <xliff:g id="NUMBER">%d</xliff:g> ដងទៀត។"</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"បាន​ចាក់​សោ​ដោយ​ប្រើ PUK2។ សូម​ទាក់ទង​ទៅ​ក្រុមហ៊ុនផ្ដល់សេវា ដើម្បី​ដោះ​សោ។"</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"លេខសម្ងាត់ PIN2 មិនត្រូវបានរារាំងទៀតទេ"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"បញ្ហាស៊ីមកាត ឬបណ្ដាញ។"</string>
     <string name="doneButton" msgid="7371209609238460207">"រួចរាល់"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 9492581..a12b794 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"ಪಾಸ್‌ವರ್ಡ್ ತಪ್ಪಾಗಿದೆ. SIM ಅನ್ನು ಇದೀಗ ಲಾಕ್ ಮಾಡಲಾಗಿದೆ. PUK2 ನಮೂದಿಸಿ."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 ಅನ್ನು ಶಾಶ್ವತವಾಗಿ ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾಕಿ ಉಳಿದಿರುವ ಪ್ರಯತ್ನಗಳನ್ನು ಹೊಂದಿರುವಿರಿ."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 ಲಾಕ್ ಆಗಿದೆ. ಅನ್‌ಲಾಕ್ ಮಾಡಲು ಸೇವೆ ಒದಗಿಸುವವರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 ಇನ್ನು ಮುಂದೆ ನಿರ್ಬಂಧಿತವಾಗಿರುವುದಿಲ್ಲ"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"ನೆಟ್‌ವರ್ಕ್‌ ಅಥವಾ ಸಿಮ್ ಕಾರ್ಡ್‌ ದೋಷ"</string>
     <string name="doneButton" msgid="7371209609238460207">"ಮುಗಿದಿದೆ"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 588d187..63bb926 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"비밀번호가 잘못되어 SIM이 잠겼습니다. PUK2를 입력하세요."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2가 완전히 차단되었습니다."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"<xliff:g id="NUMBER">%d</xliff:g>번의 기회가 남았습니다."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2로 잠금 설정되었습니다. 모든 통신사에서 사용할 수 있도록 하려면 서비스 제공업체에 문의하세요."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 차단이 해제되었습니다."</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"네트워크 또는 SIM 카드 오류"</string>
     <string name="doneButton" msgid="7371209609238460207">"완료"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 68fbf51..a6c691c 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Сырсөз туура эмес. SIM азыр кулпуланды. PUK2 киргизиңиз."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 биротоло бөгөттөлдү."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Сизде <xliff:g id="NUMBER">%d</xliff:g> аракет калды."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 кулпуланды. Кулпуну ачуу үчүн оператор менен байланышыңыз."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"Мындан ары PIN2 бөгөттөлбөйт"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Тармак же SIM карта катасы"</string>
     <string name="doneButton" msgid="7371209609238460207">"Даяр"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index a9e56fa..0fc3dfd 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"ລະ​ຫັດ​ຜ່ານ​ບໍ່​ຖືກ​ຕ້ອງ​. SIM ຖືກ​ລັອກ​ແລ້ວ​ດຽວ​ນີ້​. ປ້ອນ PUK2 ເຂົ້າ​ໄປ​."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 ຖືກບລັອກຢ່າງຖາວອນແລ້ວ."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"ທ່ານ​ຍັງ​ພະ​ຍາ​ຍາມ​ໄດ້​ອີກ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"ລັອກ PUK2 ແລ້ວ. ຕິດຕໍ່ຜູ້ໃຫ້ບໍລິການເພື່ອປົດລັອກ."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 ບໍ່​ຖືກ​ບ​ລັອກ​ອີກ"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"ເຄືອຂ່າຍ ຫຼື SIM card ຜິດພາດ"</string>
     <string name="doneButton" msgid="7371209609238460207">"ແລ້ວໆ"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 20f24eb..07fbc2e 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Netinkamas slaptažodis. SIM kortelė užrakinta. Įveskite PUK2 kodą."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 kodas visam laikui užblokuotas."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Liko <xliff:g id="NUMBER">%d</xliff:g> bandym."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 užrakintas. Kreipkitės į paslaugos teikėją, kad atrakintų."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 kodas atblokuotas"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Tinklo ar SIM kortelės klaida"</string>
     <string name="doneButton" msgid="7371209609238460207">"Atlikta"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 8bf7174..eca2653 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Parole nav pareiza. SIM bloķēta. Ievadiet PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 kods ir neatgriezeniski bloķēts."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Jums atlikuši <xliff:g id="NUMBER">%d</xliff:g> mēģinājumi."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 ir bloķēts. Lai atbloķētu, sazinieties ar pakalpojuma sniedzēju."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 vairs nav bloķēts"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Tīkla vai SIM kartes kļūda"</string>
     <string name="doneButton" msgid="7371209609238460207">"Gatavs"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index e8cd6ae..fb5b630 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Лозинката е неточна. SIM-картичката е сега заклучена. Внесете го ПУК2-кодот."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"ПУК2 кодот е трајно блокиран."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Имате уште <xliff:g id="NUMBER">%d</xliff:g> обиди."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2-кодот е заклучен. Контактирајте со операторот за отклучување."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2-кодот веќе не е блокиран"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Грешка со мрежа или SIM картичка"</string>
     <string name="doneButton" msgid="7371209609238460207">"Готово"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 0cbb2fc..4f9b5ee 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"പാസ്‌വേഡ് തെറ്റാണ്. SIM ഇപ്പോൾ ലോക്കുചെയ്‌തിരിക്കുന്നു. PUK2 നൽകുക."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 ശാശ്വതമായി തടഞ്ഞിരിക്കുന്നു."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"നിങ്ങൾക്ക് <xliff:g id="NUMBER">%d</xliff:g> ശ്രമങ്ങൾ ശേഷിക്കുന്നു."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 ലോക്ക് ആണ്. അൺലോക്ക് ചെയ്യാൻ സേവന ദാതാവിനെ ബന്ധപ്പെടുക."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 ഇനി തടയില്ല"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"നെറ്റ്‌വർക്ക് അല്ലെങ്കിൽ സിം കാർഡ് പിശക്"</string>
     <string name="doneButton" msgid="7371209609238460207">"പൂർത്തിയായി"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index fe57247..d54d35d 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -49,7 +49,7 @@
     <string name="add_vm_number_str" msgid="7368168964435881637">"Дугаар нэмэх"</string>
     <string name="voice_number_setting_primary_user_only" msgid="3394706575741912843">"Дуут шуудангийн тохиргоог зөвхөн Үндсэн хэрэглэгч өөрчлөх боломжтой."</string>
     <string name="puk_unlocked" msgid="4627340655215746511">"Таны SIM карт тайлагдлаа. Таны утас тайлагдаж байна…"</string>
-    <string name="label_ndp" msgid="7617392683877410341">"SIM сүлжээ тайлах PIN"</string>
+    <string name="label_ndp" msgid="7617392683877410341">"SIM сүлжээ тайлах ПИН"</string>
     <string name="label_phoneid" msgid="8775611434123577808">"Операторын SIM түгжигдсэн"</string>
     <string name="sim_ndp_unlock_text" msgid="7737338355451978338">"Тайлах"</string>
     <string name="sim_ndp_dismiss_text" msgid="89667342248929777">"Алгасах"</string>
@@ -162,15 +162,15 @@
     <string name="no_change" msgid="3737264882821031892">"Ямар ч өөрчлөлт хийгдсэнгүй."</string>
     <string name="sum_voicemail_choose_provider" msgid="6750824719081403773">"Дуут шуудангийн үйлчилгээг сонгох"</string>
     <string name="voicemail_default" msgid="6427575113775462077">"Таны оператор компани"</string>
-    <string name="vm_change_pin_old_pin" msgid="7154951790929009241">"Хуучин PIN"</string>
-    <string name="vm_change_pin_new_pin" msgid="2656200418481288069">"Шинэ PIN"</string>
+    <string name="vm_change_pin_old_pin" msgid="7154951790929009241">"Хуучин ПИН"</string>
+    <string name="vm_change_pin_new_pin" msgid="2656200418481288069">"Шинэ ПИН"</string>
     <string name="vm_change_pin_progress_message" msgid="626015184502739044">"Түр хүлээнэ үү."</string>
-    <string name="vm_change_pin_error_too_short" msgid="1789139338449945483">"Шинэ PIN хэт богино байна."</string>
-    <string name="vm_change_pin_error_too_long" msgid="3634907034310018954">"Шинэ PIN хэт урт байна."</string>
-    <string name="vm_change_pin_error_too_weak" msgid="8581892952627885719">"Шинэ PIN хэт амархан байна. Сайн нууц үгэнд үргэлжилсэн дараалал буюу давтагдсан цифр ордоггүй."</string>
-    <string name="vm_change_pin_error_mismatch" msgid="5364847280026257331">"Хуучин PIN таарахгүй байна."</string>
-    <string name="vm_change_pin_error_invalid" msgid="5230002671175580674">"Шинэ PIN-д буруу тэмдэгт агуулагдаж байна."</string>
-    <string name="vm_change_pin_error_system_error" msgid="9116483527909681791">"PIN-г өөрчлөх боломжгүй"</string>
+    <string name="vm_change_pin_error_too_short" msgid="1789139338449945483">"Шинэ ПИН хэт богино байна."</string>
+    <string name="vm_change_pin_error_too_long" msgid="3634907034310018954">"Шинэ ПИН хэт урт байна."</string>
+    <string name="vm_change_pin_error_too_weak" msgid="8581892952627885719">"Шинэ ПИН хэт амархан байна. Сайн нууц үгэнд үргэлжилсэн дараалал буюу давтагдсан цифр ордоггүй."</string>
+    <string name="vm_change_pin_error_mismatch" msgid="5364847280026257331">"Хуучин ПИН таарахгүй байна."</string>
+    <string name="vm_change_pin_error_invalid" msgid="5230002671175580674">"Шинэ ПИН-д буруу тэмдэгт агуулагдаж байна."</string>
+    <string name="vm_change_pin_error_system_error" msgid="9116483527909681791">"ПИН-г өөрчлөх боломжгүй"</string>
     <string name="vvm_unsupported_message_format" msgid="4206402558577739713">"Дэмжигдээгүй мессежийн төрөл, сонсохын тулд <xliff:g id="NUMBER">%s</xliff:g> руу залгана уу."</string>
     <string name="network_settings_title" msgid="7560807107123171541">"Мобайл сүлжээ"</string>
     <string name="label_available" msgid="1316084116670821258">"Боломжтой сүлжээнүүд"</string>
@@ -449,7 +449,7 @@
     <string name="enable_fdn_ok" msgid="5080925177369329827">"FDN идэвхгүйжүүлэх"</string>
     <string name="disable_fdn_ok" msgid="3745475926874838676">"FDN-г идэвхжүүлэх"</string>
     <string name="sum_fdn" msgid="6152246141642323582">"Тогтсон залгах дугааруудыг удирдах"</string>
-    <string name="sum_fdn_change_pin" msgid="3510994280557335727">"FDN хандалтын PIN-г өөрчлөх"</string>
+    <string name="sum_fdn_change_pin" msgid="3510994280557335727">"FDN хандалтын ПИН-г өөрчлөх"</string>
     <string name="sum_fdn_manage_list" msgid="3311397063233992907">"Утасны дугаарын жагсаалтыг удирдах"</string>
     <string name="voice_privacy" msgid="7346935172372181951">"Дууны нууцлал"</string>
     <string name="voice_privacy_summary" msgid="3556460926168473346">"Сайжруулсан нууцлалын төлвийг идэвхжүүлэх"</string>
@@ -475,7 +475,7 @@
     <string name="delete_fdn_contact" msgid="7027405651994507077">"Тогтвортой залгах дугаарыг устгах"</string>
     <string name="deleting_fdn_contact" msgid="6872320570844460428">"Тогтвортой залгах дугаарыг устгаж байна…"</string>
     <string name="fdn_contact_deleted" msgid="1680714996763848838">"Тогтвортой залгах дугаарыг устгав."</string>
-    <string name="pin2_invalid" msgid="2313954262684494442">"Та буруу PIN оруулсан учир FDN шинэчлэгдсэнгүй."</string>
+    <string name="pin2_invalid" msgid="2313954262684494442">"Та буруу ПИН оруулсан учир FDN шинэчлэгдсэнгүй."</string>
     <string name="fdn_invalid_number" msgid="9067189814657840439">"Дугаар <xliff:g id="FDN_NUMBER_LIMIT_LENGTH">%d</xliff:g> цифрээс хэтэрсэн тул FDN-г шинэчлээгүй."</string>
     <string name="pin2_or_fdn_invalid" msgid="7542639487955868181">"FDN шинэчлэгдсэнгүй. PIN2 буруу байсан, эсхүл утасны дугаар зөвшөөрөгдсөнгүй."</string>
     <string name="fdn_failed" msgid="216592346853420250">"ФДН ажиллуулах амжилтгүй."</string>
@@ -483,23 +483,23 @@
     <string name="simContacts_empty" msgid="1135632055473689521">"Таны SIM картанд харилцагчид байхгүй байна."</string>
     <string name="simContacts_title" msgid="2714029230160136647">"Оруулах харилцагчдыг сонгоно уу"</string>
     <string name="simContacts_airplaneMode" msgid="4654884030631503808">"SIM картнаас дугаар импортлохын тулд онгоцны горимыг унтраа"</string>
-    <string name="enable_pin" msgid="967674051730845376">"SIM PIN Идэвхжүүлэх/идэвхгүйжүүлэх"</string>
-    <string name="change_pin" msgid="3657869530942905790">"SIM PIN өөрчлөх"</string>
-    <string name="enter_pin_text" msgid="3182311451978663356">"SIM PIN:"</string>
-    <string name="oldPinLabel" msgid="8618515202411987721">"Хуучин PIN"</string>
-    <string name="newPinLabel" msgid="3585899083055354732">"Шинэ PIN"</string>
-    <string name="confirmPinLabel" msgid="7783531218662473778">"Шинэ PIN-г баталгаажуулах"</string>
-    <string name="badPin" msgid="4549286285015892321">"Таны оруулсан хуучин PIN буруу байна. Дахин оролдоно уу."</string>
-    <string name="mismatchPin" msgid="1467254768290323845">"Таны оруулсан PIN таарахгүй байна. Дахин оролдоно уу."</string>
-    <string name="invalidPin" msgid="7363723429414001979">"4-с 8 цифртэй PIN оруулна уу"</string>
-    <string name="disable_sim_pin" msgid="3112303905548613752">"SIM-ний PIN-г цэвэрлэх"</string>
+    <string name="enable_pin" msgid="967674051730845376">"SIM ПИН Идэвхжүүлэх/идэвхгүйжүүлэх"</string>
+    <string name="change_pin" msgid="3657869530942905790">"SIM ПИН өөрчлөх"</string>
+    <string name="enter_pin_text" msgid="3182311451978663356">"SIM ПИН:"</string>
+    <string name="oldPinLabel" msgid="8618515202411987721">"Хуучин ПИН"</string>
+    <string name="newPinLabel" msgid="3585899083055354732">"Шинэ ПИН"</string>
+    <string name="confirmPinLabel" msgid="7783531218662473778">"Шинэ ПИН-г баталгаажуулах"</string>
+    <string name="badPin" msgid="4549286285015892321">"Таны оруулсан хуучин ПИН буруу байна. Дахин оролдоно уу."</string>
+    <string name="mismatchPin" msgid="1467254768290323845">"Таны оруулсан ПИН таарахгүй байна. Дахин оролдоно уу."</string>
+    <string name="invalidPin" msgid="7363723429414001979">"4-с 8 цифртэй ПИН оруулна уу"</string>
+    <string name="disable_sim_pin" msgid="3112303905548613752">"SIM-ний ПИН-г цэвэрлэх"</string>
     <string name="enable_sim_pin" msgid="445461050748318980">"SIM-ний ПИН-г тохируулах"</string>
     <string name="enable_in_progress" msgid="4135305985717272592">"ПИН-г тохируулж байна..."</string>
-    <string name="enable_pin_ok" msgid="2877428038280804256">"PIN-г тохирууллаа"</string>
-    <string name="disable_pin_ok" msgid="888505244389647754">"PIN цэвэрлэгдсэн"</string>
-    <string name="pin_failed" msgid="4527347792881939652">"PIN буруу байна"</string>
-    <string name="pin_changed" msgid="7291153750090452808">"PIN шинэчлэгдсэн"</string>
-    <string name="puk_requested" msgid="2061337960609806851">"Нууц үг буруу байна. PIN код одоо түгжигдсэн. PUK кодыг авах хүсэлт тавигдсан."</string>
+    <string name="enable_pin_ok" msgid="2877428038280804256">"ПИН-г тохирууллаа"</string>
+    <string name="disable_pin_ok" msgid="888505244389647754">"ПИН цэвэрлэгдсэн"</string>
+    <string name="pin_failed" msgid="4527347792881939652">"ПИН буруу байна"</string>
+    <string name="pin_changed" msgid="7291153750090452808">"ПИН шинэчлэгдсэн"</string>
+    <string name="puk_requested" msgid="2061337960609806851">"Нууц үг буруу байна. ПИН код одоо түгжигдсэн. PUK кодыг авах хүсэлт тавигдсан."</string>
     <string name="enter_pin2_text" msgid="7266379426804295979">"PIN2"</string>
     <string name="oldPin2Label" msgid="4648543187859997203">"Хуучин PIN2"</string>
     <string name="newPin2Label" msgid="1840905981784453939">"Шинэ PIN2"</string>
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Нууц үг буруу байна. SIM карт одоо түгжигдсэн. PUK2 кодыг оруулна уу."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"ПҮК2 бүрмөсөн түгжигдсэн."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Танд <xliff:g id="NUMBER">%d</xliff:g> оролдлого үлдлээ."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2-г түгжсэн. Түгжээг тайлахын тулд үйлчилгээ үзүүлэгчтэй холбогдоно уу."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 түгжээгүй болсон"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Сүлжээ болон SIM картын алдаа"</string>
     <string name="doneButton" msgid="7371209609238460207">"Дууссан"</string>
@@ -667,8 +668,8 @@
     <string name="description_dialpad_button" msgid="7395114120463883623">"дугаар цуглуулах самбарыг харуулах"</string>
     <string name="pane_title_emergency_dialpad" msgid="3627372514638694401">"Яаралтай тусламжийн дугаар цуглуулах самбар"</string>
     <string name="voicemail_visual_voicemail_switch_title" msgid="6610414098912832120">"Визуал дуут шуудан"</string>
-    <string name="voicemail_set_pin_dialog_title" msgid="7005128605986960003">"PIN тохируулах"</string>
-    <string name="voicemail_change_pin_dialog_title" msgid="4633077715231764435">"PIN өөрчлөх"</string>
+    <string name="voicemail_set_pin_dialog_title" msgid="7005128605986960003">"ПИН тохируулах"</string>
+    <string name="voicemail_change_pin_dialog_title" msgid="4633077715231764435">"ПИН өөрчлөх"</string>
     <string name="preference_category_ringtone" msgid="8787281191375434976">"Хонхны ая &amp; Чичиргээ"</string>
     <string name="pstn_connection_service_label" msgid="9200102709997537069">"Суурилагдсан SIM карт"</string>
     <string name="enable_video_calling_title" msgid="7246600931634161830">"Видео дуудлагыг идэвхжүүлэх"</string>
@@ -691,18 +692,18 @@
     <string name="callFailed_low_battery" msgid="4056828320214416182">"Цэнэг бага байгаа тул видео дуудлагыг дуусгасан."</string>
     <string name="callFailed_emergency_call_over_wfc_not_available" msgid="5944309590693432042">"Энэ байрлалд Wi-Fi дуудлагаар яаралтай дуудлага хийх боломжгүй."</string>
     <string name="callFailed_wfc_service_not_available_in_this_location" msgid="3624536608369524988">"Энэ байрлалд Wi-Fi дуудлага хийх боломжгүй байна."</string>
-    <string name="change_pin_title" msgid="3564254326626797321">"Дуут шуудангийн PIN-г өөрчлөх"</string>
+    <string name="change_pin_title" msgid="3564254326626797321">"Дуут шуудангийн ПИН-г өөрчлөх"</string>
     <string name="change_pin_continue_label" msgid="5177011752453506371">"Үргэлжлүүлэх"</string>
     <string name="change_pin_cancel_label" msgid="2301711566758827936">"Цуцлах"</string>
     <string name="change_pin_ok_label" msgid="6861082678817785330">"OK"</string>
-    <string name="change_pin_enter_old_pin_header" msgid="853151335217594829">"Хуучин PIN-ээ баталгаажуулна уу"</string>
-    <string name="change_pin_enter_old_pin_hint" msgid="8801292976275169367">"Үргэлжлүүлэхийн тулд дуут шуудангийн PIN оруулна уу."</string>
-    <string name="change_pin_enter_new_pin_header" msgid="4739465616733486118">"Шинэ PIN тохируулах"</string>
-    <string name="change_pin_enter_new_pin_hint" msgid="2326038476516364210">"PIN <xliff:g id="MIN">%1$d</xliff:g> - <xliff:g id="MAX">%2$d</xliff:g> цифртэй байх ёстой."</string>
-    <string name="change_pin_confirm_pin_header" msgid="2606303906320705726">"PIN кодоо баталгаажуулна уу"</string>
-    <string name="change_pin_confirm_pins_dont_match" msgid="305164501222587215">"PIN код таарахгүй байна"</string>
-    <string name="change_pin_succeeded" msgid="2504705600693014403">"Дуут шуудангийн PIN шинэчлэгдсэн"</string>
-    <string name="change_pin_system_error" msgid="7772788809875146873">"PIN тохируулах боломжгүй"</string>
+    <string name="change_pin_enter_old_pin_header" msgid="853151335217594829">"Хуучин ПИН-ээ баталгаажуулна уу"</string>
+    <string name="change_pin_enter_old_pin_hint" msgid="8801292976275169367">"Үргэлжлүүлэхийн тулд дуут шуудангийн ПИН оруулна уу."</string>
+    <string name="change_pin_enter_new_pin_header" msgid="4739465616733486118">"Шинэ ПИН тохируулах"</string>
+    <string name="change_pin_enter_new_pin_hint" msgid="2326038476516364210">"ПИН <xliff:g id="MIN">%1$d</xliff:g> - <xliff:g id="MAX">%2$d</xliff:g> цифртэй байх ёстой."</string>
+    <string name="change_pin_confirm_pin_header" msgid="2606303906320705726">"ПИН кодоо баталгаажуулна уу"</string>
+    <string name="change_pin_confirm_pins_dont_match" msgid="305164501222587215">"ПИН код таарахгүй байна"</string>
+    <string name="change_pin_succeeded" msgid="2504705600693014403">"Дуут шуудангийн ПИН шинэчлэгдсэн"</string>
+    <string name="change_pin_system_error" msgid="7772788809875146873">"ПИН тохируулах боломжгүй"</string>
     <string name="mobile_data_status_roaming_turned_off_subtext" msgid="6840673347416227054">"Дата роумингийг идэвхгүй болгосон"</string>
     <string name="mobile_data_status_roaming_turned_on_subtext" msgid="5615757897768777865">"Дата роумингийг асаасан"</string>
     <string name="mobile_data_status_roaming_without_plan_subtext" msgid="6536671968072284677">"Одоо роумингтэй байна, дата багц шаардлагатай"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index f3b7479..8a99cc6 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"पासवर्ड चुकीचा आहे. सिम आता लॉक केले आहे. PUK2 प्रविष्‍ट करा."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 कायमचे अवरोधित केले आहे."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"आपल्‍याकडे <xliff:g id="NUMBER">%d</xliff:g> शिल्लक प्रयत्न आहेत."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 द्वारे लॉक केले आहे. ते अनलॉक करण्यासाठी सेवा पुरवठादाराशी संपर्क साधा."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"पिन2 अवरोधित केला नाही"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"नेटवर्क किंवा सिम कार्ड एरर"</string>
     <string name="doneButton" msgid="7371209609238460207">"पूर्ण झाले"</string>
@@ -522,7 +523,7 @@
     <string name="card_title_dialing" msgid="8742182654254431781">"डायल करत आहे"</string>
     <string name="card_title_redialing" msgid="18130232613559964">"रीडायल करत आहे"</string>
     <string name="card_title_conf_call" msgid="901197309274457427">"कॉंफरन्स कॉल"</string>
-    <string name="card_title_incoming_call" msgid="881424648458792430">"येणारे कॉल"</string>
+    <string name="card_title_incoming_call" msgid="881424648458792430">"इनकमिंग कॉल"</string>
     <string name="card_title_call_ended" msgid="650223980095026340">"कॉल संपला"</string>
     <string name="card_title_on_hold" msgid="9028319436626975207">"होल्ड वर"</string>
     <string name="card_title_hanging_up" msgid="814874106866647871">"हँग अप करणेे"</string>
@@ -783,8 +784,8 @@
     <string name="call_barring_baoicr_enabled" msgid="1615324165512798478">"जाणारे इंटरनॅशनल रोमिंग ब्लॉक करणे बंद करायचे का?"</string>
     <string name="call_barring_baoicr_disabled" msgid="172010175248142831">"जाणारे इंटरनॅशनल रोमिंग ब्लॉक करायचे का?"</string>
     <string name="call_barring_baic" msgid="7941393541678658566">"सर्व येणारे"</string>
-    <string name="call_barring_baic_enabled" msgid="4357332358020337470">"सर्व येणारे कॉल ब्लॉक करणे बंद करायचे का?"</string>
-    <string name="call_barring_baic_disabled" msgid="2355945245938240958">"सर्व येणारे कॉल ब्लॉक करायचे का?"</string>
+    <string name="call_barring_baic_enabled" msgid="4357332358020337470">"सर्व इनकमिंग कॉल ब्लॉक करणे बंद करायचे का?"</string>
+    <string name="call_barring_baic_disabled" msgid="2355945245938240958">"सर्व इनकमिंग कॉल ब्लॉक करायचे का?"</string>
     <string name="call_barring_baicr" msgid="8712249337313034226">"येणारे इंटरनॅशनल रोमिंग"</string>
     <string name="call_barring_baicr_enabled" msgid="64774270234828175">"सर्व येणारे इंटरनॅशनल रोमिंग ब्लॉक करणे बंद करायचे का?"</string>
     <string name="call_barring_baicr_disabled" msgid="3488129262744027262">"येणारे इंटरनॅशनल रोमिंग ब्लॉक करायचे का?"</string>
@@ -809,7 +810,7 @@
     <string name="supp_service_notification_call_waiting" msgid="4577403881609445324">"कॉल प्रतीक्षेत आहे."</string>
     <string name="supp_service_clir_suppression_rejected" msgid="6105737020194776121">"क्रमांक ब्‍लॉक करणे रद्द केले."</string>
     <string name="supp_service_closed_user_group_call" msgid="2811636666505250689">"बंद वापरकर्ता गट कॉल."</string>
-    <string name="supp_service_incoming_calls_barred" msgid="2034627421274447674">"येणारे कॉल अवरोधित केले."</string>
+    <string name="supp_service_incoming_calls_barred" msgid="2034627421274447674">"इनकमिंग कॉल अवरोधित केले."</string>
     <string name="supp_service_outgoing_calls_barred" msgid="5205725332394087112">"जाणारे कॉल अवरोधित केले."</string>
     <string name="supp_service_call_forwarding_active" msgid="7910162960395132464">"कॉल फॉरवर्ड होत आहे."</string>
     <string name="supp_service_additional_call_forwarded" msgid="8772753260008398632">"अतिरिक्‍त कॉल फॉरवर्ड केला."</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 3c15edc..9236de2 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Kata laluan tidak betul. SIM kini dikunci. Masukkan PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 disekat secara kekal."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Anda mempunyai <xliff:g id="NUMBER">%d</xliff:g> percubaan lagi."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 dikunci. Hubungi penyedia perkhidmatan untuk membuka kunci."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 tidak disekat lagi"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Ralat rangkaian atau kad SIM"</string>
     <string name="doneButton" msgid="7371209609238460207">"Selesai"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 1ce4ba2..4cf2c76 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"လျှို့ဝှက်စကားလုံး မမှန်ကန်ပါ။ SIM ယခုသော့ခတ်လိုက်ပါပြီ။ PUK2 ရိုက်ထည့်ပါ။"</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 ကို ထာ၀ရ ပိတ်ထားပါသည်"</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"သင့်တွင် လက်ကျန် ကြိုးစားခွင့် <xliff:g id="NUMBER">%d</xliff:g> ရှိသည်။"</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 လော့ခ်ချထားသည်။ ဖွင့်ရန် ဝန်ဆောင်မှုပေးသူကို ဆက်သွယ်ပါ။"</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"ပင်နံပါတ်2 အား အဆက်မဖြတ်တော့ပါ။"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"ကွန်ရက် သို့မဟုတ် ဆင်းမ်ကဒ်မှားယွင်းမှု"</string>
     <string name="doneButton" msgid="7371209609238460207">"ပြီးပါပြီ"</string>
@@ -771,7 +772,7 @@
     <string name="clh_callFailed_protocol_Error_unspecified_txt" msgid="9203320572562697755">"ခေါ်ဆိုမှုကို မပြုလုပ်နိုင်ပါ။ အမှားကုဒ် ၁၁၁။"</string>
     <string name="clh_callFailed_interworking_unspecified_txt" msgid="7969686413930847182">"ခေါ်ဆိုမှုကို မပြုလုပ်နိုင်ပါ။ အမှားကုဒ် ၁၂၇။"</string>
     <string name="labelCallBarring" msgid="4180377113052853173">"ခေါ်ဆိုမှုကို ပိတ်ပင်ရန်"</string>
-    <string name="sum_call_barring_enabled" msgid="5184331188926370824">"ဖွင့်ထားသည်"</string>
+    <string name="sum_call_barring_enabled" msgid="5184331188926370824">"ဖွင့်"</string>
     <string name="sum_call_barring_disabled" msgid="5699448000600153096">"ပိတ်ထားသည်"</string>
     <string name="call_barring_baoc" msgid="7400892586336429326">"အထွက်ခေါ်ဆိုမှုအားလုံး"</string>
     <string name="call_barring_baoc_enabled" msgid="3131509193386668182">"အထွက်ခေါ်ဆိုမှုအားလုံး ပိတ်ထားခြင်းကို ပယ်ဖျက်မလား။"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index ed2959c..0db6b75 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Passordet er feil. PIN-koden er nå blokkert. Skriv inn en PUK2-kode."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 er permanent sperret."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Du har <xliff:g id="NUMBER">%d</xliff:g> forsøk igjen."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2-låst. Kontakt tjenesteleverandøren for å låse opp."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2-koden er ikke lenger blokkert"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Feil på nettverket eller SIM-kortet"</string>
     <string name="doneButton" msgid="7371209609238460207">"Ferdig"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 72c3daf..bbc33e8 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -96,7 +96,7 @@
     <string name="sum_loading_settings" msgid="434063780286688775">"सेटिङहरू लोड हुँदै..."</string>
     <string name="sum_hide_caller_id" msgid="131100328602371933">"बहिर्गमन कलहरूमा नम्बर लुकाइएको"</string>
     <string name="sum_show_caller_id" msgid="3571854755324664591">"बहिर्गमन कलहरूमा प्रदर्शित नम्बर"</string>
-    <string name="sum_default_caller_id" msgid="1767070797135682959">"बहिर्गमन कलमा मेरो नम्बर देखाउन पूर्वनिर्धारित अपरेटर सेटिङहरू प्रयोग गर्नुहोस्"</string>
+    <string name="sum_default_caller_id" msgid="1767070797135682959">"बहिर्गमन कलमा मेरो नम्बर देखाउन डिफल्ट अपरेटर सेटिङहरू प्रयोग गर्नुहोस्"</string>
     <string name="labelCW" msgid="8449327023861428622">"कल प्रतीक्षा गर्दै"</string>
     <string name="sum_cw_enabled" msgid="3977308526187139996">"कल गरेको बखत मलाई आगमन कलको जानकारी गराउनुहोस्"</string>
     <string name="sum_cw_disabled" msgid="3658094589461768637">"कल गरेको बेलामा आगमन कलहरूको बारेमा मलाई जानकारी गराउनुहोस्"</string>
@@ -151,7 +151,7 @@
     <string name="disable" msgid="1122698860799462116">"निस्कृय पार्नुहोस्"</string>
     <string name="change_num" msgid="6982164494063109334">"अपडेट गर्नुहोस्"</string>
   <string-array name="clir_display_values">
-    <item msgid="8477364191403806960">"नेटवर्क पूर्वनिर्धारित"</item>
+    <item msgid="8477364191403806960">"नेटवर्क डिफल्ट"</item>
     <item msgid="6813323051965618926">"सङ्ख्या लुकाउनुहोस्"</item>
     <item msgid="9150034130629852635">"सङ्ख्या देखाउनुहोस्"</item>
   </string-array>
@@ -295,7 +295,7 @@
     <string name="limited_sim_function_with_phone_num_notification_message" msgid="5928988883403677610">"<xliff:g id="PHONE_NUMBER">%2$s</xliff:g>.प्रयोग गर्दा <xliff:g id="CARRIER_NAME">%1$s</xliff:g> का कल तथा डेटा सेवाहरूलाई रोक लगाइन सक्छ"</string>
     <string name="limited_sim_function_notification_message" msgid="5338638075496721160">"अर्को SIM प्रयोग गर्दा <xliff:g id="CARRIER_NAME">%1$s</xliff:g> कल तथा डेटा सेवहरूलाई रोक लगाइन सक्छ।"</string>
     <string name="sip_accounts_removed_notification_title" msgid="3528076957535736095">"चल्तीबाट हटाइएका SIP खाताहरू भेट्टाइयो र हटाइयो"</string>
-    <string name="sip_accounts_removed_notification_message" msgid="1916856744869791592">"अबदेखि Android प्लेटफर्ममा SIP कल गर्न मिल्दैन।\nतपाईंका हालका SIP खाताहरू <xliff:g id="REMOVED_SIP_ACCOUNTS">%s</xliff:g> हटाइएका छन्।\nकृपया आफ्नो पूर्वनिर्धारित कल गर्ने खाताको सेटिङ पुष्टि गर्नुहोस्।"</string>
+    <string name="sip_accounts_removed_notification_message" msgid="1916856744869791592">"अबदेखि Android प्लेटफर्ममा SIP कल गर्न मिल्दैन।\nतपाईंका हालका SIP खाताहरू <xliff:g id="REMOVED_SIP_ACCOUNTS">%s</xliff:g> हटाइएका छन्।\nकृपया आफ्नो डिफल्ट कल गर्ने खाताको सेटिङ पुष्टि गर्नुहोस्।"</string>
     <string name="sip_accounts_removed_notification_action" msgid="3772778402370555562">"सेटिङमा जानुहोस्"</string>
     <string name="data_usage_title" msgid="8438592133893837464">"अनुप्रयोगले गरेको डेटाको प्रयोग"</string>
     <string name="data_usage_template" msgid="6287906680674061783">"<xliff:g id="ID_2">%2$s</xliff:g> सम्म <xliff:g id="ID_1">%1$s</xliff:g> मोबाइल डेटा प्रयोग भयो"</string>
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"पासवर्ड गलत छ। सिम अब ब्लक गरिएको छ। PUK2 प्रविष्टि गर्नुहोस्।"</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 स्थायी रूपमा रोक्का गरियो।"</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n" तपाईंसँग <xliff:g id="NUMBER">%d</xliff:g> प्रयास बाँकी छन्।"</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"SIM कार्ड PUK2 बाट लक गरिएको छ। अनलक गर्न सेवा प्रदायकलाई सम्पर्क गर्नुहोस्।"</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 अब ब्लक गरिएको छैन"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"नेटवर्क वा SIM कार्ड त्रुटि।"</string>
     <string name="doneButton" msgid="7371209609238460207">"सम्पन्न भयो"</string>
@@ -875,7 +876,7 @@
     <string name="radioInfo_lac" msgid="3892986460272607013">"LAC"</string>
     <string name="radioInfo_cid" msgid="1423185536264406705">"CID"</string>
     <string name="radio_info_subid" msgid="6839966868621703203">"हालको subId:"</string>
-    <string name="radio_info_dds" msgid="1122593144425697126">"पूर्वनिर्धारित डेटा SIM को SubId:"</string>
+    <string name="radio_info_dds" msgid="1122593144425697126">"डिफल्ट डेटा SIM को SubId:"</string>
     <string name="radio_info_dl_kbps" msgid="2382922659525318726">"DL ब्यान्डविथ (kbps):"</string>
     <string name="radio_info_ul_kbps" msgid="2102225400904799036">"UL व्यान्डविथ (kbps):"</string>
     <string name="radio_info_phy_chan_config" msgid="1277949603275436081">"LTE को भौतिक च्यानलको कन्फिगरेसन:"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 44299a9..7fa1a7b 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Wachtwoord onjuist. Simkaart nu vergrendeld. Geef PUK2 op."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2-code is definitief geblokkeerd."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Je hebt nog <xliff:g id="NUMBER">%d</xliff:g> pogingen."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 vergrendeld. Neem contact op met je serviceprovider om te ontgrendelen."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 niet langer geblokkeerd"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Netwerk- of simkaartfout"</string>
     <string name="doneButton" msgid="7371209609238460207">"Klaar"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 5d62d32..309f20f 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"ଭୁଲ୍ ପାସ୍‌ୱର୍ଡ। ବର୍ତ୍ତମାନ SIM ଲକ୍ ହୋ‌ଇଗଲା। PUK2କୁ ପ୍ରବେଶ କରନ୍ତୁ।"</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2କୁ ସ୍ଥାୟୀରୂପେ ଅବରୋଧ କରାଯାଇଛି।"</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"ଆପଣଙ୍କର <xliff:g id="NUMBER">%d</xliff:g>ଟି ସୁଯୋଗ ବଳକା ଅଛି।"</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 ଲକ୍ କରାଯାଇଛି। ଅନଲକ୍ କରିବାକୁ ସେବା ପ୍ରଦାନକାରୀ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2କୁ ଆଉ ଅବରୋଧ କରାଯାଇନାହିଁ"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"ନେଟ୍‌ୱର୍କ କିମ୍ବା SIM କାର୍ଡ ତ୍ରୁଟି"</string>
     <string name="doneButton" msgid="7371209609238460207">"ହୋଇଗଲା"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index ea38abd..2fc2689 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"ਪਾਸਵਰਡ ਗ਼ਲਤ। SIM ਹੁਣ ਲੌਕ ਹੈ। PUK2 ਦਰਜ ਕਰੋ।"</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 ਸਥਾਈ ਤੌਰ ਤੇ ਬਲੌਕ ਕੀਤਾ ਹੋਇਆ ਹੈ।"</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"ਤੁਹਾਡੇ ਕੋਲ <xliff:g id="NUMBER">%d</xliff:g> ਕੋਸ਼ਿਸ਼ਾਂ ਬਾਕੀ ਹਨ।"</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 ਲਾਕ ਹੈ। ਅਣਲਾਕ ਕਰਨ ਲਈ ਸੇਵਾ ਪ੍ਰਦਾਨਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 ਹੁਣ ਬਲੌਕ ਨਹੀਂ ਹੈ"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"ਨੈਟਵਰਕ ਜਾਂ SIM ਕਾਰਡ ਤਰੁੱਟੀ"</string>
     <string name="doneButton" msgid="7371209609238460207">"ਹੋ ਗਿਆ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 29768ba..d803c14 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Nieprawidłowe hasło. Karta SIM została zablokowana. Wpisz PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 został trwale zablokowany."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Masz jeszcze <xliff:g id="NUMBER">%d</xliff:g> prób(y)."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"Kod PUK2 zablokowany. Aby odblokować, skontaktuj się z dostawcą usług."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 nie jest już zablokowany"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Błąd sieci lub karty SIM"</string>
     <string name="doneButton" msgid="7371209609238460207">"Gotowe"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index dbbdd85..ffce9e1 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Palavra-passe incorreta. SIM bloqueado. Introduza o PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 bloqueado permanentemente."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Tem mais <xliff:g id="NUMBER">%d</xliff:g> tentativas."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 bloqueado. Contacte o fornecedor de serviços para desbloquear."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"O PIN2 deixou de estar bloqueado"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Erro do cartão SIM ou da rede"</string>
     <string name="doneButton" msgid="7371209609238460207">"Concluído"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index c49ecdc..0e6a812 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Senha incorreta. Chip bloqueado. Insira o PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 permanentemente bloqueado."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Você tem <xliff:g id="NUMBER">%d</xliff:g> tentativas restantes."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 bloqueado. Entre em contato com o provedor de serviços para desbloqueá-lo."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 não mais bloqueado"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Erro de rede ou do chip"</string>
     <string name="doneButton" msgid="7371209609238460207">"Concluído"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 8b6d72e..654e70c 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Parola nu este corectă. Cardul SIM a fost blocat. Introduceți codul PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"Codul PUK2 este blocat definitiv."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"V-au rămas <xliff:g id="NUMBER">%d</xliff:g> (de) încercări."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"Blocat cu PUK2. Contactați furnizorul de servicii pentru a debloca."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"Codul PIN2 nu mai este blocat"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Eroare de rețea sau de card SIM"</string>
     <string name="doneButton" msgid="7371209609238460207">"Terminat"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index b7a44c7..8a0e770 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -303,7 +303,7 @@
     <string name="carrier_settings_euicc" msgid="1190237227261337749">"Оператор"</string>
     <string name="keywords_carrier_settings_euicc" msgid="8540160967922063745">"оператор, esim, sim, euicc, сменить оператора, добавить оператора"</string>
     <string name="carrier_settings_euicc_summary" msgid="2027941166597330117">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g> – <xliff:g id="PHONE_NUMBER">%2$s</xliff:g>"</string>
-    <string name="mobile_data_settings_title" msgid="7228249980933944101">"Мобильный Интернет"</string>
+    <string name="mobile_data_settings_title" msgid="7228249980933944101">"Мобильный интернет"</string>
     <string name="mobile_data_settings_summary" msgid="5012570152029118471">"Доступ к Интернету по мобильной сети"</string>
     <string name="data_usage_disable_mobile" msgid="5669109209055988308">"Отключить мобильный Интернет?"</string>
     <string name="sim_selection_required_pref" msgid="6985901872978341314">"Выберите SIM-карту"</string>
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Неверный пароль. SIM-карта заблокирована. Введите код PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"Код PUK2 заблокирован навсегда"</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Осталось попыток: <xliff:g id="NUMBER">%d</xliff:g>."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"Код PUK2 заблокирован. Чтобы разблокировать его, обратитесь к оператору."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"Код PIN2 разблокирован."</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Ошибка сети или SIM-карты"</string>
     <string name="doneButton" msgid="7371209609238460207">"Готово"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 91763ab..26b8c22 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"මුරපදය වැරදිය. SIM දැන් අගුළු දමා තිබේ. PUK2 ඇතුළු කරන්න."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 සදාකාලිකවම අවහිරයි."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"ඔබට නැවත උත්සාහ කිරීම් <xliff:g id="NUMBER">%d</xliff:g> ක් තිබේ."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 අගුළු දැමිණි. අගුළු ඇරීමට සේවා සපයන්නා සම්බන්ධ කර ගන්න."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"තව දුරටත් PIN2 අවහිර කර නොතිබේ"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"ජාලයේ හෝ SIM කාඩ්පතෙහි දෝෂයක්"</string>
     <string name="doneButton" msgid="7371209609238460207">"හරි"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 9bc4539..4a4173f 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Heslo je nesprávne. SIM karta bola uzamknutá. Zadajte kód PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"Kód PUK2 je natrvalo blokovaný."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Zostávajú vám pokusy (počet: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"SIM karta je blokovaná kódom PUK2. Ak ju chcete odblokovať, kontaktujte poskytovateľa služieb."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"Kód PIN2 už nie je blokovaný"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Došlo k chybe siete alebo SIM karty"</string>
     <string name="doneButton" msgid="7371209609238460207">"Hotovo"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 0a0755e..fba55c1 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Geslo je napačno. Kartica SIM je zaklenjena. Vnesite kodo PUK 2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"Koda PUK2 je trajno blokirana."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Imate še toliko poskusov: <xliff:g id="NUMBER">%d</xliff:g>."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"Zaklenjeno s kodo PUK2. Za odklepanje se obrnite na ponudnika storitev."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"Koda PIN 2 ni več blokirana"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Napaka omrežja ali kartice SIM"</string>
     <string name="doneButton" msgid="7371209609238460207">"Dokončano"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 647d75a..acefc2c 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Fjalëkalimi është i pasaktë. Karta SIM tani është e kyçur. Fut PUK2-shin."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2-shi është i bllokuar përgjithmonë."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Të kanë mbetur edhe <xliff:g id="NUMBER">%d</xliff:g> përpjekje."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"Kodi PUK2 i kyçur. Kontakto me ofruesin e shërbimit për ta shkyçur."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2-shi nuk është më i bllokuar"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Gabim në rrjet ose në kartën SIM"</string>
     <string name="doneButton" msgid="7371209609238460207">"U krye"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index d26cc50..434e355 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Лозинка није тачна. SIM је сада блокиран. Унесите PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 је трајно блокиран."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Имате још <xliff:g id="NUMBER">%d</xliff:g> покушаја."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 је закључан. За откључавање се обратите добављачу услуге."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 више није блокиран"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Грешка на мрежи или SIM картици"</string>
     <string name="doneButton" msgid="7371209609238460207">"Готово"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 66304a2..2ac04ab 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -75,7 +75,7 @@
     <string name="phone_accounts_configure_account_settings" msgid="6622119715253196586">"Konfigurera kontoinställningar"</string>
     <string name="phone_accounts_all_calling_accounts" msgid="1609600743500618823">"Alla konton för samtal"</string>
     <string name="phone_accounts_all_calling_accounts_summary" msgid="2214134955430107240">"Välj vilka konton som kan ringa samtal"</string>
-    <string name="wifi_calling" msgid="3650509202851355742">"Wi-Fi-samtal"</string>
+    <string name="wifi_calling" msgid="3650509202851355742">"wifi-samtal"</string>
     <string name="connection_service_default_label" msgid="7332739049855715584">"Inbyggd anslutningstjänst"</string>
     <string name="voicemail" msgid="7697769412804195032">"Röstbrevlåda"</string>
     <string name="voicemail_settings_with_label" msgid="4228431668214894138">"Röstbrevlåda (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
@@ -309,7 +309,7 @@
     <string name="sim_selection_required_pref" msgid="6985901872978341314">"Du måste välja något"</string>
     <string name="sim_change_data_title" msgid="9142726786345906606">"Vill du ändra data-SIM?"</string>
     <string name="sim_change_data_message" msgid="3567358694255933280">"Vill du använda <xliff:g id="NEW_SIM">%1$s</xliff:g> i stället för <xliff:g id="OLD_SIM">%2$s</xliff:g> för mobildata?"</string>
-    <string name="wifi_calling_settings_title" msgid="5800018845662016507">"Wi-Fi-samtal"</string>
+    <string name="wifi_calling_settings_title" msgid="5800018845662016507">"wifi-samtal"</string>
     <string name="video_calling_settings_title" msgid="342829454913266078">"Videosamtal via operatören"</string>
     <string name="gsm_umts_options" msgid="4968446771519376808">"Alternativ för GSM/UMTS"</string>
     <string name="cdma_options" msgid="3669592472226145665">"CDMA-alternativ"</string>
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Felaktigt lösenord. SIM-kortet är nu låst. Ange PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK-kod 2 har blockerats permanent."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Du har <xliff:g id="NUMBER">%d</xliff:g> försök kvar."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 låst. Kontakta tjänsteleverantören för att låsa upp."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 är inte längre blockerad"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Nätverks- eller SIM-kortsfel"</string>
     <string name="doneButton" msgid="7371209609238460207">"Färdig"</string>
@@ -553,7 +554,7 @@
     <string name="incall_error_supp_service_hangup" msgid="836524952243836735">"Det gick inte att släppa samtal."</string>
     <string name="incall_error_supp_service_hold" msgid="8535056414643540997">"Det går inte att hålla kvar samtal."</string>
     <string name="incall_error_wfc_only_no_wireless_network" msgid="5860742792811400109">"Anslut till ett trådlöst nätverk om du vill ringa."</string>
-    <string name="incall_error_promote_wfc" msgid="9164896813931363415">"Aktivera Wi-Fi-samtal för att ringa."</string>
+    <string name="incall_error_promote_wfc" msgid="9164896813931363415">"Aktivera wifi-samtal för att ringa."</string>
     <string name="emergency_information_hint" msgid="9208897544917793012">"Nödinformation"</string>
     <string name="emergency_information_owner_hint" msgid="6256909888049185316">"Ägare"</string>
     <string name="emergency_information_confirm_hint" msgid="5109017615894918914">"Tryck igen för att visa information"</string>
@@ -615,7 +616,7 @@
     <string name="ota_hfa_activation_title" msgid="3300556778212729671">"Aktiveras ..."</string>
     <string name="ota_hfa_activation_dialog_message" msgid="7921718445773342996">"Din mobila datatjänst aktiveras av mobilen.\n\nDetta kan ta upp till fem minuter."</string>
     <string name="ota_skip_activation_dialog_title" msgid="7666611236789203797">"Vill du hoppa över aktiveringen?"</string>
-    <string name="ota_skip_activation_dialog_message" msgid="6691722887019708713">"Om du hoppar över aktiveringen kan du inte ringa samtal eller ansluta till mobila datanätverk (men du kan ansluta till Wi-Fi-nätverk). Du kommer att påminnas om att aktivera telefonen varje gång du sätter på den, tills du har aktiverat den."</string>
+    <string name="ota_skip_activation_dialog_message" msgid="6691722887019708713">"Om du hoppar över aktiveringen kan du inte ringa samtal eller ansluta till mobila datanätverk (men du kan ansluta till wifi-nätverk). Du kommer att påminnas om att aktivera telefonen varje gång du sätter på den, tills du har aktiverat den."</string>
     <string name="ota_skip_activation_dialog_skip_label" msgid="5908029466817825633">"Hoppa över"</string>
     <string name="ota_activate" msgid="7939695753665438357">"Aktivera"</string>
     <string name="ota_title_activate_success" msgid="1272135024761004889">"Telefonen är aktiverad."</string>
@@ -679,18 +680,18 @@
     <string name="sim_description_emergency_calls" msgid="5146872803938897296">"Endast nödsamtal"</string>
     <string name="sim_description_default" msgid="7474671114363724971">"SIM-kortsplats: <xliff:g id="SLOT_ID">%s</xliff:g>"</string>
     <string name="accessibility_settings_activity_title" msgid="7883415189273700298">"Tillgänglighet"</string>
-    <string name="status_hint_label_incoming_wifi_call" msgid="2606052595898044071">"Wi-Fi-samtal från"</string>
-    <string name="status_hint_label_wifi_call" msgid="942993035689809853">"Wi-Fi-samtal"</string>
+    <string name="status_hint_label_incoming_wifi_call" msgid="2606052595898044071">"wifi-samtal från"</string>
+    <string name="status_hint_label_wifi_call" msgid="942993035689809853">"wifi-samtal"</string>
     <string name="emergency_action_launch_hint" msgid="2762016865340891314">"Tryck igen för att öppna"</string>
     <string name="message_decode_error" msgid="1061856591500290887">"Ett fel inträffade när meddelandet avkodades."</string>
     <string name="callFailed_cdma_activation" msgid="5392057031552253550">"Ett SIM-kort har använts för att aktivera tjänsten och uppdatera roamingfunktionerna i mobilen."</string>
     <string name="callFailed_cdma_call_limit" msgid="1074219746093031412">"Det finns för många aktiva samtal. Avsluta eller slå samman pågående samtal innan du ringer ett nytt."</string>
     <string name="callFailed_imei_not_accepted" msgid="7257903653685147251">"Det går inte att ansluta. Sätt i ett giltigt SIM-kort."</string>
-    <string name="callFailed_wifi_lost" msgid="1788036730589163141">"Wi-Fi-anslutningen bruten. Samtal avslutat."</string>
+    <string name="callFailed_wifi_lost" msgid="1788036730589163141">"wifi-anslutningen bruten. Samtal avslutat."</string>
     <string name="dialFailed_low_battery" msgid="6857904237423407056">"Det går inte att ringa videosamtal på grund av svagt batteri."</string>
     <string name="callFailed_low_battery" msgid="4056828320214416182">"Videosamtalet slutade på grund av svagt batteri."</string>
-    <string name="callFailed_emergency_call_over_wfc_not_available" msgid="5944309590693432042">"Nödsamtal via Wi-Fi är inte tillgängligt på den här platsen."</string>
-    <string name="callFailed_wfc_service_not_available_in_this_location" msgid="3624536608369524988">"Wi-Fi-samtal är inte tillgängligt på den här platsen."</string>
+    <string name="callFailed_emergency_call_over_wfc_not_available" msgid="5944309590693432042">"Nödsamtal via wifi är inte tillgängligt på den här platsen."</string>
+    <string name="callFailed_wfc_service_not_available_in_this_location" msgid="3624536608369524988">"wifi-samtal är inte tillgängligt på den här platsen."</string>
     <string name="change_pin_title" msgid="3564254326626797321">"Ändra röstbrevlådans pinkod"</string>
     <string name="change_pin_continue_label" msgid="5177011752453506371">"Fortsätt"</string>
     <string name="change_pin_cancel_label" msgid="2301711566758827936">"Avbryt"</string>
@@ -835,7 +836,7 @@
     <string name="radio_info_data_connection_disable" msgid="6404751291511368706">"Inaktivera dataanslutning"</string>
     <string name="volte_provisioned_switch_string" msgid="4812874990480336178">"VoLTE-administrerad"</string>
     <string name="vt_provisioned_switch_string" msgid="8295542122512195979">"Videosamtal tillhandahålls"</string>
-    <string name="wfc_provisioned_switch_string" msgid="3835004640321078988">"Wi-Fi-samtal tillhandahålls"</string>
+    <string name="wfc_provisioned_switch_string" msgid="3835004640321078988">"wifi-samtal tillhandahålls"</string>
     <string name="eab_provisioned_switch_string" msgid="4449676720736033035">"EAB/Presence tillhandahålls"</string>
     <string name="cbrs_data_switch_string" msgid="6060356430838077653">"Data via CBRS"</string>
     <string name="dsds_switch_string" msgid="7564769822086764796">"Aktivera DSDS"</string>
@@ -853,7 +854,7 @@
     <string name="radio_info_ims_reg_status_not_registered" msgid="8045821447288876085">"Inte registrerad"</string>
     <string name="radio_info_ims_feature_status_available" msgid="6493200914756969292">"Tillgänglig"</string>
     <string name="radio_info_ims_feature_status_unavailable" msgid="8930391136839759778">"Inte tillgängligt"</string>
-    <string name="radio_info_ims_reg_status" msgid="25582845222446390">"IMS-registrering: <xliff:g id="STATUS">%1$s</xliff:g>\nRöst via LTE: <xliff:g id="AVAILABILITY_0">%2$s</xliff:g>\nRöst via Wi-Fi: <xliff:g id="AVAILABILITY_1">%3$s</xliff:g>\nVideosamtal: <xliff:g id="AVAILABILITY_2">%4$s</xliff:g>\nUT-gränssnitt: <xliff:g id="AVAILABILITY_3">%5$s</xliff:g>"</string>
+    <string name="radio_info_ims_reg_status" msgid="25582845222446390">"IMS-registrering: <xliff:g id="STATUS">%1$s</xliff:g>\nRöst via LTE: <xliff:g id="AVAILABILITY_0">%2$s</xliff:g>\nRöst via wifi: <xliff:g id="AVAILABILITY_1">%3$s</xliff:g>\nVideosamtal: <xliff:g id="AVAILABILITY_2">%4$s</xliff:g>\nUT-gränssnitt: <xliff:g id="AVAILABILITY_3">%5$s</xliff:g>"</string>
     <string name="radioInfo_service_in" msgid="45753418231446400">"I tjänst"</string>
     <string name="radioInfo_service_out" msgid="287972405416142312">"Ur funktion"</string>
     <string name="radioInfo_service_emergency" msgid="4763879891415016848">"Endast nödsamtal"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 246e47f..c292108 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Nenosiri si sahihi. SIM sasa imefungwa. Weka PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 Imezuiwa kabisa."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Una majaribio <xliff:g id="NUMBER">%d</xliff:g> yaliyobaki."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"Imefungwa kwa sababu PUK2 si sahihi. Wasiliana na mtoa huduma ili aifungue."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 sasa haijazuiwa"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Hitilafu ya mtandao au SIM kadi"</string>
     <string name="doneButton" msgid="7371209609238460207">"Kwisha"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 53feaf6..ab850a6 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -339,7 +339,7 @@
     <string name="maintenance_enable" msgid="2646784483222342290">"பராமரிப்பு இயக்கப்பட்டது"</string>
     <string name="maintenance_disable" msgid="2121032601497725602">"பராமரிப்பு முடக்கப்பட்டது"</string>
     <string name="general_news_settings" msgid="2670499575962080411">"பொது செய்திகள்"</string>
-    <string name="bf_news_settings" msgid="8571709425370794221">"வணிகம் மற்றும் நிதிசார்ந்த செய்திகள்"</string>
+    <string name="bf_news_settings" msgid="8571709425370794221">"பிசினஸ் மற்றும் நிதிசார்ந்த செய்திகள்"</string>
     <string name="sports_news_settings" msgid="2684364556989168438">"விளையாட்டுச் செய்திகள்"</string>
     <string name="entertainment_news_settings" msgid="4228527702346305543">"பொழுதுபோக்குச் செய்திகள்"</string>
     <string name="enable_disable_local" msgid="7654175079979415572">"உள்ளூர்"</string>
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"கடவுச்சொல் தவறானது. சிம் இப்போது பூட்டப்பட்டது. PUK2ஐ உள்ளிடவும்."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 தற்காலிகமாகத் தடுக்கப்பட்டது."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"நீங்கள் <xliff:g id="NUMBER">%d</xliff:g> முறை முயற்சிக்கலாம்."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 லாக் செய்யப்பட்டுள்ளது. அன்லாக் செய்ய சேவை வழங்குநரைத் தொடர்புகொள்ளவும்."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 இனி தடுக்கப்படாது"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"நெட்வொர்க் அல்லது சிம் கார்டு பிழை"</string>
     <string name="doneButton" msgid="7371209609238460207">"முடிந்தது"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 1addd62..311e0fd 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -144,7 +144,7 @@
     <string name="stk_cc_ss_to_ussd_error" msgid="8330749347425752192">"SS అభ్యర్థన USSD అభ్యర్థనకు మార్చబడింది"</string>
     <string name="stk_cc_ss_to_ss_error" msgid="8297155544652134278">"కొత్త SS అభ్యర్థనకు మార్చబడింది"</string>
     <string name="stk_cc_ss_to_dial_video_error" msgid="4255261231466032505">"SS అభ్యర్థన వీడియో కాల్‌కి మార్చబడింది"</string>
-    <string name="fdn_check_failure" msgid="1833769746374185247">"మీ ఫోన్ అనువర్తనం యొక్క ఫిక్స్‌డ్ డయలింగ్ నంబర్‌ల సెట్టింగ్ ప్రారంభించబడింది. తత్ఫలితంగా, కాల్ సంబంధిత లక్షణాల్లో కొన్ని పని చేయడం లేదు."</string>
+    <string name="fdn_check_failure" msgid="1833769746374185247">"మీ ఫోన్ యాప్‌ యొక్క ఫిక్స్‌డ్ డయలింగ్ నంబర్‌ల సెట్టింగ్ ప్రారంభించబడింది. తత్ఫలితంగా, కాల్ సంబంధిత లక్షణాల్లో కొన్ని పని చేయడం లేదు."</string>
     <string name="radio_off_error" msgid="8321564164914232181">"ఈ సెట్టింగ్‌లను వీక్షించడానికి ముందు రేడియోను ప్రారంభించండి."</string>
     <string name="close_dialog" msgid="1074977476136119408">"సరే"</string>
     <string name="enable" msgid="2636552299455477603">"ఆన్ చేయి"</string>
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"పాస్‌వర్డ్ చెల్లదు. SIM ఇప్పుడు లాక్ చేయబడింది. PUK2ని నమోదు చేయండి."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 శాశ్వతంగా బ్లాక్ చేయబడింది."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"మీకు <xliff:g id="NUMBER">%d</xliff:g> ప్రయత్నాలు మిగిలి ఉన్నాయి."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 లాక్ చేయబడింది. అన్‌లాక్ చేయడానికి సర్వీస్ ప్రొవైడర్‌ను కాంటాక్ట్ చేయండి."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 ఇప్పుడు బ్లాక్ అయ్యి లేదు"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"నెట్‌వర్క్ లేదా SIM కార్డ్ లోపం"</string>
     <string name="doneButton" msgid="7371209609238460207">"పూర్తయింది"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 0c89178..f709a7c 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"รหัสผ่านไม่ถูกต้อง ระบบล็อกซิมแล้ว โปรดป้อน PUK2"</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 ถูกบล็อกอย่างถาวร"</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"คุณพยายามได้อีก <xliff:g id="NUMBER">%d</xliff:g> ครั้ง"</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 ล็อกอยู่ ติดต่อผู้ให้บริการเพื่อปลดล็อก"</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"ไม่มีการบล็อก PIN2 อีกต่อไป"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"เครือข่ายหรือซิมการ์ดเกิดข้อผิดพลาด"</string>
     <string name="doneButton" msgid="7371209609238460207">"เสร็จสิ้น"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index c781d71..5d62d87 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Mali ang password. Naka-lock na ngayon ang SIM. Ilagay ang PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"Permanenteng na-block ang PUK2."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Mayroon ka na lang <xliff:g id="NUMBER">%d</xliff:g> (na) natitirang pagsubok."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"Na-lock ang PUK2. Makipag-ugnayan sa service provider para i-unlock."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"Hindi na naka-block ang PIN2"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Error sa network o SIM card"</string>
     <string name="doneButton" msgid="7371209609238460207">"Tapos na"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 7c9a00d..c5a1060 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Şifre hatalı. SIM kilitlendi. PUK2\'yi girin."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 kalıcı olarak engellendi."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"<xliff:g id="NUMBER">%d</xliff:g> deneme hakkınız kaldı."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 kilitlendi. Kilidi açmak için servis sağlayıcıyla iletişime geçin."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 artık engellenmiş durumda değil"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Ağ veya SIM kart hatası"</string>
     <string name="doneButton" msgid="7371209609238460207">"Bitti"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 9ef5fed..61c1c68 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Неправильний пароль. SIM-карту заблоковано. Введіть PUK2-код."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2-код назавжди заблоковано."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"У вас залишилося стільки спроб: <xliff:g id="NUMBER">%d</xliff:g>."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"Заблоковано кодом PUK2. Щоб розблокувати, зв’яжіться з оператором."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2-код більше не заблоковано"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Помилка мережі або SIM-карти"</string>
     <string name="doneButton" msgid="7371209609238460207">"Готово"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index ec3b772..cfc2df8 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"‏پاس ورڈ غلط ہے۔ SIM اب مقفل ہے۔ PUK2 درج کریں۔"</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"‏PUK2 مستقل طور پر مسدود ہے۔"</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"آپ کے پاس <xliff:g id="NUMBER">%d</xliff:g> کوششیں بچی ہیں۔"</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"‏PUK2 مقفل ہے۔ غیر مقفل کرنے کے ليے سروس فراہم کنندہ سے رابطہ کریں۔"</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"‏PIN2 اب مسدود نہیں ہے"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"‏نیٹ ورک یا SIM کارڈ کی خرابی"</string>
     <string name="doneButton" msgid="7371209609238460207">"ہوگیا"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 3bd6991..9ebb2ac 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Parol noto‘g‘ri. SIM karta qulflandi. PUK2 kodini kiriting."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 kod butunlay to‘sib qo‘yildi."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Sizda <xliff:g id="NUMBER">%d</xliff:g> ta urinish qoldi."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 bloklangan. Uni blokdan chiqarish uchun xizmat ta’minotchisiga murojaat qiling."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 kodi blokdan chiqarildi"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Tarmoq yoki SIM kartada xato"</string>
     <string name="doneButton" msgid="7371209609238460207">"Tayyor"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 191e2e7..a0fb9a0 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Mật khẩu không đúng. SIM hiện đã bị chặn. Hãy nhập PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 bị chặn vĩnh viễn."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Bạn còn <xliff:g id="NUMBER">%d</xliff:g> lần thử."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 đang bị khóa. Hãy liên hệ với nhà cung cấp dịch vụ để mở khóa."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 không còn bị chặn"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Lỗi mạng hoặc thẻ SIM"</string>
     <string name="doneButton" msgid="7371209609238460207">"Xong"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 08bb0fe..50b4b27 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"密码不正确。SIM 卡已锁定。请输入 PUK2 码。"</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2码已被永远锁定。"</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"您还可以尝试输入 <xliff:g id="NUMBER">%d</xliff:g> 次。"</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"SIM 卡已通过 PUK2 进行锁定。请联系服务提供商来解锁。"</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 码已解除锁定"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"网络或 SIM 卡错误"</string>
     <string name="doneButton" msgid="7371209609238460207">"完成"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 7b5391b..4da008f 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"密碼不正確。SIM 現在已被封鎖,請輸入 PUK2。"</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 碼已被永久封鎖。"</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"您還有 <xliff:g id="NUMBER">%d</xliff:g> 次嘗試機會。"</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"PUK2 已鎖定。請通知服務供應商解鎖。"</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 目前沒有封鎖"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"網絡或 SIM 卡錯誤。"</string>
     <string name="doneButton" msgid="7371209609238460207">"完成"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index f998c5e..440bb1d 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"密碼不正確,SIM 卡現已遭到封鎖。請輸入 PUK2。"</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"PUK2 遭到永久封鎖。"</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"您還可以嘗試 <xliff:g id="NUMBER">%d</xliff:g> 次。"</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"SIM 卡已遭 PUK2 碼鎖定,請要求服務供應商協助解鎖。"</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 已解除封鎖"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"網路或 SIM 卡錯誤"</string>
     <string name="doneButton" msgid="7371209609238460207">"完成"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index e84395b..3456b3a 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -515,6 +515,7 @@
     <string name="puk2_requested" msgid="6992374450720307514">"Iphasiwedi ayilungile. I-SIM manje ikhiyiwe. Faka i-PUK2."</string>
     <string name="puk2_blocked" msgid="3131139031779319911">"I-PUK2 ivinjiwe unaphakade."</string>
     <string name="pin2_attempts" msgid="5625178102026453023">\n"Unemizamo engu-<xliff:g id="NUMBER">%d</xliff:g> esele."</string>
+    <string name="puk2_locked" msgid="6497760825455461057">"I-PUK2 ikhiyiwe. Xhumana nomhlinzeki wesevisi ukuze uvule."</string>
     <string name="pin2_unblocked" msgid="4481107908727789303">"I-PIN2 ayisavinjiwe"</string>
     <string name="pin2_error_exception" msgid="8116103864600823641">"Iphutha lenethiwekhi noma lekhadi le-SIM"</string>
     <string name="doneButton" msgid="7371209609238460207">"Kwenziwe"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index 9f8cc81..a296254 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -317,4 +317,8 @@
     <!-- The package names which can request thermal mitigation. -->
     <string-array name="thermal_mitigation_allowlisted_packages" translatable="false">
     </string-array>
+
+    <!-- The package name of the app which hosts the
+         {@link TelecomManager#ACTION_SHOW_CALL_SETTINGS} settings screen. -->
+    <string name="call_settings_package_name">com.android.phone</string>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 88d2f1a..47d571e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2159,6 +2159,8 @@
     <string name="radio_info_nr_state">NR State:</string>
     <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
     <string name="radio_info_nr_frequency">NR Frequency:</string>
+    <!-- Radio Info screen. Label for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="radio_info_network_slicing_config" translatable="false">Network slicing config:</string>
 
     <!-- Band Mode Selection -->
     <!-- Band mode screen.  Title of activity. -->
diff --git a/sip/res/values-iw/strings.xml b/sip/res/values-iw/strings.xml
index 6e84560..34b1b20 100644
--- a/sip/res/values-iw/strings.xml
+++ b/sip/res/values-iw/strings.xml
@@ -24,29 +24,29 @@
     <string name="sip_call_options_title" msgid="5027066677561068192">"‏שימוש בשיחות SIP"</string>
     <string name="sip_call_options_wifi_only_title" msgid="6663105297927456484">"‏שימוש בשיחות SIP ‏(Wi-Fi בלבד)‏"</string>
     <string name="sip_call_options_entry_1" msgid="4722647332760934261">"לכל השיחות כאשר רשת הנתונים זמינה"</string>
-    <string name="sip_call_options_entry_2" msgid="7338504256051655013">"‏עבור שיחות SIP בלבד"</string>
+    <string name="sip_call_options_entry_2" msgid="7338504256051655013">"‏מעבר לשיחות SIP בלבד"</string>
     <string name="sip_call_options_wifi_only_entry_1" msgid="922329055414010991">"לכל השיחות"</string>
     <string name="add_sip_account" msgid="5754758646745144384">"חשבון חדש"</string>
     <string name="remove_sip_account" msgid="8272617403399636513">"הסרת חשבון"</string>
     <string name="sip_account_list" msgid="2596262496233721769">"‏חשבונות SIP"</string>
-    <string name="saving_account" msgid="3390358043846687266">"שומר את החשבון..."</string>
-    <string name="removing_account" msgid="1544132880414780408">"מסיר את החשבון..."</string>
-    <string name="sip_menu_save" msgid="4377112554203123060">"שמור"</string>
-    <string name="sip_menu_discard" msgid="1883166691772895243">"מחק"</string>
-    <string name="alert_dialog_close" msgid="1734746505531110706">"סגור את הפרופיל"</string>
+    <string name="saving_account" msgid="3390358043846687266">"שמירת החשבון מתבצעת..."</string>
+    <string name="removing_account" msgid="1544132880414780408">"הסרת החשבון מתבצעת..."</string>
+    <string name="sip_menu_save" msgid="4377112554203123060">"שמירה"</string>
+    <string name="sip_menu_discard" msgid="1883166691772895243">"מחיקה"</string>
+    <string name="alert_dialog_close" msgid="1734746505531110706">"סגירת הפרופיל"</string>
     <string name="alert_dialog_ok" msgid="7806760618798687406">"אישור"</string>
-    <string name="close_profile" msgid="3756064641769751774">"סגור"</string>
-    <string name="registration_status_checking_status" msgid="884179594507591180">"בודק מצב..."</string>
-    <string name="registration_status_registering" msgid="7986331597809521791">"מבצע רישום..."</string>
-    <string name="registration_status_still_trying" msgid="7178623685868766282">"עדיין מנסה..."</string>
+    <string name="close_profile" msgid="3756064641769751774">"סגירה"</string>
+    <string name="registration_status_checking_status" msgid="884179594507591180">"בדיקת המצב מתבצעת..."</string>
+    <string name="registration_status_registering" msgid="7986331597809521791">"הרישום מתבצע..."</string>
+    <string name="registration_status_still_trying" msgid="7178623685868766282">"הניסיון מתבצע..."</string>
     <string name="registration_status_not_receiving" msgid="3873074208531938401">"לא מקבל שיחות."</string>
     <string name="registration_status_no_data" msgid="2987064560116584121">"רישום החשבון הופסק כיוון שאין חיבור לאינטרנט."</string>
     <string name="registration_status_no_wifi_data" msgid="685470618241482948">"‏רישום החשבון הופסק כיוון שאין חיבור Wi-Fi."</string>
     <string name="registration_status_not_running" msgid="6236403137652262659">"רישום החשבון נכשל."</string>
-    <string name="registration_status_done" msgid="6787397199273357721">"מקבל שיחות."</string>
+    <string name="registration_status_done" msgid="6787397199273357721">"קבלת שיחות."</string>
     <string name="registration_status_failed_try_later" msgid="7855389184910312091">"רישום החשבון נכשל: (<xliff:g id="REGISTRATION_ERROR_MESSAGE">%s</xliff:g>); ניסיון חוזר יבוצע מאוחר יותר"</string>
     <string name="registration_status_invalid_credentials" msgid="8896714049938660777">"רישום החשבון נכשל: שם המשתמש או הסיסמה שגויים."</string>
-    <string name="registration_status_server_unreachable" msgid="3832339558868965604">"רישום החשבון נכשל: בדוק את שם השרת."</string>
+    <string name="registration_status_server_unreachable" msgid="3832339558868965604">"רישום החשבון נכשל: יש לבדוק את שם השרת."</string>
     <string name="third_party_account_summary" msgid="5918779106950859167">"האפליקציה <xliff:g id="ACCOUNT_OWNER">%s</xliff:g> משתמשת כרגע בחשבון הזה."</string>
     <string name="sip_edit_title" msgid="7438891546610820307">"‏פרטי חשבון SIP"</string>
     <string name="sip_edit_new_title" msgid="8394790068979636381">"‏פרטי חשבון SIP"</string>
@@ -57,7 +57,7 @@
     <string name="proxy_address_title" msgid="4120361943254795287">"‏כתובת שרת Proxy יוצא"</string>
     <string name="port_title" msgid="1703586046264385110">"מספר יציאה"</string>
     <string name="transport_title" msgid="1661659138226029178">"סוג העברה"</string>
-    <string name="send_keepalive_title" msgid="5319788151608946049">"שלח אות חיבור"</string>
+    <string name="send_keepalive_title" msgid="5319788151608946049">"שליחת אות חיבור"</string>
     <string name="advanced_settings" msgid="2704644977548662872">"הגדרות אופציונליות"</string>
     <string name="auth_username_title" msgid="9002505242616662698">"שם משתמש לאימות"</string>
     <string name="auth_username_summary" msgid="6346313945275377230">"שם משתמש המשמש לאימות"</string>
@@ -67,14 +67,14 @@
     <string name="display_name_summary" msgid="6749135030093260358">"‏&lt;זהה לשם משתמש&gt;"</string>
     <string name="optional_summary" msgid="620379377865437488">"‏&lt;אופציונלי&gt;"</string>
     <string name="advanced_settings_show" msgid="2318728080037568529">"איפה כל ההגדרות?"</string>
-    <string name="advanced_settings_hide" msgid="6200816937370652083">"▽ גע כדי להסתיר את הכול"</string>
-    <string name="all_empty_alert" msgid="6085603517610199098">"‏הזן את פרטי חשבון ה-SIP החדש."</string>
+    <string name="advanced_settings_hide" msgid="6200816937370652083">"▽ יש לגעת כדי להסתיר את הכול"</string>
+    <string name="all_empty_alert" msgid="6085603517610199098">"‏יש להזין את פרטי חשבון ה-SIP החדש."</string>
     <string name="empty_alert" msgid="3693655518612836718">"<xliff:g id="INPUT_FIELD_NAME">%s</xliff:g> הוא שדה חובה ולא ניתן להשאיר אותו ריק."</string>
     <string name="not_a_valid_port" msgid="3664668836663491376">"מספר היציאה צריך להיות בין 1000 ל-65534."</string>
-    <string name="no_internet_available" msgid="161720645084325479">"‏כדי לבצע שיחת SIP, ראשית בדוק את חיבור האינטרנט שלך."</string>
-    <string name="no_wifi_available" msgid="1179092018692306312">"‏עליך להיות מחובר לרשת Wi-Fi כדי לבצע שיחות SIP (השתמש ב\'הגדרות רשת ותקשורת אלחוטית\')."</string>
+    <string name="no_internet_available" msgid="161720645084325479">"‏כדי לבצע שיחת SIP, ראשית יש לבדוק את חיבור האינטרנט שלך."</string>
+    <string name="no_wifi_available" msgid="1179092018692306312">"‏יש צורך בחיבור לרשת Wi-Fi כדי לבצע שיחות SIP (יש להשתמש ב\'הגדרות רשת ותקשורת אלחוטית\')."</string>
     <string name="no_voip" msgid="3366395789297981738">"‏שיחות SIP לא נתמכות"</string>
     <string name="sip_system_decide" msgid="197230378376326430">"אוטומטי"</string>
-    <string name="sip_always_send_keepalive" msgid="4986533673960084769">"שלח תמיד"</string>
+    <string name="sip_always_send_keepalive" msgid="4986533673960084769">"שליחה תמיד"</string>
     <string name="sip_connection_service_label" msgid="8796284274240316006">"‏שיחות SIP מובנות"</string>
 </resources>
diff --git a/sip/res/values-kn/strings.xml b/sip/res/values-kn/strings.xml
index cf7cd59..99fe93e 100644
--- a/sip/res/values-kn/strings.xml
+++ b/sip/res/values-kn/strings.xml
@@ -19,7 +19,7 @@
     <string name="sip_settings" msgid="7452587325305604702">"ಎಸ್‌ಐಪಿ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="sip_accounts" msgid="7297896885665783239">"ಎಸ್‌ಐಪಿ ಖಾತೆಗಳು"</string>
     <string name="sip_accounts_title" msgid="3061686404598143943">"ಖಾತೆಗಳು"</string>
-    <string name="sip_receive_calls" msgid="3403644006618369349">"ಒಳಬರುವ ಕರೆಗಳನ್ನು ಸ್ವೀಕರಿಸು"</string>
+    <string name="sip_receive_calls" msgid="3403644006618369349">"ಒಳಬರುವ ಕರೆಗಳನ್ನು ಸ್ವೀಕರಿಸಿ"</string>
     <string name="sip_receive_calls_summary" msgid="5306603671778761443">"ಹೆಚ್ಚು ಬ್ಯಾಟರಿಯನ್ನು ಬಳಸುತ್ತದೆ"</string>
     <string name="sip_call_options_title" msgid="5027066677561068192">"ಎಸ್‌ಐಪಿ ಕರೆ ಮಾಡುವಿಕೆಯನ್ನು ಬಳಸಿ"</string>
     <string name="sip_call_options_wifi_only_title" msgid="6663105297927456484">"ಎಸ್‌ಐಪಿ ಕರೆ ಮಾಡುವಿಕೆಯನ್ನು ಬಳಸಿ (ವೈ-ಫೈ ಮಾತ್ರ)"</string>
diff --git a/sip/res/values-mr/strings.xml b/sip/res/values-mr/strings.xml
index 60d9c88..6eb7245 100644
--- a/sip/res/values-mr/strings.xml
+++ b/sip/res/values-mr/strings.xml
@@ -19,7 +19,7 @@
     <string name="sip_settings" msgid="7452587325305604702">"SIP सेटिंग्ज"</string>
     <string name="sip_accounts" msgid="7297896885665783239">"SIP खाती"</string>
     <string name="sip_accounts_title" msgid="3061686404598143943">"खाती"</string>
-    <string name="sip_receive_calls" msgid="3403644006618369349">"येणारे कॉल घ्या"</string>
+    <string name="sip_receive_calls" msgid="3403644006618369349">"इनकमिंग कॉल घ्या"</string>
     <string name="sip_receive_calls_summary" msgid="5306603671778761443">"अधिक बॅटरी वापरते"</string>
     <string name="sip_call_options_title" msgid="5027066677561068192">"SIP कॉलिंग वापरा"</string>
     <string name="sip_call_options_wifi_only_title" msgid="6663105297927456484">"SIP कॉलिंग वापरा (वाय-फाय केवळ)"</string>
diff --git a/sip/res/values-ne/strings.xml b/sip/res/values-ne/strings.xml
index 9fc1263..e8938aa 100644
--- a/sip/res/values-ne/strings.xml
+++ b/sip/res/values-ne/strings.xml
@@ -31,7 +31,7 @@
     <string name="sip_account_list" msgid="2596262496233721769">"SIP खाताहरू"</string>
     <string name="saving_account" msgid="3390358043846687266">"खाता बचत गर्दै..."</string>
     <string name="removing_account" msgid="1544132880414780408">"खाता हटाउँदै..."</string>
-    <string name="sip_menu_save" msgid="4377112554203123060">"सुरक्षित गर्नुहोस्"</string>
+    <string name="sip_menu_save" msgid="4377112554203123060">"सेभ गर्नुहोस्"</string>
     <string name="sip_menu_discard" msgid="1883166691772895243">"त्याग्नुहोस्"</string>
     <string name="alert_dialog_close" msgid="1734746505531110706">"प्रोफाइल बन्द गर्नुहोस्"</string>
     <string name="alert_dialog_ok" msgid="7806760618798687406">"ठिक छ"</string>
@@ -51,7 +51,7 @@
     <string name="sip_edit_title" msgid="7438891546610820307">"SIP खाता विवरणहरू"</string>
     <string name="sip_edit_new_title" msgid="8394790068979636381">"SIP खाता विवरणहरू"</string>
     <string name="domain_address_title" msgid="8238078615181248579">"सर्भर"</string>
-    <string name="username_title" msgid="298416796886107970">"एक-पटके पाठ सन्देश"</string>
+    <string name="username_title" msgid="298416796886107970">"एक-पटके टेक्स्ट म्यासेज"</string>
     <string name="password_title" msgid="8035579335591959021">"पासवर्ड"</string>
     <string name="display_name_title" msgid="3730105783656830160">"नाम प्रदर्शन गर्नुहोस्"</string>
     <string name="proxy_address_title" msgid="4120361943254795287">"बाहिरका प्रोक्सी ठेगाना"</string>
@@ -59,12 +59,12 @@
     <string name="transport_title" msgid="1661659138226029178">"यातायात प्रकार"</string>
     <string name="send_keepalive_title" msgid="5319788151608946049">"चालु राख्नको लागि पठाउनुहोस्"</string>
     <string name="advanced_settings" msgid="2704644977548662872">"वैकल्पिक सेटिङहरू"</string>
-    <string name="auth_username_title" msgid="9002505242616662698">"प्रमाणीकरणको एक-पटके पाठ सन्देश"</string>
-    <string name="auth_username_summary" msgid="6346313945275377230">"प्रमाणीकरणको लागि एक-पटके पाठ सन्देश प्रयोग भएको"</string>
+    <string name="auth_username_title" msgid="9002505242616662698">"प्रमाणीकरणको एक-पटके टेक्स्ट म्यासेज"</string>
+    <string name="auth_username_summary" msgid="6346313945275377230">"प्रमाणीकरणको लागि एक-पटके टेक्स्ट म्यासेज प्रयोग भएको"</string>
     <string name="default_preference_summary_username" msgid="8788114717555599222">"&lt;सेट गरिएको छैन&gt;"</string>
     <string name="default_preference_summary_password" msgid="3695366978153175549">"&lt;सेट गरिएको छैन&gt;"</string>
     <string name="default_preference_summary_domain_address" msgid="443247296785732364">"&lt;सेट गरिएको छैन&gt;"</string>
-    <string name="display_name_summary" msgid="6749135030093260358">"&lt;एक-पटके पाठ सन्देश जस्तै&gt;"</string>
+    <string name="display_name_summary" msgid="6749135030093260358">"&lt;एक-पटके टेक्स्ट म्यासेज जस्तै&gt;"</string>
     <string name="optional_summary" msgid="620379377865437488">"&lt;वैकल्पिकgt;"</string>
     <string name="advanced_settings_show" msgid="2318728080037568529">"▷ छोएर सबै देखाउनुहोस्"</string>
     <string name="advanced_settings_hide" msgid="6200816937370652083">"▽ छोएर सबै लुकाउनुहोस्"</string>
diff --git a/sip/res/values-sq/strings.xml b/sip/res/values-sq/strings.xml
index 5c50085..e2e2ff1 100644
--- a/sip/res/values-sq/strings.xml
+++ b/sip/res/values-sq/strings.xml
@@ -54,7 +54,7 @@
     <string name="username_title" msgid="298416796886107970">"Emri i përdoruesit"</string>
     <string name="password_title" msgid="8035579335591959021">"Fjalëkalimi"</string>
     <string name="display_name_title" msgid="3730105783656830160">"Shfaq emrin"</string>
-    <string name="proxy_address_title" msgid="4120361943254795287">"Adresa e përfaqësuesit dalës"</string>
+    <string name="proxy_address_title" msgid="4120361943254795287">"Adresa e proxy-it dalës"</string>
     <string name="port_title" msgid="1703586046264385110">"Numri i portës"</string>
     <string name="transport_title" msgid="1661659138226029178">"Lloji i transportit"</string>
     <string name="send_keepalive_title" msgid="5319788151608946049">"Kontrolli i veprimtarisë"</string>
diff --git a/sip/res/values-sv/strings.xml b/sip/res/values-sv/strings.xml
index 2976425..a59eb21 100644
--- a/sip/res/values-sv/strings.xml
+++ b/sip/res/values-sv/strings.xml
@@ -41,7 +41,7 @@
     <string name="registration_status_still_trying" msgid="7178623685868766282">"Försöker fortfarande ..."</string>
     <string name="registration_status_not_receiving" msgid="3873074208531938401">"Tar inte emot samtal."</string>
     <string name="registration_status_no_data" msgid="2987064560116584121">"Kontoregistreringen avbröts eftersom det inte finns någon internetanslutning."</string>
-    <string name="registration_status_no_wifi_data" msgid="685470618241482948">"Kontoregistreringen avbröts eftersom det inte finns någon Wi-Fi-anslutning."</string>
+    <string name="registration_status_no_wifi_data" msgid="685470618241482948">"Kontoregistreringen avbröts eftersom det inte finns någon wifi-anslutning."</string>
     <string name="registration_status_not_running" msgid="6236403137652262659">"Det gick inte att registrera kontot."</string>
     <string name="registration_status_done" msgid="6787397199273357721">"Tar emot samtal."</string>
     <string name="registration_status_failed_try_later" msgid="7855389184910312091">"Det gick inte att registrera kontot: (<xliff:g id="REGISTRATION_ERROR_MESSAGE">%s</xliff:g>); försöker igen senare"</string>
@@ -72,7 +72,7 @@
     <string name="empty_alert" msgid="3693655518612836718">"<xliff:g id="INPUT_FIELD_NAME">%s</xliff:g> är ett obligatoriskt fält som måste fyllas i."</string>
     <string name="not_a_valid_port" msgid="3664668836663491376">"Portnumret ska vara mellan 1000 och 65534."</string>
     <string name="no_internet_available" msgid="161720645084325479">"Om du vill ringa ett SIP-samtal kontrollerar du först att du är ansluten till internet."</string>
-    <string name="no_wifi_available" msgid="1179092018692306312">"Du måste vara ansluten till Wi-Fi för att kunna ringa SIP-samtal (du ändrar detta i inställningarna för Trådlöst och nätverk)."</string>
+    <string name="no_wifi_available" msgid="1179092018692306312">"Du måste vara ansluten till wifi för att kunna ringa SIP-samtal (du ändrar detta i inställningarna för Trådlöst och nätverk)."</string>
     <string name="no_voip" msgid="3366395789297981738">"SIP-samtal stöds inte"</string>
     <string name="sip_system_decide" msgid="197230378376326430">"Automatiskt"</string>
     <string name="sip_always_send_keepalive" msgid="4986533673960084769">"Skicka alltid"</string>
diff --git a/sip/res/values-te/strings.xml b/sip/res/values-te/strings.xml
index 9abb6f5..b15b514 100644
--- a/sip/res/values-te/strings.xml
+++ b/sip/res/values-te/strings.xml
@@ -47,7 +47,7 @@
     <string name="registration_status_failed_try_later" msgid="7855389184910312091">"ఖాతా నమోదు విఫలమైంది: (<xliff:g id="REGISTRATION_ERROR_MESSAGE">%s</xliff:g>); తర్వాత ప్రయత్నిస్తుంది"</string>
     <string name="registration_status_invalid_credentials" msgid="8896714049938660777">"ఖాతా నమోదు విఫలమైంది: చెల్లని వినియోగదారు పేరు లేదా పాస్‌వర్డ్."</string>
     <string name="registration_status_server_unreachable" msgid="3832339558868965604">"ఖాతా నమోదు విఫలమైంది: సర్వర్ పేరు తనిఖీ చేయండి."</string>
-    <string name="third_party_account_summary" msgid="5918779106950859167">"ఈ ఖాతా ప్రస్తుతం <xliff:g id="ACCOUNT_OWNER">%s</xliff:g> అనువర్తనం ద్వారా ఉపయోగంలో ఉంది."</string>
+    <string name="third_party_account_summary" msgid="5918779106950859167">"ఈ ఖాతా ప్రస్తుతం <xliff:g id="ACCOUNT_OWNER">%s</xliff:g> యాప్‌ ద్వారా ఉపయోగంలో ఉంది."</string>
     <string name="sip_edit_title" msgid="7438891546610820307">"SIP ఖాతా వివరాలు"</string>
     <string name="sip_edit_new_title" msgid="8394790068979636381">"SIP ఖాతా వివరాలు"</string>
     <string name="domain_address_title" msgid="8238078615181248579">"సర్వర్"</string>
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 2b91a24..a463243 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -714,9 +714,6 @@
         mFromSystemUnlocked = new boolean[numPhones];
         mServiceConnectionForNoSimConfig = new CarrierServiceConnection[numPhones];
         mServiceBoundForNoSimConfig = new boolean[numPhones];
-        // Make this service available through ServiceManager.
-        TelephonyFrameworkInitializer
-                .getTelephonyServiceManager().getCarrierConfigServiceRegisterer().register(this);
         logd("CarrierConfigLoader has started");
         mSubscriptionInfoUpdater = subscriptionInfoUpdater;
         mHandler.sendEmptyMessage(EVENT_CHECK_SYSTEM_UPDATE);
@@ -732,6 +729,9 @@
             if (sInstance == null) {
                 sInstance = new CarrierConfigLoader(context,
                         PhoneFactory.getSubscriptionInfoUpdater(), Looper.myLooper());
+                // Make this service available through ServiceManager.
+                TelephonyFrameworkInitializer.getTelephonyServiceManager()
+                        .getCarrierConfigServiceRegisterer().register(sInstance);
             } else {
                 Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);
             }
@@ -892,9 +892,15 @@
     /** Returns the package name of a priveleged carrier app, or null if there is none. */
     @Nullable
     private String getCarrierPackageForPhoneId(int phoneId) {
-        List<String> carrierPackageNames = TelephonyManager.from(mContext)
+        List<String> carrierPackageNames;
+        final long token = Binder.clearCallingIdentity();
+        try {
+            carrierPackageNames = TelephonyManager.from(mContext)
                 .getCarrierPackageNamesForIntentAndPhone(
-                        new Intent(CarrierService.CARRIER_SERVICE_INTERFACE), phoneId);
+                    new Intent(CarrierService.CARRIER_SERVICE_INTERFACE), phoneId);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
         if (carrierPackageNames != null && carrierPackageNames.size() > 0) {
             return carrierPackageNames.get(0);
         } else {
diff --git a/src/com/android/phone/ImsRcsController.java b/src/com/android/phone/ImsRcsController.java
index bd6ba6b..90c9df4 100644
--- a/src/com/android/phone/ImsRcsController.java
+++ b/src/com/android/phone/ImsRcsController.java
@@ -17,7 +17,6 @@
 package com.android.phone;
 
 import android.Manifest;
-import android.app.ActivityManager;
 import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.Binder;
@@ -95,7 +94,7 @@
         mApp = app;
         TelephonyFrameworkInitializer
                 .getTelephonyServiceManager().getTelephonyImsServiceRegisterer().register(this);
-        mImsResolver = mApp.getImsResolver();
+        mImsResolver = ImsResolver.getInstance();
     }
 
     /**
@@ -276,9 +275,6 @@
             List<Uri> contactNumbers, IRcsUceControllerCallback c) {
         enforceAccessUserCapabilityExchangePermission("requestCapabilities");
         enforceReadContactsPermission("requestCapabilities");
-        if (!isCallingProcessInForeground(Binder.getCallingUid())) {
-            throw new SecurityException("The caller is not in the foreground.");
-        }
         final long token = Binder.clearCallingIdentity();
         try {
             UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
@@ -300,9 +296,6 @@
             String callingFeatureId, Uri contactNumber, IRcsUceControllerCallback c) {
         enforceAccessUserCapabilityExchangePermission("requestAvailability");
         enforceReadContactsPermission("requestAvailability");
-        if (!isCallingProcessInForeground(Binder.getCallingUid())) {
-            throw new SecurityException("The caller is not in the foreground.");
-        }
         final long token = Binder.clearCallingIdentity();
         try {
             UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
@@ -414,6 +407,20 @@
         return pidfXml == null ? "none" : pidfXml;
     }
 
+    /**
+     * Remove UCE requests cannot be sent to the network status.
+     * @return true if this command is successful.
+     */
+    // Used for SHELL command only right now.
+    public boolean removeUceRequestDisallowedStatus(int subId) throws ImsException {
+        UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+                UceControllerManager.class);
+        if (uceCtrlManager == null) {
+            return false;
+        }
+        return uceCtrlManager.removeUceRequestDisallowedStatus();
+    }
+
     @Override
     public void registerUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c) {
         enforceReadPrivilegedPermission("registerUcePublishStateCallback");
@@ -668,19 +675,6 @@
     }
 
     /**
-     * Check if the calling process is in the foreground.
-     *
-     * @return true if the caller is in the foreground.
-     */
-    private boolean isCallingProcessInForeground(int uid) {
-        ActivityManager am = mApp.getSystemService(ActivityManager.class);
-        boolean isCallingProcessForeground = am != null
-                && am.getUidImportance(uid)
-                        == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
-        return isCallingProcessForeground;
-    }
-
-    /**
      * Retrieve ImsPhone instance.
      *
      * @param subId the subscription ID
diff --git a/src/com/android/phone/ImsUtil.java b/src/com/android/phone/ImsUtil.java
index 0825cfb..ba4ad38 100644
--- a/src/com/android/phone/ImsUtil.java
+++ b/src/com/android/phone/ImsUtil.java
@@ -165,7 +165,7 @@
     private static boolean getLastKnownRoamingState(int phoneId) {
         try {
             ImsPhone imsPhone = (ImsPhone) (PhoneFactory.getPhone(phoneId).getImsPhone());
-            return imsPhone.getRoamingState();
+            return imsPhone.getLastKnownRoamingState();
         } catch (NullPointerException | ClassCastException e) {
             return false;
         }
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index 4fb61f0..fb45f4c 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -565,9 +565,10 @@
                     .setChannelId(NotificationChannelController.CHANNEL_ID_CALL_FORWARD)
                     .setOnlyAlertOnce(isRefresh);
 
-            Intent intent = new Intent(Intent.ACTION_MAIN);
+            Intent intent = new Intent(TelecomManager.ACTION_SHOW_CALL_SETTINGS);
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-            intent.setClassName("com.android.phone", "com.android.phone.CallFeaturesSetting");
+            intent.setPackage(mContext.getResources().getString(
+                    R.string.call_settings_package_name));
             SubscriptionInfoHelper.addExtrasToIntent(
                     intent, mSubscriptionManager.getActiveSubscriptionInfo(subId));
             builder.setContentIntent(PendingIntent.getActivity(mContext, subId /* requestCode */,
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 7bb786d..130c775 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -57,6 +57,7 @@
 import android.widget.Toast;
 
 import com.android.ims.ImsFeatureBinderRepository;
+import com.android.internal.os.BinderCallsStats;
 import com.android.internal.telephony.CallManager;
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.MmiCode;
@@ -156,7 +157,6 @@
     CallNotifier notifier;
     CallerInfoCache callerInfoCache;
     NotificationMgr notificationMgr;
-    ImsResolver mImsResolver;
     TelephonyRcsService mTelephonyRcsService;
     public PhoneInterfaceManager phoneMgr;
     public ImsRcsController imsRcsController;
@@ -211,6 +211,7 @@
             new CarrierVvmPackageInstalledReceiver();
 
     private final SettingsObserver mSettingsObserver;
+    private BinderCallsStats.SettingsObserver mBinderCallsSettingsObserver;
 
     private static class EventSimStateChangedBag {
         final int mPhoneId;
@@ -406,10 +407,10 @@
                         R.string.config_ims_mmtel_package);
                 String defaultImsRcsPackage = getResources().getString(
                         R.string.config_ims_rcs_package);
-                mImsResolver = new ImsResolver(this, defaultImsMmtelPackage,
+                ImsResolver.make(this, defaultImsMmtelPackage,
                         defaultImsRcsPackage, PhoneFactory.getPhones().length,
                         new ImsFeatureBinderRepository());
-                mImsResolver.initialize();
+                ImsResolver.getInstance().initialize();
 
                 // With the IMS phone created, load static config.xml values from the phone process
                 // so that it can be provided to the ImsPhoneCallTracker.
@@ -531,6 +532,12 @@
                     SettingsConstants.HAC_KEY + "=" + (hac == SettingsConstants.HAC_ENABLED
                             ? SettingsConstants.HAC_VAL_ON : SettingsConstants.HAC_VAL_OFF));
         }
+
+        // Start tracking Binder latency for the phone process.
+        mBinderCallsSettingsObserver = new BinderCallsStats.SettingsObserver(
+            getApplicationContext(),
+            new BinderCallsStats(new BinderCallsStats.Injector()),
+            com.android.internal.os.BinderLatencyProto.Dims.TELEPHONY);
     }
 
     /**
@@ -556,10 +563,6 @@
         return PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subId));
     }
 
-    public ImsResolver getImsResolver() {
-        return mImsResolver;
-    }
-
     /* package */ CallManager getCallManager() {
         return mCM;
     }
@@ -1025,7 +1028,7 @@
         pw.println("ImsResolver:");
         pw.increaseIndent();
         try {
-            if (mImsResolver != null) mImsResolver.dump(fd, pw, args);
+            if (ImsResolver.getInstance() != null) ImsResolver.getInstance().dump(fd, pw, args);
         } catch (Exception e) {
             e.printStackTrace();
         }
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 127e08b..71abc31 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -108,7 +108,7 @@
 import android.telephony.UssdResponse;
 import android.telephony.VisualVoicemailSmsFilterSettings;
 import android.telephony.data.ApnSetting;
-import android.telephony.data.SlicingConfig;
+import android.telephony.data.NetworkSlicingConfig;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.gba.GbaAuthRequest;
 import android.telephony.gba.UaSecurityProtocolIdentifier;
@@ -140,6 +140,7 @@
 import com.android.internal.telephony.CallForwardInfo;
 import com.android.internal.telephony.CallManager;
 import com.android.internal.telephony.CallStateException;
+import com.android.internal.telephony.CallTracker;
 import com.android.internal.telephony.CarrierResolver;
 import com.android.internal.telephony.CellNetworkScanResult;
 import com.android.internal.telephony.CommandException;
@@ -355,6 +356,7 @@
     private ImsResolver mImsResolver;
     private UserManager mUserManager;
     private AppOpsManager mAppOps;
+    private PackageManager mPm;
     private MainThreadHandler mMainThreadHandler;
     private SubscriptionController mSubscriptionController;
     private SharedPreferences mTelephonySharedPreferences;
@@ -1645,8 +1647,8 @@
                     if (ar.exception == null && ar.result != null) {
                         request.result = ar.result;
                     } else {
-                        request.result = new IllegalArgumentException(
-                                "Failed to retrieve system selection channels");
+                        request.result = new IllegalStateException(
+                                "Failed to retrieve system selecton channels");
                         if (ar.result == null) {
                             loge("getSystemSelectionChannels: Empty response");
                         } else {
@@ -1937,24 +1939,24 @@
                     request = (MainThreadRequest) ar.userObj;
                     ResultReceiver result = (ResultReceiver) request.argument;
 
-                    SlicingConfig slicingConfig = null;
+                    NetworkSlicingConfig slicingConfig = null;
                     Bundle bundle = new Bundle();
                     int resultCode = 0;
                     if (ar.exception != null) {
                         Log.e(LOG_TAG, "Exception retrieving slicing configuration="
                                 + ar.exception);
-                        resultCode = TelephonyManager.SlicingException.ERROR_MODEM_ERROR;
+                        resultCode = TelephonyManager.NetworkSlicingException.ERROR_MODEM_ERROR;
                     } else if (ar.result == null) {
                         Log.w(LOG_TAG, "Timeout Waiting for slicing configuration!");
-                        resultCode = TelephonyManager.SlicingException.ERROR_TIMEOUT;
+                        resultCode = TelephonyManager.NetworkSlicingException.ERROR_TIMEOUT;
                     } else {
                         // use the result as returned
-                        resultCode = TelephonyManager.SlicingException.SUCCESS;
-                        slicingConfig = (SlicingConfig) ar.result;
+                        resultCode = TelephonyManager.NetworkSlicingException.SUCCESS;
+                        slicingConfig = (NetworkSlicingConfig) ar.result;
                     }
 
                     if (slicingConfig == null) {
-                        slicingConfig = new SlicingConfig();
+                        slicingConfig = new NetworkSlicingConfig();
                     }
                     bundle.putParcelable(TelephonyManager.KEY_SLICING_CONFIG_HANDLE, slicingConfig);
                     result.send(resultCode, bundle);
@@ -2087,7 +2089,7 @@
                 // Wait for at least timeoutInMs before returning null request result
                 long now = SystemClock.elapsedRealtime();
                 long deadline = now + timeoutInMs;
-                while (request == null && now < deadline) {
+                while (request.result == null && now < deadline) {
                     try {
                         request.wait(deadline - now);
                     } catch (InterruptedException e) {
@@ -2162,9 +2164,10 @@
     private PhoneInterfaceManager(PhoneGlobals app) {
         mApp = app;
         mCM = PhoneGlobals.getInstance().mCM;
-        mImsResolver = PhoneGlobals.getInstance().getImsResolver();
+        mImsResolver = ImsResolver.getInstance();
         mUserManager = (UserManager) app.getSystemService(Context.USER_SERVICE);
         mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
+        mPm = app.getSystemService(PackageManager.class);
         mMainThreadHandler = new MainThreadHandler();
         mSubscriptionController = SubscriptionController.getInstance();
         mTelephonySharedPreferences =
@@ -3102,6 +3105,7 @@
             return null;
         }
         int subId = phone.getSubId();
+        enforceCallingPackage(callingPackage, Binder.getCallingUid(), "getImeiForSlot");
         if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mApp, subId,
                 callingPackage, callingFeatureId, "getImeiForSlot")) {
             return null;
@@ -3247,6 +3251,26 @@
     //
 
     /**
+     * Make sure the caller is the calling package itself
+     *
+     * @throws SecurityException if the caller is not the calling package
+     */
+    private void enforceCallingPackage(String callingPackage, int callingUid, String message) {
+        int packageUid = -1;
+        PackageManager pm = mApp.getBaseContext().createContextAsUser(
+                UserHandle.getUserHandleForUid(callingUid), 0).getPackageManager();
+        try {
+            packageUid = pm.getPackageUid(callingPackage, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            // packageUid is -1
+        }
+        if (packageUid != callingUid) {
+            throw new SecurityException(message + ": Package " + callingPackage
+                    + " does not belong to " + callingUid);
+        }
+    }
+
+    /**
      * Make sure the caller has the MODIFY_PHONE_STATE permission.
      *
      * @throws SecurityException if the caller does not have the required permission
@@ -4488,7 +4512,9 @@
     public void setImsProvisioningStatusForCapability(int subId, int capability, int tech,
             boolean isProvisioned) {
         if (tech != ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN
-                && tech != ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+                && tech != ImsRegistrationImplBase.REGISTRATION_TECH_LTE
+                && tech != ImsRegistrationImplBase.REGISTRATION_TECH_NR
+                && tech != ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM) {
             throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
         }
         checkModifyPhoneStatePermission(subId, "setImsProvisioningStatusForCapability");
@@ -4498,6 +4524,12 @@
             if (!isImsProvisioningRequired(subId, capability, true)) {
                 return;
             }
+            if (tech == ImsRegistrationImplBase.REGISTRATION_TECH_NR
+                    || tech == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM) {
+                loge("setImsProvisioningStatusForCapability: called for technology that does "
+                        + "not support provisioning - " + tech);
+                return;
+            }
 
             // this capability requires provisioning, route to the correct API.
             ImsManager ims = ImsManager.getInstance(mApp, getSlotIndex(subId));
@@ -4525,7 +4557,7 @@
                     }
                     cacheMmTelCapabilityProvisioning(subId, capability, tech, isProvisioned);
                     try {
-                        ims.changeMmTelCapability(capability, tech, isProvisioned);
+                        ims.changeMmTelCapability(isProvisioned, capability, tech);
                     } catch (com.android.ims.ImsException e) {
                         loge("setImsProvisioningStatusForCapability: couldn't change UT capability"
                                 + ", Exception" + e.getMessage());
@@ -4547,7 +4579,9 @@
     @Override
     public boolean getImsProvisioningStatusForCapability(int subId, int capability, int tech) {
         if (tech != ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN
-                && tech != ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+                && tech != ImsRegistrationImplBase.REGISTRATION_TECH_LTE
+                && tech != ImsRegistrationImplBase.REGISTRATION_TECH_NR
+                && tech != ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM) {
             throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
         }
         enforceReadPrivilegedPermission("getProvisioningStatusForCapability");
@@ -4558,6 +4592,13 @@
                 return true;
             }
 
+            if (tech == ImsRegistrationImplBase.REGISTRATION_TECH_NR
+                    || tech == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM) {
+                loge("getImsProvisioningStatusForCapability: called for technology that does "
+                        + "not support provisioning - " + tech);
+                return true;
+            }
+
             ImsManager ims = ImsManager.getInstance(mApp, getSlotIndex(subId));
             switch (capability) {
                 case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE: {
@@ -4867,8 +4908,8 @@
      */
     @Override
     public int getDataNetworkType(String callingPackage, String callingFeatureId) {
-        return getDataNetworkTypeForSubscriber(getDefaultSubscription(), callingPackage,
-                callingFeatureId);
+        return getDataNetworkTypeForSubscriber(mSubscriptionController.getDefaultDataSubId(),
+                callingPackage, callingFeatureId);
     }
 
     /**
@@ -6341,7 +6382,11 @@
         TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
                 mApp, subId, "setAllowedNetworkTypesForReason");
         if (!TelephonyManager.isValidAllowedNetworkTypesReason(reason)) {
-            Rlog.e(LOG_TAG, "Invalid allowed network type reason: " + reason);
+            loge("setAllowedNetworkTypesForReason: Invalid allowed network type reason: " + reason);
+            return false;
+        }
+        if (!SubscriptionManager.isUsableSubscriptionId(subId)) {
+            loge("setAllowedNetworkTypesForReason: Invalid subscriptionId:" + subId);
             return false;
         }
 
@@ -6660,6 +6705,7 @@
 
     @Override
     public int checkCarrierPrivilegesForPackage(int subId, String pkgName) {
+        enforceReadPrivilegedPermission("checkCarrierPrivilegesForPackage");
         if (TextUtils.isEmpty(pkgName)) {
             return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
         }
@@ -6677,6 +6723,7 @@
 
     @Override
     public int checkCarrierPrivilegesForPackageAnyPhone(String pkgName) {
+        // TODO(b/186774706): Remove @RequiresPermission from TelephonyManager API
         if (TextUtils.isEmpty(pkgName))
             return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
         int result = TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
@@ -6700,6 +6747,7 @@
 
     @Override
     public List<String> getCarrierPackageNamesForIntentAndPhone(Intent intent, int phoneId) {
+        enforceReadPrivilegedPermission("getCarrierPackageNamesForIntentAndPhone");
         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
             loge("phoneId " + phoneId + " is not valid.");
             return null;
@@ -6714,6 +6762,7 @@
 
     @Override
     public List<String> getPackagesWithCarrierPrivileges(int phoneId) {
+        enforceReadPrivilegedPermission("getPackagesWithCarrierPrivileges");
         PackageManager pm = mApp.getPackageManager();
         List<String> privilegedPackages = new ArrayList<>();
         List<PackageInfo> packages = null;
@@ -9305,9 +9354,11 @@
         WorkSource workSource = getWorkSource(Binder.getCallingUid());
         final long identity = Binder.clearCallingIdentity();
         try {
-            List<RadioAccessSpecifier> specifiers =
-                    (List<RadioAccessSpecifier>) sendRequest(CMD_GET_SYSTEM_SELECTION_CHANNELS,
-                    null, subId, workSource);
+            Object result = sendRequest(CMD_GET_SYSTEM_SELECTION_CHANNELS, null, subId, workSource);
+            if (result instanceof IllegalStateException) {
+                throw (IllegalStateException) result;
+            }
+            List<RadioAccessSpecifier> specifiers = (List<RadioAccessSpecifier>) result;
             if (DBG) log("getSystemSelectionChannels: " + specifiers);
             return specifiers;
         } finally {
@@ -10204,6 +10255,32 @@
         }
     }
 
+    @Override
+    public void setDeviceToDeviceForceEnabled(boolean isForceEnabled) {
+        TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(),
+                "setDeviceToDeviceForceEnabled");
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            Arrays.stream(PhoneFactory.getPhones()).forEach(
+                    p -> {
+                        Phone thePhone = p.getImsPhone();
+                        if (thePhone != null && thePhone instanceof ImsPhone) {
+                            ImsPhone imsPhone = (ImsPhone) thePhone;
+                            CallTracker tracker = imsPhone.getCallTracker();
+                            if (tracker != null && tracker instanceof ImsPhoneCallTracker) {
+                                ImsPhoneCallTracker imsPhoneCallTracker =
+                                        (ImsPhoneCallTracker) tracker;
+                                imsPhoneCallTracker.setDeviceToDeviceForceEnabled(isForceEnabled);
+                            }
+                        }
+                    }
+            );
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     /**
      * Gets the config of RCS VoLTE single registration enabled for the device.
      */
@@ -10425,6 +10502,23 @@
         }
     }
 
+    /**
+     * Remove UCE requests cannot be sent to the network status.
+     */
+    // Used for SHELL command only right now.
+    @Override
+    public boolean removeUceRequestDisallowedStatus(int subId) {
+        TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(), "uceRemoveDisallowedStatus");
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return mApp.imsRcsController.removeUceRequestDisallowedStatus(subId);
+        } catch (ImsException e) {
+            throw new ServiceSpecificException(e.getCode(), e.getMessage());
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
 
     @Override
     public void setSignalStrengthUpdateRequest(int subId, SignalStrengthUpdateRequest request,
diff --git a/src/com/android/phone/RcsProvisioningMonitor.java b/src/com/android/phone/RcsProvisioningMonitor.java
index 9e30728..4c5a8e9 100644
--- a/src/com/android/phone/RcsProvisioningMonitor.java
+++ b/src/com/android/phone/RcsProvisioningMonitor.java
@@ -543,9 +543,13 @@
                     == ProvisioningManager.STATUS_CAPABLE) {
                 try {
                     RcsConfig rcsConfig = new RcsConfig(getConfig(subId));
-                    return rcsConfig.isRcsVolteSingleRegistrationSupported();
+                    return rcsConfig.isRcsVolteSingleRegistrationSupported(
+                            mPhone.getPhone(subId).getServiceState().getRoaming());
                 } catch (IllegalArgumentException e) {
                     logd("fail to get rcs config for sub:" + subId);
+                } catch (NullPointerException e) {
+                    // should not happen
+                    logd("fail to get roaming state for sub: " + subId);
                 }
             }
         }
diff --git a/src/com/android/phone/SimPhonebookProvider.java b/src/com/android/phone/SimPhonebookProvider.java
index 4a15950..b921398 100644
--- a/src/com/android/phone/SimPhonebookProvider.java
+++ b/src/com/android/phone/SimPhonebookProvider.java
@@ -16,6 +16,9 @@
 
 package com.android.phone;
 
+import static com.android.internal.telephony.IccProvider.STR_NEW_TAG;
+import static com.android.internal.telephony.IccProvider.STR_NEW_NUMBER;
+
 import android.Manifest;
 import android.annotation.TestApi;
 import android.content.ContentProvider;
@@ -662,8 +665,11 @@
     private boolean updateRecord(PhonebookArgs args, AdnRecord existingRecord, String pin2,
             String newName, String newPhone) {
         try {
+            ContentValues values = new ContentValues();
+            values.put(STR_NEW_TAG, newName);
+            values.put(STR_NEW_NUMBER, newPhone);
             return mIccPhoneBookSupplier.get().updateAdnRecordsInEfByIndexForSubscriber(
-                    args.subscriptionId, existingRecord.getEfid(), newName, newPhone,
+                    args.subscriptionId, existingRecord.getEfid(), values,
                     existingRecord.getRecId(),
                     pin2);
         } catch (RemoteException e) {
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index 8fc7e94..c83ea64 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -30,9 +30,12 @@
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.provider.BlockedNumberContract;
+import android.telephony.BarringInfo;
 import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.TelephonyRegistryManager;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.ImsException;
 import android.telephony.ims.RcsContactUceCapability;
@@ -41,6 +44,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.SparseArray;
 
 import com.android.ims.rcs.uce.util.FeatureTags;
 import com.android.internal.telephony.ITelephony;
@@ -129,6 +133,10 @@
     private static final String D2D_SUBCOMMAND = "d2d";
     private static final String D2D_SEND = "send";
     private static final String D2D_TRANSPORT = "transport";
+    private static final String D2D_SET_DEVICE_SUPPORT = "set-device-support";
+
+    private static final String BARRING_SUBCOMMAND = "barring";
+    private static final String BARRING_SEND_INFO = "send";
 
     private static final String RCS_UCE_COMMAND = "uce";
     private static final String UCE_GET_EAB_CONTACT = "get-eab-contact";
@@ -137,19 +145,29 @@
     private static final String UCE_SET_DEVICE_ENABLED = "set-device-enabled";
     private static final String UCE_OVERRIDE_PUBLISH_CAPS = "override-published-caps";
     private static final String UCE_GET_LAST_PIDF_XML = "get-last-publish-pidf";
+    private static final String UCE_REMOVE_REQUEST_DISALLOWED_STATUS =
+            "remove-request-disallowed-status";
 
     // Check if a package has carrier privileges on any SIM, regardless of subId/phoneId.
     private static final String HAS_CARRIER_PRIVILEGES_COMMAND = "has-carrier-privileges";
 
+    private static final String DISABLE_PHYSICAL_SUBSCRIPTION = "disable-physical-subscription";
+    private static final String ENABLE_PHYSICAL_SUBSCRIPTION = "enable-physical-subscription";
+
     private static final String THERMAL_MITIGATION_COMMAND = "thermal-mitigation";
     private static final String ALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND = "allow-package";
     private static final String DISALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND = "disallow-package";
 
+    private static final String GET_ALLOWED_NETWORK_TYPES_FOR_USER =
+            "get-allowed-network-types-for-users";
+    private static final String SET_ALLOWED_NETWORK_TYPES_FOR_USER =
+            "set-allowed-network-types-for-users";
     // Take advantage of existing methods that already contain permissions checks when possible.
     private final ITelephony mInterface;
 
     private SubscriptionManager mSubscriptionManager;
     private CarrierConfigManager mCarrierConfigManager;
+    private TelephonyRegistryManager mTelephonyRegistryManager;
     private Context mContext;
 
     private enum CcType {
@@ -243,6 +261,8 @@
                 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
         mSubscriptionManager = (SubscriptionManager)
                 context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+        mTelephonyRegistryManager = (TelephonyRegistryManager)
+                context.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
         mContext = context;
     }
 
@@ -275,6 +295,8 @@
                 return handleGbaCommand();
             case D2D_SUBCOMMAND:
                 return handleD2dCommand();
+            case BARRING_SUBCOMMAND:
+                return handleBarringCommand();
             case SINGLE_REGISTATION_CONFIG:
                 return handleSingleRegistrationConfigCommand();
             case RESTART_MODEM:
@@ -287,6 +309,13 @@
                 return handleHasCarrierPrivilegesCommand();
             case THERMAL_MITIGATION_COMMAND:
                 return handleThermalMitigationCommand();
+            case DISABLE_PHYSICAL_SUBSCRIPTION:
+                return handleEnablePhysicalSubscription(false);
+            case ENABLE_PHYSICAL_SUBSCRIPTION:
+                return handleEnablePhysicalSubscription(true);
+            case GET_ALLOWED_NETWORK_TYPES_FOR_USER:
+            case SET_ALLOWED_NETWORK_TYPES_FOR_USER:
+                return handleAllowedNetworkTypesCommand(cmd);
             default: {
                 return handleDefaultCommands(cmd);
             }
@@ -321,6 +350,10 @@
         pw.println("    Prepare for unattended reboot.");
         pw.println("  has-carrier-privileges [package]");
         pw.println("    Query carrier privilege status for a package. Prints true or false.");
+        pw.println("  get-allowed-network-types-for-users");
+        pw.println("    Get the Allowed Network Types.");
+        pw.println("  set-allowed-network-types-for-users");
+        pw.println("    Set the Allowed Network Types.");
         onHelpIms();
         onHelpUce();
         onHelpEmergencyNumber();
@@ -330,6 +363,8 @@
         onHelpGba();
         onHelpSrc();
         onHelpD2D();
+        onHelpDisableOrEnablePhysicalSubscription();
+        onHelpAllowedNetworkTypes();
     }
 
     private void onHelpD2D() {
@@ -349,6 +384,22 @@
         pw.println("  d2d transport TYPE");
         pw.println("    Forces the specified D2D transport TYPE to be active.  Use the");
         pw.println("    short class name of the transport; i.e. DtmfTransport or RtpTransport.");
+        pw.println("  d2d set-device-support true/default");
+        pw.println("    true - forces device support to be enabled for D2D.");
+        pw.println("    default - clear any previously set force-enable of D2D, reverting to ");
+        pw.println("    the current device's configuration.");
+    }
+
+    private void onHelpBarring() {
+        PrintWriter pw = getOutPrintWriter();
+        pw.println("Barring Commands:");
+        pw.println("  barring send -s SLOT_ID -b BARRING_TYPE -c IS_CONDITIONALLY_BARRED"
+                + " -t CONDITIONAL_BARRING_TIME_SECS");
+        pw.println("    Notifies of a barring info change for the specified slot id.");
+        pw.println("    BARRING_TYPE: 0 for BARRING_TYPE_NONE");
+        pw.println("    BARRING_TYPE: 1 for BARRING_TYPE_UNCONDITIONAL");
+        pw.println("    BARRING_TYPE: 2 for BARRING_TYPE_CONDITIONAL");
+        pw.println("    BARRING_TYPE: -1 for BARRING_TYPE_UNKNOWN");
     }
 
     private void onHelpIms() {
@@ -423,6 +474,8 @@
         pw.println("  uce get-last-publish-pidf [-s SLOT_ID]");
         pw.println("    Get the PIDF XML included in the last SIP PUBLISH, or \"none\" if no ");
         pw.println("    PUBLISH is active");
+        pw.println("  uce remove-request-disallowed-status [-s SLOT_ID]");
+        pw.println("    Remove the UCE is disallowed to execute UCE requests status");
     }
 
     private void onHelpNumberVerification() {
@@ -446,6 +499,15 @@
                 + "mitigation.");
     }
 
+    private void onHelpDisableOrEnablePhysicalSubscription() {
+        PrintWriter pw = getOutPrintWriter();
+        pw.println("Disable or enable a physical subscription");
+        pw.println("  disable-physical-subscription SUB_ID");
+        pw.println("    Disable the physical subscription with the provided subId, if allowed.");
+        pw.println("  enable-physical-subscription SUB_ID");
+        pw.println("    Enable the physical subscription with the provided subId, if allowed.");
+    }
+
     private void onHelpDataTestMode() {
         PrintWriter pw = getOutPrintWriter();
         pw.println("Mobile Data Test Mode Commands:");
@@ -565,6 +627,30 @@
         pw.println("          is specified, it will choose the default voice SIM slot.");
     }
 
+    private void onHelpAllowedNetworkTypes() {
+        PrintWriter pw = getOutPrintWriter();
+        pw.println("Allowed Network Types Commands:");
+        pw.println("  get-allowed-network-types-for-users [-s SLOT_ID]");
+        pw.println("    Print allowed network types value.");
+        pw.println("    Options are:");
+        pw.println("      -s: The SIM slot ID to read allowed network types value for. If no");
+        pw.println("          option is specified, it will choose the default voice SIM slot.");
+        pw.println("  set-allowed-network-types-for-users [-s SLOT_ID] [NETWORK_TYPES_BITMASK]");
+        pw.println("    Sets allowed network types to NETWORK_TYPES_BITMASK.");
+        pw.println("    Options are:");
+        pw.println("      -s: The SIM slot ID to set allowed network types value for. If no");
+        pw.println("          option is specified, it will choose the default voice SIM slot.");
+        pw.println("    NETWORK_TYPES_BITMASK specifies the new network types value and this type");
+        pw.println("      is bitmask in binary format. Reference the NetworkTypeBitMask");
+        pw.println("      at TelephonyManager.java");
+        pw.println("      For example:");
+        pw.println("        NR only                    : 10000000000000000000");
+        pw.println("        NR|LTE                     : 11000001000000000000");
+        pw.println("        NR|LTE|CDMA|EVDO|GSM|WCDMA : 11001111101111111111");
+        pw.println("        LTE|CDMA|EVDO|GSM|WCDMA    : 01001111101111111111");
+        pw.println("        LTE only                   : 01000001000000000000");
+    }
+
     private int handleImsCommand() {
         String arg = getNextArg();
         if (arg == null) {
@@ -756,6 +842,41 @@
         return -1;
     }
 
+    private boolean subIsEsim(int subId) {
+        SubscriptionInfo info = mSubscriptionManager.getActiveSubscriptionInfo(subId);
+        if (info != null) {
+            return info.isEmbedded();
+        }
+        return false;
+    }
+
+    private int handleEnablePhysicalSubscription(boolean enable) {
+        PrintWriter errPw = getErrPrintWriter();
+        int subId = 0;
+        try {
+            subId = Integer.parseInt(getNextArgRequired());
+        } catch (NumberFormatException e) {
+            errPw.println((enable ? "enable" : "disable")
+                    + "-physical-subscription requires an integer as a subId.");
+            return -1;
+        }
+        // Verify that the user is allowed to run the command. Only allowed in rooted device in a
+        // non user build.
+        if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
+            errPw.println("cc: Permission denied.");
+            return -1;
+        }
+        // Verify that the subId represents a physical sub
+        if (subIsEsim(subId)) {
+            errPw.println("SubId " + subId + " is not for a physical subscription");
+            return -1;
+        }
+        Log.d(LOG_TAG, (enable ? "Enabling" : "Disabling")
+                + " physical subscription with subId=" + subId);
+        mSubscriptionManager.setUiccApplicationsEnabled(subId, enable);
+        return 0;
+    }
+
     private int handleThermalMitigationCommand() {
         String arg = getNextArg();
         String packageName = getNextArg();
@@ -800,6 +921,9 @@
             case D2D_TRANSPORT: {
                 return handleD2dTransportCommand();
             }
+            case D2D_SET_DEVICE_SUPPORT: {
+                return handleD2dDeviceSupportedCommand();
+            }
         }
 
         return -1;
@@ -863,6 +987,113 @@
         }
         return 0;
     }
+    private int handleBarringCommand() {
+        String arg = getNextArg();
+        if (arg == null) {
+            onHelpBarring();
+            return 0;
+        }
+
+        switch (arg) {
+            case BARRING_SEND_INFO: {
+                return handleBarringSendCommand();
+            }
+        }
+        return -1;
+    }
+
+    private int handleBarringSendCommand() {
+        PrintWriter errPw = getErrPrintWriter();
+        int slotId = getDefaultSlot();
+        int subId = SubscriptionManager.getSubId(slotId)[0];
+        @BarringInfo.BarringServiceInfo.BarringType int barringType =
+                BarringInfo.BarringServiceInfo.BARRING_TYPE_UNCONDITIONAL;
+        boolean isConditionallyBarred = false;
+        int conditionalBarringTimeSeconds = 0;
+
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            switch (opt) {
+                case "-s": {
+                    try {
+                        slotId = Integer.parseInt(getNextArgRequired());
+                        subId = SubscriptionManager.getSubId(slotId)[0];
+                    } catch (NumberFormatException e) {
+                        errPw.println("barring send requires an integer as a SLOT_ID.");
+                        return -1;
+                    }
+                    break;
+                }
+                case "-b": {
+                    try {
+                        barringType = Integer.parseInt(getNextArgRequired());
+                        if (barringType < -1 || barringType > 2) {
+                            throw new NumberFormatException();
+                        }
+
+                    } catch (NumberFormatException e) {
+                        errPw.println("barring send requires an integer in range [-1,2] as "
+                                + "a BARRING_TYPE.");
+                        return -1;
+                    }
+                    break;
+                }
+                case "-c": {
+                    try {
+                        isConditionallyBarred = Boolean.parseBoolean(getNextArgRequired());
+                    } catch (Exception e) {
+                        errPw.println("barring send requires a boolean after -c indicating"
+                                + " conditional barring");
+                        return -1;
+                    }
+                    break;
+                }
+                case "-t": {
+                    try {
+                        conditionalBarringTimeSeconds = Integer.parseInt(getNextArgRequired());
+                    } catch (NumberFormatException e) {
+                        errPw.println("barring send requires an integer for time of barring"
+                                + " in seconds after -t for conditional barring");
+                        return -1;
+                    }
+                    break;
+                }
+            }
+        }
+        SparseArray<BarringInfo.BarringServiceInfo> barringServiceInfos = new SparseArray<>();
+        BarringInfo.BarringServiceInfo bsi = new BarringInfo.BarringServiceInfo(
+                barringType, isConditionallyBarred, 0, conditionalBarringTimeSeconds);
+        barringServiceInfos.append(0, bsi);
+        BarringInfo barringInfo = new BarringInfo(null, barringServiceInfos);
+        try {
+            mTelephonyRegistryManager.notifyBarringInfoChanged(slotId, subId, barringInfo);
+        } catch (Exception e) {
+            Log.w(LOG_TAG, "barring send error: " + e.getMessage());
+            errPw.println("Exception: " + e.getMessage());
+            return -1;
+        }
+        return 0;
+    }
+
+    private int handleD2dDeviceSupportedCommand() {
+        PrintWriter errPw = getErrPrintWriter();
+
+        String arg = getNextArg();
+        if (arg == null) {
+            onHelpD2D();
+            return 0;
+        }
+
+        boolean isEnabled = "true".equals(arg.toLowerCase());
+        try {
+            mInterface.setDeviceToDeviceForceEnabled(isEnabled);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "Error forcing D2D enabled: " + e.getMessage());
+            errPw.println("Exception: " + e.getMessage());
+            return -1;
+        }
+        return 0;
+    }
 
     // ims set-ims-service
     private int handleImsSetServiceCommand() {
@@ -1860,6 +2091,8 @@
                 return handleUceOverridePublishCaps();
             case UCE_GET_LAST_PIDF_XML:
                 return handleUceGetPidfXml();
+            case UCE_REMOVE_REQUEST_DISALLOWED_STATUS:
+                return handleUceRemoveRequestDisallowedStatus();
         }
         return -1;
     }
@@ -1946,6 +2179,26 @@
         return 0;
     }
 
+    private int handleUceRemoveRequestDisallowedStatus() {
+        int subId = getSubId("uce remove-request-disallowed-status");
+        if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            Log.w(LOG_TAG, "uce remove-request-disallowed-status, Invalid subscription ID");
+            return -1;
+        }
+        boolean result;
+        try {
+            result = mInterface.removeUceRequestDisallowedStatus(subId);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "uce remove-request-disallowed-status, error " + e.getMessage());
+            return -1;
+        }
+        if (VDBG) {
+            Log.v(LOG_TAG, "uce remove-request-disallowed-status, returned: " + result);
+        }
+        getOutPrintWriter().println(result);
+        return 0;
+    }
+
     private int handleSrcSetTestEnabledCommand() {
         String enabledStr = getNextArg();
         if (enabledStr == null) {
@@ -2295,6 +2548,7 @@
         String packageName = getNextArgRequired();
 
         boolean hasCarrierPrivileges;
+        final long token = Binder.clearCallingIdentity();
         try {
             hasCarrierPrivileges =
                     mInterface.checkCarrierPrivilegesForPackageAnyPhone(packageName)
@@ -2303,9 +2557,122 @@
             Log.w(LOG_TAG, HAS_CARRIER_PRIVILEGES_COMMAND + " exception", e);
             getErrPrintWriter().println("Exception: " + e.getMessage());
             return -1;
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
 
         getOutPrintWriter().println(hasCarrierPrivileges);
         return 0;
     }
+
+    private int handleAllowedNetworkTypesCommand(String command) {
+        if (!checkShellUid()) {
+            return -1;
+        }
+
+        PrintWriter errPw = getErrPrintWriter();
+        String tag = command + ": ";
+        String opt;
+        int subId = -1;
+        Log.v(LOG_TAG, command + " start");
+
+        while ((opt = getNextOption()) != null) {
+            if (opt.equals("-s")) {
+                try {
+                    subId = slotStringToSubId(tag, getNextArgRequired());
+                    if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+                        errPw.println(tag + "No valid subscription found.");
+                        return -1;
+                    }
+                } catch (IllegalArgumentException e) {
+                    // Missing slot id
+                    errPw.println(tag + "SLOT_ID expected after -s.");
+                    return -1;
+                }
+            } else {
+                errPw.println(tag + "Unknown option " + opt);
+                return -1;
+            }
+        }
+
+        if (GET_ALLOWED_NETWORK_TYPES_FOR_USER.equals(command)) {
+            return handleGetAllowedNetworkTypesCommand(subId);
+        }
+        if (SET_ALLOWED_NETWORK_TYPES_FOR_USER.equals(command)) {
+            return handleSetAllowedNetworkTypesCommand(subId);
+        }
+        return -1;
+    }
+
+    private int handleGetAllowedNetworkTypesCommand(int subId) {
+        PrintWriter errPw = getErrPrintWriter();
+
+        long result = -1;
+        try {
+            if (mInterface != null) {
+                result = mInterface.getAllowedNetworkTypesForReason(subId,
+                        TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER);
+            } else {
+                throw new IllegalStateException("telephony service is null.");
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "getAllowedNetworkTypesForReason RemoteException" + e);
+            errPw.println(GET_ALLOWED_NETWORK_TYPES_FOR_USER + "RemoteException " + e);
+            return -1;
+        }
+
+        getOutPrintWriter().println(TelephonyManager.convertNetworkTypeBitmaskToString(result));
+        return 0;
+    }
+
+    private int handleSetAllowedNetworkTypesCommand(int subId) {
+        PrintWriter errPw = getErrPrintWriter();
+
+        String bitmaskString = getNextArg();
+        if (TextUtils.isEmpty(bitmaskString)) {
+            errPw.println(SET_ALLOWED_NETWORK_TYPES_FOR_USER + " No NETWORK_TYPES_BITMASK");
+            return -1;
+        }
+        long allowedNetworkTypes = convertNetworkTypeBitmaskFromStringToLong(bitmaskString);
+        if (allowedNetworkTypes < 0) {
+            errPw.println(SET_ALLOWED_NETWORK_TYPES_FOR_USER + " No valid NETWORK_TYPES_BITMASK");
+            return -1;
+        }
+        boolean result = false;
+        try {
+            if (mInterface != null) {
+                result = mInterface.setAllowedNetworkTypesForReason(subId,
+                        TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER, allowedNetworkTypes);
+            } else {
+                throw new IllegalStateException("telephony service is null.");
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "setAllowedNetworkTypesForReason RemoteException" + e);
+            errPw.println(SET_ALLOWED_NETWORK_TYPES_FOR_USER + " RemoteException " + e);
+            return -1;
+        }
+
+        String resultMessage = SET_ALLOWED_NETWORK_TYPES_FOR_USER + " failed";
+        if (result) {
+            resultMessage = SET_ALLOWED_NETWORK_TYPES_FOR_USER + " completed";
+        }
+        getOutPrintWriter().println(resultMessage);
+        return 0;
+    }
+
+    private long convertNetworkTypeBitmaskFromStringToLong(String bitmaskString) {
+        if (TextUtils.isEmpty(bitmaskString)) {
+            return -1;
+        }
+        if (VDBG) {
+            Log.v(LOG_TAG, "AllowedNetworkTypes:" + bitmaskString
+                            + ", length: " + bitmaskString.length());
+        }
+        try {
+            return Long.parseLong(bitmaskString, 2);
+        } catch (NumberFormatException e) {
+            Log.e(LOG_TAG, "AllowedNetworkTypes: " + e);
+            return -1;
+        }
+    }
 }
diff --git a/src/com/android/phone/settings/RadioInfo.java b/src/com/android/phone/settings/RadioInfo.java
index 88de151..8c53971 100644
--- a/src/com/android/phone/settings/RadioInfo.java
+++ b/src/com/android/phone/settings/RadioInfo.java
@@ -56,6 +56,7 @@
 import android.telephony.CellSignalStrengthLte;
 import android.telephony.CellSignalStrengthWcdma;
 import android.telephony.DataSpecificRegistrationInfo;
+import android.telephony.data.NetworkSlicingConfig;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.PhysicalChannelConfig;
 import android.telephony.RadioAccessFamily;
@@ -245,6 +246,7 @@
     private TextView mNrAvailable;
     private TextView mNrState;
     private TextView mNrFrequency;
+    private TextView mNetworkSlicingConfig;
     private EditText mSmsc;
     private Switch mRadioPowerOnSwitch;
     private Button mCellInfoRefreshRateButton;
@@ -494,6 +496,7 @@
         mNrState = (TextView) findViewById(R.id.nr_state);
         mNrFrequency = (TextView) findViewById(R.id.nr_frequency);
         mPhyChanConfig = (TextView) findViewById(R.id.phy_chan_config);
+        mNetworkSlicingConfig = (TextView) findViewById(R.id.network_slicing_config);
 
         // hide 5G stats on devices that don't support 5G
         if ((mTelephonyManager.getSupportedRadioAccessFamily()
@@ -508,6 +511,8 @@
             mNrState.setVisibility(View.GONE);
             ((TextView) findViewById(R.id.nr_frequency_label)).setVisibility(View.GONE);
             mNrFrequency.setVisibility(View.GONE);
+            ((TextView) findViewById(R.id.network_slicing_config_label)).setVisibility(View.GONE);
+            mNetworkSlicingConfig.setVisibility(View.GONE);
         }
 
         mPreferredNetworkType = (Spinner) findViewById(R.id.preferredNetworkType);
@@ -1125,6 +1130,10 @@
             mNrState.setText(NetworkRegistrationInfo.nrStateToString(ss.getNrState()));
             mNrFrequency.setText(ServiceState.frequencyRangeToString(ss.getNrFrequencyRange()));
         }
+
+        NetworkSlicingConfig slicingConfig = new NetworkSlicingConfig();
+        mNetworkSlicingConfig.setText(slicingConfig.toString());
+
     }
 
     private void updateProperties() {
@@ -1331,7 +1340,7 @@
             new MenuItem.OnMenuItemClickListener() {
         public boolean onMenuItemClick(MenuItem item) {
             boolean isImsRegistered = mPhone.isImsRegistered();
-            boolean availableVolte = mPhone.isVolteEnabled();
+            boolean availableVolte = mPhone.isVoiceOverCellularImsEnabled();
             boolean availableWfc = mPhone.isWifiCallingEnabled();
             boolean availableVt = mPhone.isVideoEnabled();
             boolean availableUt = mPhone.isUtEnabled();
diff --git a/src/com/android/services/telephony/CallQualityManager.java b/src/com/android/services/telephony/CallQualityManager.java
deleted file mode 100644
index 262ce88..0000000
--- a/src/com/android/services/telephony/CallQualityManager.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2020 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;
-
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.SystemClock;
-import android.telecom.BluetoothCallQualityReport;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.SlidingWindowEventCounter;
-import com.android.phone.R;
-
-/**
- * class to handle call quality events that are received by telecom and telephony
- */
-public class CallQualityManager {
-    private static final String TAG = CallQualityManager.class.getCanonicalName();
-
-    /** notification ids */
-    public static final int BLUETOOTH_CHOPPY_VOICE_NOTIFICATION_ID = 700;
-    public static final String CALL_QUALITY_CHANNEL_ID = "CallQualityNotificationChannel";
-    public static final long NOTIFICATION_BACKOFF_TIME_MILLIS = 5L * 60 * 1000;
-    public static final int NUM_OCCURRENCES_THRESHOLD = 5;
-    public static final long TIME_WINDOW_MILLIS = 5 * 1000;
-
-    private final Context mContext;
-    private final NotificationChannel mNotificationChannel;
-    private final NotificationManager mNotificationManager;
-    private final SlidingWindowEventCounter mSlidingWindowEventCounter;
-
-    private long mNotificationLastTime;
-
-    public CallQualityManager(Context context) {
-        mContext = context;
-        mNotificationChannel = new NotificationChannel(CALL_QUALITY_CHANNEL_ID,
-                mContext.getString(R.string.call_quality_notification_name),
-                NotificationManager.IMPORTANCE_HIGH);
-        mNotificationManager = (NotificationManager)
-                mContext.getSystemService(Context.NOTIFICATION_SERVICE);
-        mNotificationManager.createNotificationChannel(mNotificationChannel);
-        //making sure at the start we qualify to show notifications
-        mNotificationLastTime =
-                SystemClock.elapsedRealtime() - NOTIFICATION_BACKOFF_TIME_MILLIS - 1;
-        mSlidingWindowEventCounter =
-                new SlidingWindowEventCounter(TIME_WINDOW_MILLIS, NUM_OCCURRENCES_THRESHOLD);
-    }
-
-    /**
-     * method that is called whenever a
-     * {@code BluetoothCallQualityReport.EVENT_SEND_BLUETOOTH_CALL_QUALITY_REPORT} is received
-     * @param extras Bundle that includes serialized {@code BluetoothCallQualityReport} parcelable
-     */
-    @VisibleForTesting
-    public void onBluetoothCallQualityReported(Bundle extras) {
-        if (extras == null) {
-            Log.d(TAG, "onBluetoothCallQualityReported: no extras provided");
-        }
-
-        BluetoothCallQualityReport callQualityReport = extras.getParcelable(
-                BluetoothCallQualityReport.EXTRA_BLUETOOTH_CALL_QUALITY_REPORT);
-
-        if (callQualityReport.isChoppyVoice()) {
-            onChoppyVoice();
-        }
-        // TODO: once other signals are also sent, we will add more actions here
-    }
-
-    /**
-     * method to post a notification to user suggesting ways to improve call quality in case of
-     * bluetooth choppy voice
-     */
-    @VisibleForTesting
-    public void onChoppyVoice() {
-        String title = "Call Quality Improvement";
-        Log.d(TAG, "Bluetooth choppy voice signal received.");
-        if (mSlidingWindowEventCounter.addOccurrence(SystemClock.elapsedRealtime())) {
-            timedNotify(title,
-                    mContext.getText(R.string.call_quality_notification_bluetooth_details));
-        }
-    }
-
-    // notify user only if you haven't in the last NOTIFICATION_BACKOFF_TIME_MILLIS milliseconds
-    private void timedNotify(String title, CharSequence details) {
-        if (!mContext.getResources().getBoolean(
-                R.bool.enable_bluetooth_call_quality_notification)) {
-            Log.d(TAG, "Bluetooth call quality notifications not enabled.");
-            return;
-        }
-        long now = SystemClock.elapsedRealtime();
-        if (now - mNotificationLastTime > NOTIFICATION_BACKOFF_TIME_MILLIS) {
-            int iconId = android.R.drawable.stat_notify_error;
-
-            Notification notification = new Notification.Builder(mContext)
-                    .setSmallIcon(iconId)
-                    .setWhen(System.currentTimeMillis())
-                    .setAutoCancel(true)
-                    .setContentTitle(title)
-                    .setContentText(details)
-                    .setStyle(new Notification.BigTextStyle().bigText(details))
-                    .setChannelId(CALL_QUALITY_CHANNEL_ID)
-                    .setOnlyAlertOnce(true)
-                    .build();
-
-            mNotificationManager.notify(TAG, BLUETOOTH_CHOPPY_VOICE_NOTIFICATION_ID, notification);
-            mNotificationLastTime = now;
-            Log.d(TAG, "Call quality signal received, showing notification");
-        } else {
-            Log.d(TAG, "Call quality signal received, but not showing notification, "
-                    + "as recently notified in the last "
-                    + NOTIFICATION_BACKOFF_TIME_MILLIS / 1000 + " seconds");
-        }
-    }
-
-    /**
-     * close the notifications that have been emitted during the call
-     */
-    public void clearNotifications() {
-        mNotificationManager.cancel(TAG, BLUETOOTH_CHOPPY_VOICE_NOTIFICATION_ID);
-    }
-}
diff --git a/src/com/android/services/telephony/CdmaConferenceController.java b/src/com/android/services/telephony/CdmaConferenceController.java
index 8523a5f..a076ec8 100644
--- a/src/com/android/services/telephony/CdmaConferenceController.java
+++ b/src/com/android/services/telephony/CdmaConferenceController.java
@@ -20,11 +20,14 @@
 import android.telecom.Connection;
 import android.telecom.DisconnectCause;
 import android.telecom.PhoneAccountHandle;
+import android.util.ArraySet;
 
 import com.android.phone.PhoneUtils;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Manages CDMA conference calls. CDMA conference calls are much more limited than GSM conference
@@ -83,6 +86,9 @@
 
     private final Handler mHandler = new Handler();
 
+    private final Set<CdmaConnection> mPendingAddConnections = Collections.synchronizedSet(
+            new ArraySet<>());
+
     public CdmaConferenceController(TelephonyConnectionService connectionService) {
         mConnectionService = connectionService;
     }
@@ -91,7 +97,7 @@
     private CdmaConference mConference;
 
     void add(final CdmaConnection connection) {
-        if (mCdmaConnections.contains(connection)) {
+        if (mCdmaConnections.contains(connection) || !mPendingAddConnections.add(connection)) {
             // Adding a duplicate realistically shouldn't happen.
             Log.w(this, "add - connection already tracked; connection=%s", connection);
             return;
@@ -140,6 +146,7 @@
 
     private void addInternal(CdmaConnection connection) {
         mCdmaConnections.add(connection);
+        mPendingAddConnections.remove(connection);
         connection.addTelephonyConnectionListener(mTelephonyConnectionListener);
         recalculateConference();
     }
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index b0b0303..64c008a 100755
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -30,13 +30,12 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.PersistableBundle;
-import android.telecom.BluetoothCallQualityReport;
 import android.telecom.CallAudioState;
+import android.telecom.CallDiagnostics;
 import android.telecom.CallScreeningService;
 import android.telecom.Conference;
 import android.telecom.Connection;
 import android.telecom.ConnectionService;
-import android.telecom.DiagnosticCall;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.StatusHints;
@@ -141,6 +140,7 @@
     private static final int MSG_REDIAL_CONNECTION_CHANGED = 20;
     private static final int MSG_REJECT = 21;
     private static final int MSG_DTMF_DONE = 22;
+    private static final int MSG_MEDIA_ATTRIBUTES_CHANGED = 23;
 
     private static final String JAPAN_COUNTRY_CODE_WITH_PLUS_SIGN = "+81";
     private static final String JAPAN_ISO_COUNTRY_CODE = "JP";
@@ -256,6 +256,10 @@
                     setAudioQuality(audioQuality);
                     break;
 
+                case MSG_MEDIA_ATTRIBUTES_CHANGED:
+                    refreshCodec();
+                    break;
+
                 case MSG_SET_CONFERENCE_PARTICIPANTS:
                     List<ConferenceParticipant> participants = (List<ConferenceParticipant>) msg.obj;
                     updateConferenceParticipants(participants);
@@ -598,6 +602,12 @@
         public void onAudioQualityChanged(int audioQuality) {
             mHandler.obtainMessage(MSG_SET_AUDIO_QUALITY, audioQuality).sendToTarget();
         }
+
+        @Override
+        public void onMediaAttributesChanged() {
+            mHandler.obtainMessage(MSG_MEDIA_ATTRIBUTES_CHANGED).sendToTarget();
+        }
+
         /**
          * Handles a change in the state of conference participant(s), as reported by the
          * {@link com.android.internal.telephony.Connection}.
@@ -887,8 +897,6 @@
     private final Set<TelephonyConnectionListener> mTelephonyListeners = Collections.newSetFromMap(
             new ConcurrentHashMap<TelephonyConnectionListener, Boolean>(8, 0.9f, 1));
 
-    private CallQualityManager mCallQualityManager;
-
     protected TelephonyConnection(com.android.internal.telephony.Connection originalConnection,
             String callId, @android.telecom.Call.Details.CallDirection int callDirection) {
         setCallDirection(callDirection);
@@ -898,15 +906,14 @@
         }
     }
 
+    @VisibleForTesting
+    protected TelephonyConnection() {
+        // Do nothing
+    }
+
     @Override
     public void onCallEvent(String event, Bundle extras) {
         switch (event) {
-            case BluetoothCallQualityReport.EVENT_BLUETOOTH_CALL_QUALITY_REPORT:
-                if (mCallQualityManager == null) {
-                    mCallQualityManager = new CallQualityManager(getPhone().getContext());
-                }
-                mCallQualityManager.onBluetoothCallQualityReported(extras);
-                break;
             case Connection.EVENT_DEVICE_TO_DEVICE_MESSAGE:
                 // A Device to device message is being sent by a CallDiagnosticService.
                 handleOutgoingDeviceToDeviceMessage(extras);
@@ -1236,6 +1243,8 @@
         Log.v(this, "performAnswer");
         if (isValidRingingCall() && getPhone() != null) {
             try {
+                mTelephonyConnectionService.maybeDisconnectCallsOnOtherSubs(
+                        getPhoneAccountHandle());
                 getPhone().acceptCall(videoState);
             } catch (CallStateException e) {
                 Log.e(this, e, "Failed to accept call.");
@@ -1687,7 +1696,7 @@
                 Connection.AUDIO_CODEC_NONE);
         if (newCodecType != oldCodecType) {
             newExtras.putInt(Connection.EXTRA_AUDIO_CODEC, newCodecType);
-            Log.i(this, "put audio codec:" + newCodecType);
+            Log.i(this, "refreshCodec: codec changed; old=%d, new=%d", oldCodecType, newCodecType);
             changed = true;
         }
         if (isImsConnection()) {
@@ -1695,7 +1704,8 @@
             float oldBitrate = newExtras.getFloat(Connection.EXTRA_AUDIO_CODEC_BITRATE_KBPS, 0.0f);
             if (Math.abs(newBitrate - oldBitrate) > THRESHOLD) {
                 newExtras.putFloat(Connection.EXTRA_AUDIO_CODEC_BITRATE_KBPS, newBitrate);
-                Log.i(this, "put audio bitrate:" + newBitrate);
+                Log.i(this, "refreshCodec: bitrate changed; old=%f, new=%f", oldBitrate,
+                        newBitrate);
                 changed = true;
             }
 
@@ -1704,7 +1714,8 @@
                     0.0f);
             if (Math.abs(newBandwidth - oldBandwidth) > THRESHOLD) {
                 newExtras.putFloat(Connection.EXTRA_AUDIO_CODEC_BANDWIDTH_KHZ, newBandwidth);
-                Log.i(this, "put audio bandwidth:" + newBandwidth);
+                Log.i(this, "refreshCodec: bandwidth changed; old=%f, new=%f", oldBandwidth,
+                        newBandwidth);
                 changed = true;
             }
         } else {
@@ -1715,7 +1726,7 @@
         }
 
         if (changed) {
-            Log.i(this, "Audio attribute, Codec:"
+            Log.i(this, "refreshCodec: Codec:"
                     + newExtras.getInt(Connection.EXTRA_AUDIO_CODEC, Connection.AUDIO_CODEC_NONE)
                     + ", Bitrate:"
                     + newExtras.getFloat(Connection.EXTRA_AUDIO_CODEC_BITRATE_KBPS, 0.0f)
@@ -2052,6 +2063,15 @@
     }
 
     /**
+     * Sets whether to treat this call as an emergency call or not.
+     * @param shouldTreatAsEmergencyCall
+     */
+    @VisibleForTesting
+    public void setShouldTreatAsEmergencyCall(boolean shouldTreatAsEmergencyCall) {
+        mTreatAsEmergencyCall = shouldTreatAsEmergencyCall;
+    }
+
+    /**
      * Un-sets the underlying radio connection.
      */
     void clearOriginalConnection() {
@@ -3200,9 +3220,6 @@
         setDisconnected(disconnectCause);
         notifyDisconnected(disconnectCause);
         notifyStateChanged(getState());
-        if (mCallQualityManager != null) {
-            mCallQualityManager.clearNotifications();
-        }
     }
 
     /**
@@ -3344,14 +3361,20 @@
         if (!getPhone().getContext().getResources().getBoolean(
                 R.bool.config_use_device_to_device_communication)) {
             Log.i(this, "maybeConfigureDeviceToDeviceCommunication: not using D2D.");
+            notifyD2DAvailabilityChanged(false);
             return;
         }
         if (!isImsConnection()) {
             Log.i(this, "maybeConfigureDeviceToDeviceCommunication: not an IMS connection.");
+            if (mCommunicator != null) {
+                mCommunicator = null;
+            }
+            notifyD2DAvailabilityChanged(false);
             return;
         }
         if (mTreatAsEmergencyCall || mIsNetworkIdentifiedEmergencyCall) {
             Log.i(this, "maybeConfigureDeviceToDeviceCommunication: emergency call; no D2D");
+            notifyD2DAvailabilityChanged(false);
             return;
         }
 
@@ -3405,10 +3428,22 @@
             addTelephonyConnectionListener(mD2DCallStateAdapter);
         } else {
             Log.i(this, "maybeConfigureDeviceToDeviceCommunication: no transports; disabled.");
+            notifyD2DAvailabilityChanged(false);
         }
     }
 
     /**
+     * Notifies upper layers of the availability of D2D communication.
+     * @param isAvailable {@code true} if D2D is available, {@code false} otherwise.
+     */
+    private void notifyD2DAvailabilityChanged(boolean isAvailable) {
+        Bundle extras = new Bundle();
+        extras.putBoolean(Connection.EXTRA_IS_DEVICE_TO_DEVICE_COMMUNICATION_AVAILABLE,
+                isAvailable);
+        putTelephonyExtras(extras);
+    }
+
+    /**
      * @return The D2D communication class, or {@code null} if not set up.
      */
     public @Nullable Communicator getCommunicator() {
@@ -3435,19 +3470,19 @@
 
             Integer dcMsgValue;
             switch (msg.getType()) {
-                case DiagnosticCall.MESSAGE_CALL_AUDIO_CODEC:
+                case CallDiagnostics.MESSAGE_CALL_AUDIO_CODEC:
                     dcMsgValue = MessageTypeAndValueHelper.CODEC_TO_DC_CODEC.getValue(
                             msg.getValue());
                     break;
-                case DiagnosticCall.MESSAGE_CALL_NETWORK_TYPE:
+                case CallDiagnostics.MESSAGE_CALL_NETWORK_TYPE:
                     dcMsgValue = MessageTypeAndValueHelper.RAT_TYPE_TO_DC_NETWORK_TYPE.getValue(
                             msg.getValue());
                     break;
-                case DiagnosticCall.MESSAGE_DEVICE_BATTERY_STATE:
+                case CallDiagnostics.MESSAGE_DEVICE_BATTERY_STATE:
                     dcMsgValue = MessageTypeAndValueHelper.BATTERY_STATE_TO_DC_BATTERY_STATE
                             .getValue(msg.getValue());
                     break;
-                case DiagnosticCall.MESSAGE_DEVICE_NETWORK_COVERAGE:
+                case CallDiagnostics.MESSAGE_DEVICE_NETWORK_COVERAGE:
                     dcMsgValue = MessageTypeAndValueHelper.COVERAGE_TO_DC_COVERAGE
                             .getValue(msg.getValue());
                     break;
@@ -3468,6 +3503,15 @@
     }
 
     /**
+     * Handles report from {@link Communicator} when the availability of D2D changes.
+     * @param isAvailable {@code true} if D2D is available, {@code false} if unavailable.
+     */
+    @Override
+    public void onD2DAvailabilitychanged(boolean isAvailable) {
+        notifyD2DAvailabilityChanged(isAvailable);
+    }
+
+    /**
      * Called by a {@link ConnectionService} to notify Telecom that a {@link Conference#onMerge()}
      * operation has started.
      */
@@ -3675,7 +3719,7 @@
     }
 
     /**
-     * Handles a device to device message which a {@link DiagnosticCall} wishes to send.
+     * Handles a device to device message which a {@link CallDiagnostics} wishes to send.
      * @param extras the call event extras bundle.
      */
     private void handleOutgoingDeviceToDeviceMessage(Bundle extras) {
@@ -3684,19 +3728,19 @@
 
         Integer internalMessageValue;
         switch (messageType) {
-            case DiagnosticCall.MESSAGE_CALL_AUDIO_CODEC:
+            case CallDiagnostics.MESSAGE_CALL_AUDIO_CODEC:
                 internalMessageValue = MessageTypeAndValueHelper.CODEC_TO_DC_CODEC.getKey(
                         messageValue);
                 break;
-            case DiagnosticCall.MESSAGE_CALL_NETWORK_TYPE:
+            case CallDiagnostics.MESSAGE_CALL_NETWORK_TYPE:
                 internalMessageValue = MessageTypeAndValueHelper.RAT_TYPE_TO_DC_NETWORK_TYPE.getKey(
                         messageValue);
                 break;
-            case DiagnosticCall.MESSAGE_DEVICE_BATTERY_STATE:
+            case CallDiagnostics.MESSAGE_DEVICE_BATTERY_STATE:
                 internalMessageValue = MessageTypeAndValueHelper.BATTERY_STATE_TO_DC_BATTERY_STATE
                         .getKey(messageValue);
                 break;
-            case DiagnosticCall.MESSAGE_DEVICE_NETWORK_COVERAGE:
+            case CallDiagnostics.MESSAGE_DEVICE_NETWORK_COVERAGE:
                 internalMessageValue = MessageTypeAndValueHelper.COVERAGE_TO_DC_COVERAGE
                         .getKey(messageValue);
                 break;
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index bc39ffc..824bb4b 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -84,6 +84,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Queue;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
@@ -95,7 +96,7 @@
  * Service for making GSM and CDMA connections.
  */
 public class TelephonyConnectionService extends ConnectionService {
-
+    private static final String LOG_TAG = TelephonyConnectionService.class.getSimpleName();
     // Timeout before we continue with the emergency call without waiting for DDS switch response
     // from the modem.
     private static final int DEFAULT_DATA_SWITCH_TIMEOUT_MS = 1000;
@@ -1258,10 +1259,15 @@
                 createConnectionFor(phone, originalConnection, false /* isOutgoing */,
                         request.getAccountHandle(), request.getTelecomCallId(),
                         request.isAdhocConferenceCall());
+
         handleIncomingRtt(request, originalConnection);
         if (connection == null) {
             return Connection.createCanceledConnection();
         } else {
+            // Add extra to call if answering this incoming call would cause an in progress call on
+            // another subscription to be disconnected.
+            maybeIndicateAnsweringWillDisconnect(connection, request.getAccountHandle());
+
             connection.setTtyEnabled(mDeviceState.isTtyModeEnabled(getApplicationContext()));
             return connection;
         }
@@ -1600,7 +1606,7 @@
         Phone imsPhone = phone.getImsPhone();
 
         return imsPhone != null
-                && (imsPhone.isVolteEnabled() || imsPhone.isWifiCallingEnabled())
+                && (imsPhone.isVoiceOverCellularImsEnabled() || imsPhone.isWifiCallingEnabled())
                 && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE);
     }
 
@@ -2533,18 +2539,22 @@
        getAllConnections().stream()
                .filter(f -> f instanceof TelephonyConnection)
                .forEach(t -> {
-                        TelephonyConnection tc = (TelephonyConnection) t;
-                        Communicator c = tc.getCommunicator();
-                        if (c == null) {
-                            Log.w(this, "sendTestDeviceToDeviceMessage: D2D not enabled");
-                            return;
-                        }
+                   TelephonyConnection tc = (TelephonyConnection) t;
+                   if (!tc.isImsConnection()) {
+                       Log.w(this, "sendTestDeviceToDeviceMessage: not an IMS connection");
+                       return;
+                   }
+                   Communicator c = tc.getCommunicator();
+                   if (c == null) {
+                       Log.w(this, "sendTestDeviceToDeviceMessage: D2D not enabled");
+                       return;
+                   }
 
-                        c.sendMessages(new HashSet<Communicator.Message>() {{
-                            add(new Communicator.Message(message, value));
-                        }});
+                   c.sendMessages(new HashSet<Communicator.Message>() {{
+                       add(new Communicator.Message(message, value));
+                   }});
 
-       });
+               });
     }
 
     /**
@@ -2582,4 +2592,79 @@
         }
         return origAccountHandle;
     }
+
+    /**
+     * For the passed in incoming {@link TelephonyConnection}, add
+     * {@link Connection#EXTRA_ANSWERING_DROPS_FG_CALL} if there are ongoing calls on another
+     * subscription (ie phone account handle) than the one passed in.
+     * @param connection The connection.
+     * @param phoneAccountHandle The {@link PhoneAccountHandle} the incoming call originated on;
+     *                           this is passed in because
+     *                           {@link Connection#getPhoneAccountHandle()} is not set until after
+     *                           {@link ConnectionService#onCreateIncomingConnection(
+     *                           PhoneAccountHandle, ConnectionRequest)} returns.
+     */
+    public void maybeIndicateAnsweringWillDisconnect(@NonNull TelephonyConnection connection,
+            @NonNull PhoneAccountHandle phoneAccountHandle) {
+        if (isCallPresentOnOtherSub(phoneAccountHandle)) {
+            Log.i(this, "maybeIndicateAnsweringWillDisconnect; answering call %s will cause a call "
+                    + "on another subscription to drop.", connection.getTelecomCallId());
+            Bundle extras = new Bundle();
+            extras.putBoolean(Connection.EXTRA_ANSWERING_DROPS_FG_CALL, true);
+            connection.putExtras(extras);
+        }
+    }
+
+    /**
+     * Checks to see if there are calls present on a sub other than the one passed in.
+     * @param incomingHandle The new incoming connection {@link PhoneAccountHandle}
+     */
+    private boolean isCallPresentOnOtherSub(@NonNull PhoneAccountHandle incomingHandle) {
+        return getAllConnections().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(), incomingHandle))
+                .count() > 0;
+    }
+
+    /**
+     * Where there are ongoing calls on another subscription other than the one specified,
+     * disconnect these calls.  This is used where there is an incoming call on one sub, but there
+     * are ongoing calls on another sub which need to be disconnected.
+     * @param incomingHandle The incoming {@link PhoneAccountHandle}.
+     */
+    public void maybeDisconnectCallsOnOtherSubs(@NonNull PhoneAccountHandle incomingHandle) {
+        Log.i(this, "maybeDisconnectCallsOnOtherSubs: check for calls not on %s", incomingHandle);
+        maybeDisconnectCallsOnOtherSubs(getAllConnections(), incomingHandle);
+    }
+
+    /**
+     * Used by {@link #maybeDisconnectCallsOnOtherSubs(PhoneAccountHandle)} to perform call
+     * disconnection.  This method exists as a convenience so that it is possible to unit test
+     * the core functionality.
+     * @param connections the calls to check.
+     * @param incomingHandle the incoming handle.
+     */
+    @VisibleForTesting
+    public static void maybeDisconnectCallsOnOtherSubs(@NonNull Collection<Connection> connections,
+            @NonNull PhoneAccountHandle incomingHandle) {
+        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(), incomingHandle))
+                .forEach(c -> {
+                    if (c instanceof TelephonyConnection) {
+                        TelephonyConnection tc = (TelephonyConnection) c;
+                        if (!tc.shouldTreatAsEmergencyCall()) {
+                            Log.i(LOG_TAG, "maybeDisconnectCallsOnOtherSubs: disconnect %s due to "
+                                    + "incoming call on other sub.", tc.getTelecomCallId());
+                            tc.onDisconnect();
+                        }
+                    }
+                });
+    }
 }
diff --git a/src/com/android/services/telephony/rcs/DelegateBinderStateManager.java b/src/com/android/services/telephony/rcs/DelegateBinderStateManager.java
index 9d2c5d6..1a016ee 100644
--- a/src/com/android/services/telephony/rcs/DelegateBinderStateManager.java
+++ b/src/com/android/services/telephony/rcs/DelegateBinderStateManager.java
@@ -19,6 +19,7 @@
 import android.telephony.ims.DelegateRegistrationState;
 import android.telephony.ims.DelegateRequest;
 import android.telephony.ims.FeatureTagState;
+import android.telephony.ims.SipDelegateConfiguration;
 import android.telephony.ims.SipDelegateConnection;
 import android.telephony.ims.SipDelegateImsConfiguration;
 import android.telephony.ims.SipDelegateManager;
@@ -52,6 +53,11 @@
          * The SipDelegate has notified telephony that the IMS configuration has changed.
          */
         void onImsConfigurationChanged(SipDelegateImsConfiguration config);
+
+        /**
+         * The SipDelegate has notified telephony that the IMS configuration has changed.
+         */
+        void onConfigurationChanged(SipDelegateConfiguration config);
     }
 
     /** Allow for mocks to be created for testing. */
diff --git a/src/com/android/services/telephony/rcs/DelegateStateTracker.java b/src/com/android/services/telephony/rcs/DelegateStateTracker.java
index 18ad98e..321c7ba 100644
--- a/src/com/android/services/telephony/rcs/DelegateStateTracker.java
+++ b/src/com/android/services/telephony/rcs/DelegateStateTracker.java
@@ -19,6 +19,7 @@
 import android.os.RemoteException;
 import android.telephony.ims.DelegateRegistrationState;
 import android.telephony.ims.FeatureTagState;
+import android.telephony.ims.SipDelegateConfiguration;
 import android.telephony.ims.SipDelegateImsConfiguration;
 import android.telephony.ims.aidl.ISipDelegate;
 import android.telephony.ims.aidl.ISipDelegateConnectionStateCallback;
@@ -159,6 +160,20 @@
         }
     }
 
+    /**
+     * THe underlying SipDelegate has reported that the IMS configuration has changed.
+     * @param config The config to be sent to the IMS application.
+     */
+    @Override
+    public void onConfigurationChanged(SipDelegateConfiguration config) {
+        logi("onImsConfigurationChanged: Sending new IMS configuration.");
+        try {
+            mAppStateCallback.onConfigurationChanged(config);
+        } catch (RemoteException e) {
+            logw("onImsConfigurationChanged: IMS application is dead: " + e);
+        }
+    }
+
     /** Write state about this tracker into the PrintWriter to be included in the dumpsys */
     public void dump(PrintWriter printWriter) {
         printWriter.println("Last reg state: " + mLastRegState);
diff --git a/src/com/android/services/telephony/rcs/MessageTransportStateTracker.java b/src/com/android/services/telephony/rcs/MessageTransportStateTracker.java
deleted file mode 100644
index daafeb2..0000000
--- a/src/com/android/services/telephony/rcs/MessageTransportStateTracker.java
+++ /dev/null
@@ -1,479 +0,0 @@
-/*
- * Copyright (C) 2020 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.rcs;
-
-import android.os.Binder;
-import android.os.RemoteException;
-import android.telephony.ims.DelegateMessageCallback;
-import android.telephony.ims.DelegateRegistrationState;
-import android.telephony.ims.FeatureTagState;
-import android.telephony.ims.SipDelegateImsConfiguration;
-import android.telephony.ims.SipDelegateManager;
-import android.telephony.ims.SipMessage;
-import android.telephony.ims.aidl.ISipDelegate;
-import android.telephony.ims.aidl.ISipDelegateMessageCallback;
-import android.telephony.ims.stub.SipDelegate;
-import android.util.LocalLog;
-import android.util.Log;
-
-import java.io.PrintWriter;
-import java.util.Set;
-import java.util.concurrent.Executor;
-import java.util.function.Consumer;
-
-/**
- * Tracks the SIP message path both from the IMS application to the SipDelegate and from the
- * SipDelegate back to the IMS Application.
- * <p>
- * Responsibilities include:
- * 1) Queue incoming and outgoing SIP messages and deliver to IMS application and SipDelegate in
- *        order. If there is an error delivering the message, notify the caller.
- * 2) TODO Perform basic validation of outgoing messages.
- * 3) TODO Record the status of ongoing SIP Dialogs and trigger the completion of pending
- *         consumers when they are finished or call closeDialog to clean up the SIP
- *         dialogs that did not complete within the allotted timeout time.
- * <p>
- * Note: This handles incoming binder calls, so all calls from other processes should be handled on
- * the provided Executor.
- */
-public class MessageTransportStateTracker implements DelegateBinderStateManager.StateCallback {
-    private static final String TAG = "MessageST";
-
-    /**
-     * Communicates the result of verifying whether a SIP message should be sent based on the
-     * contents of the SIP message as well as if the transport is in an available state for the
-     * intended recipient of the message.
-     */
-    private static class VerificationResult {
-        public static final VerificationResult SUCCESS = new VerificationResult();
-
-        /**
-         * If {@code true}, the requested SIP message has been verified to be sent to the remote. If
-         * {@code false}, the SIP message has failed verification and should not be sent to the
-         * result. The {@link #restrictedReason} field will contain the reason for the verification
-         * failure.
-         */
-        public final boolean isVerified;
-
-        /**
-         * The reason associated with why the SIP message was not verified and generated a
-         * {@code false} result for {@link #isVerified}.
-         */
-        public final int restrictedReason;
-
-        /**
-         * Communicates a verified result of success. Use {@link #SUCCESS} instead.
-         */
-        private VerificationResult() {
-            isVerified = true;
-            restrictedReason = SipDelegateManager.MESSAGE_FAILURE_REASON_UNKNOWN;
-        }
-
-        /**
-         * The result of verifying that the SIP Message should be sent.
-         * @param reason The reason associated with why the SIP message was not verified and
-         *               generated a {@code false} result for {@link #isVerified}.
-         */
-        VerificationResult(@SipDelegateManager.MessageFailureReason int reason) {
-            isVerified = false;
-            restrictedReason = reason;
-        }
-    }
-
-    // SipDelegateConnection(IMS Application) -> SipDelegate(ImsService)
-    private final ISipDelegate.Stub mSipDelegateConnection = new ISipDelegate.Stub() {
-        /**
-         * The IMS application is acknowledging that it has successfully received and processed an
-         * incoming SIP message sent by the SipDelegate in
-         * {@link ISipDelegateMessageCallback#onMessageReceived(SipMessage)}.
-         */
-        @Override
-        public void notifyMessageReceived(String viaTransactionId) {
-            long token = Binder.clearCallingIdentity();
-            try {
-                mExecutor.execute(() -> {
-                    if (mSipDelegate == null) {
-                        logw("notifyMessageReceived called when SipDelegate is not associated for "
-                                + "transaction id: " + viaTransactionId);
-                        return;
-                    }
-                    try {
-                        // TODO track the SIP Dialogs created/destroyed on the associated
-                        // SipDelegate.
-                        mSipDelegate.notifyMessageReceived(viaTransactionId);
-                    } catch (RemoteException e) {
-                        logw("SipDelegate not available when notifyMessageReceived was called "
-                                + "for transaction id: " + viaTransactionId);
-                    }
-                });
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        /**
-         * The IMS application is acknowledging that it received an incoming SIP message sent by the
-         * SipDelegate in {@link ISipDelegateMessageCallback#onMessageReceived(SipMessage)} but it
-         * was unable to process it.
-         */
-        @Override
-        public void notifyMessageReceiveError(String viaTransactionId, int reason) {
-            long token = Binder.clearCallingIdentity();
-            try {
-                mExecutor.execute(() -> {
-                    if (mSipDelegate == null) {
-                        logw("notifyMessageReceiveError called when SipDelegate is not associated "
-                                + "for transaction id: " + viaTransactionId);
-                        return;
-                    }
-                    try {
-                        // TODO track the SIP Dialogs created/destroyed on the associated
-                        // SipDelegate.
-                        mSipDelegate.notifyMessageReceiveError(viaTransactionId, reason);
-                    } catch (RemoteException e) {
-                        logw("SipDelegate not available when notifyMessageReceiveError was called "
-                                + "for transaction id: " + viaTransactionId);
-                    }
-                });
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        /**
-         * The IMS application is sending an outgoing SIP message to the SipDelegate to be processed
-         * and sent over the network.
-         */
-        @Override
-        public void sendMessage(SipMessage sipMessage, long configVersion) {
-            long token = Binder.clearCallingIdentity();
-            try {
-                mExecutor.execute(() -> {
-                    VerificationResult result = verifyOutgoingMessage(sipMessage);
-                    if (!result.isVerified) {
-                        notifyDelegateSendError("Outgoing messages restricted", sipMessage,
-                                result.restrictedReason);
-                        return;
-                    }
-                    try {
-                        // TODO track the SIP Dialogs created/destroyed on the associated
-                        // SipDelegate.
-                        mSipDelegate.sendMessage(sipMessage, configVersion);
-                        logi("sendMessage: message sent - " + sipMessage + ", configVersion: "
-                                + configVersion);
-                    } catch (RemoteException e) {
-                        notifyDelegateSendError("RemoteException: " + e, sipMessage,
-                                SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD);
-                    }
-                });
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        /**
-         * The SipDelegateConnection is requesting that the resources associated with an ongoing SIP
-         * dialog be released as the SIP dialog is now closed.
-         */
-        @Override
-        public void cleanupSession(String callId) {
-            long token = Binder.clearCallingIdentity();
-            try {
-                mExecutor.execute(() -> {
-                    if (mSipDelegate == null) {
-                        logw("closeDialog called when SipDelegate is not associated, callId: "
-                                + callId);
-                        return;
-                    }
-                    try {
-                        // TODO track the SIP Dialogs created/destroyed on the associated
-                        // SipDelegate.
-                        mSipDelegate.cleanupSession(callId);
-                    } catch (RemoteException e) {
-                        logw("SipDelegate not available when closeDialog was called "
-                                + "for call id: " + callId);
-                    }
-                });
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-    };
-
-    // SipDelegate(ImsService) -> SipDelegateConnection(IMS Application)
-    private final ISipDelegateMessageCallback.Stub mDelegateConnectionMessageCallback =
-            new ISipDelegateMessageCallback.Stub() {
-        /**
-         * An Incoming SIP Message has been received by the SipDelegate and is being routed
-         * to the IMS application for processing.
-         * <p>
-         * IMS application will call {@link ISipDelegate#notifyMessageReceived(String)} to
-         * acknowledge receipt of this incoming message.
-         */
-        @Override
-        public void onMessageReceived(SipMessage message) {
-            long token = Binder.clearCallingIdentity();
-            try {
-                mExecutor.execute(() -> {
-                    VerificationResult result = verifyIncomingMessage(message);
-                    if (!result.isVerified) {
-                        notifyAppReceiveError("Incoming messages restricted", message,
-                                result.restrictedReason);
-                        return;
-                    }
-                    try {
-                        // TODO track the SIP Dialogs created/destroyed on the associated
-                        //  SipDelegate.
-                        mAppCallback.onMessageReceived(message);
-                        logi("onMessageReceived: received " + message);
-                    } catch (RemoteException e) {
-                        notifyAppReceiveError("RemoteException: " + e, message,
-                                SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD);
-                    }
-                });
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        /**
-         * An outgoing SIP message sent previously by the SipDelegateConnection to the SipDelegate
-         * using {@link ISipDelegate#sendMessage(SipMessage, int)} as been successfully sent.
-         */
-        @Override
-        public void onMessageSent(String viaTransactionId) {
-            long token = Binder.clearCallingIdentity();
-            try {
-                mExecutor.execute(() -> {
-                    if (mSipDelegate == null) {
-                        logw("Unexpected state, onMessageSent called when SipDelegate is not "
-                                + "associated");
-                    }
-                    try {
-                        mAppCallback.onMessageSent(viaTransactionId);
-                    } catch (RemoteException e) {
-                        logw("Error sending onMessageSent to SipDelegateConnection, remote not"
-                                + "available for transaction ID: " + viaTransactionId);
-                    }
-                });
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        /**
-         * An outgoing SIP message sent previously by the SipDelegateConnection to the SipDelegate
-         * using {@link ISipDelegate#sendMessage(SipMessage, int)} failed to be sent.
-         */
-        @Override
-        public void onMessageSendFailure(String viaTransactionId, int reason) {
-            long token = Binder.clearCallingIdentity();
-            try {
-                mExecutor.execute(() -> {
-                    if (mSipDelegate == null) {
-                        logw("Unexpected state, onMessageSendFailure called when SipDelegate is not"
-                                + "associated");
-                    }
-                    try {
-                        mAppCallback.onMessageSendFailure(viaTransactionId, reason);
-                    } catch (RemoteException e) {
-                        logw("Error sending onMessageSendFailure to SipDelegateConnection, remote"
-                                + " not available for transaction ID: " + viaTransactionId);
-                    }
-                });
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-    };
-
-    private final ISipDelegateMessageCallback mAppCallback;
-    private final Executor mExecutor;
-    private final int mSubId;
-    private final LocalLog mLocalLog = new LocalLog(SipTransportController.LOG_SIZE);
-
-    private ISipDelegate mSipDelegate;
-    private Consumer<Boolean> mPendingClosedConsumer;
-    private int mDelegateClosingReason = -1;
-    private int mDelegateClosedReason = -1;
-
-    public MessageTransportStateTracker(int subId, Executor executor,
-            ISipDelegateMessageCallback appMessageCallback) {
-        mSubId = subId;
-        mAppCallback = appMessageCallback;
-        mExecutor = executor;
-    }
-
-    @Override
-    public void onRegistrationStateChanged(DelegateRegistrationState registrationState) {
-        // TODO: integrate registration changes to SipMessage verification checks.
-    }
-
-    @Override
-    public void onImsConfigurationChanged(SipDelegateImsConfiguration config) {
-        // Not needed for this Tracker
-    }
-
-    /**
-     * Open the transport and allow SIP messages to be sent/received on the delegate specified.
-     * @param delegate The delegate connection to send SIP messages to on the ImsService.
-     * @param deniedFeatureTags Feature tags that have been denied. Outgoing SIP messages relating
-     *         to these tags will be denied.
-     */
-    public void openTransport(ISipDelegate delegate, Set<FeatureTagState> deniedFeatureTags) {
-        mSipDelegate = delegate;
-        mDelegateClosingReason = -1;
-        mDelegateClosedReason = -1;
-        // TODO: integrate denied tags to SipMessage verification checks.
-    }
-
-    /** Dump state about this tracker that should be included in the dumpsys */
-    public void dump(PrintWriter printWriter) {
-        printWriter.println("Most recent logs:");
-        mLocalLog.dump(printWriter);
-    }
-
-    /**
-     * @return SipDelegate implementation to be sent to IMS application.
-     */
-    public ISipDelegate getDelegateConnection() {
-        return mSipDelegateConnection;
-    }
-
-    /**
-     * @return MessageCallback implementation to be sent to the ImsService.
-     */
-    public ISipDelegateMessageCallback getMessageCallback() {
-        return mDelegateConnectionMessageCallback;
-    }
-
-    /**
-     * Gradually close all SIP Dialogs by:
-     * 1) denying all new outgoing SIP Dialog requests with the reason specified and
-     * 2) only allowing existing SIP Dialogs to continue.
-     * <p>
-     * This will allow traffic to continue on existing SIP Dialogs until a BYE is sent and the
-     * SIP Dialogs are closed or a timeout is hit and {@link SipDelegate#closeDialog(String)} is
-     * forcefully called on all open SIP Dialogs.
-     * <p>
-     * Any outgoing out-of-dialog traffic on this transport will be denied with the provided reason.
-     * <p>
-     * Incoming out-of-dialog traffic will continue to be set up until the SipDelegate is fully
-     * closed.
-     * @param delegateClosingReason The reason code to return to
-     * {@link DelegateMessageCallback#onMessageSendFailure(String, int)} if a new out-of-dialog SIP
-     *         message is received while waiting for existing Dialogs.
-     * @param closedReason reason to return to new outgoing SIP messages via
-     *         {@link SipDelegate#notifyMessageReceiveError(String, int)} once the transport
-     *         transitions to the fully closed state.
-     * @param resultConsumer The consumer called when the message transport has been closed. It will
-     *         return {@code true} if the procedure completed successfully or {@link false} if the
-     *         transport needed to be closed forcefully due to the application not responding before
-     *         a timeout occurred.
-     */
-    public void closeGracefully(int delegateClosingReason, int closedReason,
-            Consumer<Boolean> resultConsumer) {
-        mDelegateClosingReason = delegateClosingReason;
-        mPendingClosedConsumer = resultConsumer;
-        mExecutor.execute(() -> {
-            // TODO: Track SIP Dialogs and complete when there are no SIP dialogs open anymore or
-            //  the timeout occurs.
-            mPendingClosedConsumer.accept(true);
-            mPendingClosedConsumer = null;
-            closeTransport(closedReason);
-        });
-    }
-
-    /**
-     * Close all ongoing SIP Dialogs immediately and respond to any incoming/outgoing messages with
-     * the provided reason.
-     * @param closedReason The failure reason to provide to incoming/outgoing SIP messages
-     *         if an attempt is made to send/receive a message after this method is called.
-     */
-    public void close(int closedReason) {
-        closeTransport(closedReason);
-    }
-
-    // Clean up all state related to the existing SipDelegate immediately.
-    private void closeTransport(int closedReason) {
-        // TODO: add logic to forcefully close open SIP dialogs once they are being tracked.
-        mSipDelegate = null;
-        if (mPendingClosedConsumer != null) {
-            mExecutor.execute(() -> {
-                logw("closeTransport: transport close forced with pending consumer.");
-                mPendingClosedConsumer.accept(false /*closedGracefully*/);
-                mPendingClosedConsumer = null;
-            });
-        }
-        mDelegateClosingReason = -1;
-        mDelegateClosedReason = closedReason;
-    }
-
-    private VerificationResult verifyOutgoingMessage(SipMessage message) {
-        if (mDelegateClosingReason > -1) {
-            return new VerificationResult(mDelegateClosingReason);
-        }
-        if (mDelegateClosedReason > -1) {
-            return new VerificationResult(mDelegateClosedReason);
-        }
-        if (mSipDelegate == null) {
-            logw("sendMessage called when SipDelegate is not associated." + message);
-            return new VerificationResult(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD);
-        }
-        return VerificationResult.SUCCESS;
-    }
-
-    private VerificationResult verifyIncomingMessage(SipMessage message) {
-        // Do not restrict incoming based on closing reason.
-        if (mDelegateClosedReason > -1) {
-            return new VerificationResult(mDelegateClosedReason);
-        }
-        return VerificationResult.SUCCESS;
-    }
-
-    private void notifyDelegateSendError(String logReason, SipMessage message, int reasonCode) {
-        // TODO parse SipMessage header for viaTransactionId.
-        logw("Error sending SipMessage[id: " + null + ", code: " + reasonCode + "] -> SipDelegate "
-                + "for reason: " + logReason);
-        try {
-            mAppCallback.onMessageSendFailure(null, reasonCode);
-        } catch (RemoteException e) {
-            logw("notifyDelegateSendError, SipDelegate is not available: " + e);
-        }
-    }
-
-    private void notifyAppReceiveError(String logReason, SipMessage message, int reasonCode) {
-        // TODO parse SipMessage header for viaTransactionId.
-        logw("Error sending SipMessage[id: " + null + ", code: " + reasonCode + "] -> "
-                + "SipDelegateConnection for reason: " + logReason);
-        try {
-            mSipDelegate.notifyMessageReceiveError(null, reasonCode);
-        } catch (RemoteException e) {
-            logw("notifyAppReceiveError, SipDelegate is not available: " + e);
-        }
-    }
-
-    private void logi(String log) {
-        Log.w(SipTransportController.LOG_TAG, TAG + "[" + mSubId + "] " + log);
-        mLocalLog.log("[I] " + log);
-    }
-
-    private void logw(String log) {
-        Log.w(SipTransportController.LOG_TAG, TAG + "[" + mSubId + "] " + log);
-        mLocalLog.log("[W] " + log);
-    }
-}
diff --git a/src/com/android/services/telephony/rcs/MessageTransportWrapper.java b/src/com/android/services/telephony/rcs/MessageTransportWrapper.java
new file mode 100644
index 0000000..0d4265a
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/MessageTransportWrapper.java
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) 2020 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.rcs;
+
+import android.os.Binder;
+import android.os.RemoteException;
+import android.telephony.ims.DelegateMessageCallback;
+import android.telephony.ims.DelegateRegistrationState;
+import android.telephony.ims.FeatureTagState;
+import android.telephony.ims.SipDelegateConfiguration;
+import android.telephony.ims.SipDelegateImsConfiguration;
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+import android.telephony.ims.aidl.ISipDelegate;
+import android.telephony.ims.aidl.ISipDelegateMessageCallback;
+import android.telephony.ims.stub.SipDelegate;
+import android.util.LocalLog;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.SipMessageParsingUtils;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.phone.RcsProvisioningMonitor;
+import com.android.services.telephony.rcs.validator.ValidationResult;
+
+import java.io.PrintWriter;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.function.Consumer;
+
+/**
+ * Wraps the SIP message path both from the IMS application to the SipDelegate and from the
+ * SipDelegate back to the IMS Application.
+ * <p>
+ * Queues incoming and outgoing SIP messages on an Executor and deliver to IMS application and
+ * SipDelegate in order. If there is an error delivering the message, the caller is notified.
+ * Uses {@link TransportSipMessageValidator} to track ongoing SIP dialogs and verify outgoing
+ * messages.
+ * <p>
+ * Note: This handles incoming binder calls, so all calls from other processes should be handled on
+ * the provided Executor.
+ */
+public class MessageTransportWrapper implements DelegateBinderStateManager.StateCallback {
+    private static final String TAG = "MessageTW";
+
+    // SipDelegateConnection(IMS Application) -> SipDelegate(ImsService)
+    private final ISipDelegate.Stub mSipDelegateConnection = new ISipDelegate.Stub() {
+        /**
+         * The IMS application is acknowledging that it has successfully received and processed an
+         * incoming SIP message sent by the SipDelegate in
+         * {@link ISipDelegateMessageCallback#onMessageReceived(SipMessage)}.
+         */
+        @Override
+        public void notifyMessageReceived(String viaTransactionId) {
+            long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> {
+                    if (mSipDelegate == null) {
+                        logw("notifyMessageReceived called when SipDelegate is not associated for "
+                                + "transaction id: " + viaTransactionId);
+                        return;
+                    }
+                    try {
+                        mSipSessionTracker.acknowledgePendingMessage(viaTransactionId);
+                        mSipDelegate.notifyMessageReceived(viaTransactionId);
+                    } catch (RemoteException e) {
+                        logw("SipDelegate not available when notifyMessageReceived was called "
+                                + "for transaction id: " + viaTransactionId);
+                    }
+                });
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        /**
+         * The IMS application is acknowledging that it received an incoming SIP message sent by the
+         * SipDelegate in {@link ISipDelegateMessageCallback#onMessageReceived(SipMessage)} but it
+         * was unable to process it.
+         */
+        @Override
+        public void notifyMessageReceiveError(String viaTransactionId, int reason) {
+            long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> {
+                    if (mSipDelegate == null) {
+                        logw("notifyMessageReceiveError called when SipDelegate is not associated "
+                                + "for transaction id: " + viaTransactionId);
+                        return;
+                    }
+                    try {
+                        mSipSessionTracker.notifyPendingMessageFailed(viaTransactionId);
+                        mSipDelegate.notifyMessageReceiveError(viaTransactionId, reason);
+                    } catch (RemoteException e) {
+                        logw("SipDelegate not available when notifyMessageReceiveError was called "
+                                + "for transaction id: " + viaTransactionId);
+                    }
+                });
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        /**
+         * The IMS application is sending an outgoing SIP message to the SipDelegate to be processed
+         * and sent over the network.
+         */
+        @Override
+        public void sendMessage(SipMessage sipMessage, long configVersion) {
+            long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> {
+                    ValidationResult result =
+                            mSipSessionTracker.verifyOutgoingMessage(sipMessage, configVersion);
+                    result = maybeOverrideValidationForTesting(result);
+                    if (!result.isValidated) {
+                        notifyDelegateSendError("Outgoing - " + result.logReason,
+                                sipMessage, result.restrictedReason);
+                        return;
+                    }
+                    try {
+                        if (mSipDelegate == null) {
+                            logw("sendMessage called when SipDelegate is not associated."
+                                    + sipMessage);
+                            notifyDelegateSendError("No SipDelegate", sipMessage,
+                                    SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD);
+
+                            return;
+                        }
+                        mSipDelegate.sendMessage(sipMessage, configVersion);
+                    } catch (RemoteException e) {
+                        notifyDelegateSendError("RemoteException: " + e, sipMessage,
+                                SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD);
+                    }
+                });
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        /**
+         * The SipDelegateConnection is requesting that the resources associated with an ongoing SIP
+         * dialog be released as the SIP dialog is now closed.
+         */
+        @Override
+        public void cleanupSession(String callId) {
+            long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> cleanupSessionInternal(callId));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+    };
+
+    // SipDelegate(ImsService) -> SipDelegateConnection(IMS Application)
+    private final ISipDelegateMessageCallback.Stub mDelegateConnectionMessageCallback =
+            new ISipDelegateMessageCallback.Stub() {
+        /**
+         * An Incoming SIP Message has been received by the SipDelegate and is being routed
+         * to the IMS application for processing.
+         * <p>
+         * IMS application will call {@link ISipDelegate#notifyMessageReceived(String)} to
+         * acknowledge receipt of this incoming message.
+         */
+        @Override
+        public void onMessageReceived(SipMessage message) {
+            long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> {
+                    ValidationResult result = mSipSessionTracker.verifyIncomingMessage(message);
+                    if (!result.isValidated) {
+                        notifyAppReceiveError("Incoming - " + result.logReason, message,
+                                result.restrictedReason);
+                        return;
+                    }
+                    try {
+                        mAppCallback.onMessageReceived(message);
+                    } catch (RemoteException e) {
+                        notifyAppReceiveError("RemoteException: " + e, message,
+                                SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD);
+                    }
+                });
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        /**
+         * An outgoing SIP message sent previously by the SipDelegateConnection to the SipDelegate
+         * using {@link ISipDelegate#sendMessage(SipMessage, long)} as been successfully sent.
+         */
+        @Override
+        public void onMessageSent(String viaTransactionId) {
+            long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> {
+                    if (mSipDelegate == null) {
+                        logw("Unexpected state, onMessageSent called when SipDelegate is not "
+                                + "associated");
+                    }
+                    try {
+                        mSipSessionTracker.acknowledgePendingMessage(viaTransactionId);
+                        mAppCallback.onMessageSent(viaTransactionId);
+                    } catch (RemoteException e) {
+                        logw("Error sending onMessageSent to SipDelegateConnection, remote not"
+                                + "available for transaction ID: " + viaTransactionId);
+                    }
+                });
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        /**
+         * An outgoing SIP message sent previously by the SipDelegateConnection to the SipDelegate
+         * using {@link ISipDelegate#sendMessage(SipMessage, long)} failed to be sent.
+         */
+        @Override
+        public void onMessageSendFailure(String viaTransactionId, int reason) {
+            long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> {
+                    if (mSipDelegate == null) {
+                        logw("Unexpected state, onMessageSendFailure called when SipDelegate is not"
+                                + "associated");
+                    }
+                    try {
+                        mSipSessionTracker.notifyPendingMessageFailed(viaTransactionId);
+                        mAppCallback.onMessageSendFailure(viaTransactionId, reason);
+                    } catch (RemoteException e) {
+                        logw("Error sending onMessageSendFailure to SipDelegateConnection, remote"
+                                + " not available for transaction ID: " + viaTransactionId);
+                    }
+                });
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+    };
+
+    /**
+     * Interface for injecting validator override dependencies for testing.
+     */
+    @VisibleForTesting
+    public interface ValidatorOverride {
+        /**
+         * @return {@code null} if the validation result should not be overridden, {@code true} if
+         * the validation result should always pass, {@code false} if the validation result should
+         * always fail.
+         */
+        Boolean getValidatorOverrideState();
+    }
+
+    private final ValidatorOverride mValidatorOverride;
+    private final ISipDelegateMessageCallback mAppCallback;
+    private final Executor mExecutor;
+    private final int mSubId;
+    private final TransportSipMessageValidator mSipSessionTracker;
+    private final LocalLog mLocalLog = new LocalLog(SipTransportController.LOG_SIZE);
+
+    private ISipDelegate mSipDelegate;
+
+    public MessageTransportWrapper(int subId, ScheduledExecutorService executor,
+            ISipDelegateMessageCallback appMessageCallback) {
+        mSubId = subId;
+        mAppCallback = appMessageCallback;
+        mExecutor = executor;
+        mSipSessionTracker = new TransportSipMessageValidator(subId, executor);
+        mValidatorOverride = () -> RcsProvisioningMonitor.getInstance()
+                .getImsFeatureValidationOverride(mSubId);
+    }
+
+    /**
+     * Mock out dependencies for unit testing.
+     */
+    @VisibleForTesting
+    public MessageTransportWrapper(int subId, ScheduledExecutorService executor,
+            ISipDelegateMessageCallback appMessageCallback,
+            TransportSipMessageValidator sipSessionTracker) {
+        mSubId = subId;
+        mAppCallback = appMessageCallback;
+        mExecutor = executor;
+        mSipSessionTracker = sipSessionTracker;
+        // Remove links to static methods calls querying overrides for testing.
+        mValidatorOverride = () -> null;
+    }
+
+    @Override
+    public void onRegistrationStateChanged(DelegateRegistrationState registrationState) {
+        mSipSessionTracker.onRegistrationStateChanged((callIds) -> {
+            for (String id : callIds)  {
+                cleanupSessionInternal(id);
+            }
+        }, registrationState);
+    }
+
+    @Override
+    public void onImsConfigurationChanged(SipDelegateImsConfiguration config) {
+        mSipSessionTracker.onImsConfigurationChanged(config);
+    }
+
+    @Override
+    public void onConfigurationChanged(SipDelegateConfiguration config) {
+        mSipSessionTracker.onConfigurationChanged(config);
+    }
+
+    /**
+     * Open the transport and allow SIP messages to be sent/received on the delegate specified.
+     * @param delegate The delegate connection to send SIP messages to on the ImsService.
+     * @param supportedFeatureTags Feature tags that are supported. Outgoing SIP messages relating
+     *                             to these tags will be allowed.
+     * @param deniedFeatureTags Feature tags that have been denied. Outgoing SIP messages relating
+     *         to these tags will be denied.
+     */
+    public void openTransport(ISipDelegate delegate, Set<String> supportedFeatureTags,
+            Set<FeatureTagState> deniedFeatureTags) {
+        logi("openTransport: delegate=" + delegate + ", supportedTags=" + supportedFeatureTags
+                + ", deniedTags=" + deniedFeatureTags);
+        mSipSessionTracker.onTransportOpened(supportedFeatureTags, deniedFeatureTags);
+        mSipDelegate = delegate;
+    }
+
+    /** Dump state about this tracker that should be included in the dumpsys */
+    public void dump(PrintWriter printWriter) {
+        IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
+        pw.println("Most recent logs:");
+        mLocalLog.dump(printWriter);
+        pw.println();
+        pw.println("Dialog Tracker:");
+        pw.increaseIndent();
+        mSipSessionTracker.dump(pw);
+        pw.decreaseIndent();
+    }
+
+    /**
+     * @return SipDelegate implementation to be sent to IMS application.
+     */
+    public ISipDelegate getDelegateConnection() {
+        return mSipDelegateConnection;
+    }
+
+    /**
+     * @return The remote application's message callback.
+     */
+    public ISipDelegateMessageCallback getAppMessageCallback() {
+        return mAppCallback;
+    }
+
+    /**
+     * @return MessageCallback implementation to be sent to the ImsService.
+     */
+    public ISipDelegateMessageCallback getMessageCallback() {
+        return mDelegateConnectionMessageCallback;
+    }
+
+    /**
+     * Gradually close all SIP Sessions by:
+     * 1) denying all new outgoing SIP Dialog requests with the reason specified and
+     * 2) only allowing existing SIP Sessions to continue.
+     * <p>
+     * This will allow traffic to continue on existing SIP Sessions until a BYE is sent and the
+     * corresponding SIP Dialogs are closed or a timeout is hit and
+     * {@link SipDelegate#cleanupSession(String)} (String)} is forcefully called on all open SIP
+     * sessions.
+     * <p>
+     * Any outgoing out-of-dialog traffic on this transport will be denied with the provided reason.
+     * <p>
+     * Incoming out-of-dialog traffic will continue to be set up until the SipDelegate is fully
+     * closed.
+     * @param delegateClosingReason The reason code to return to
+     * {@link DelegateMessageCallback#onMessageSendFailure(String, int)} if a new out-of-dialog SIP
+     *         message is received while waiting for existing Dialogs.
+     * @param closedReason reason to return to new outgoing SIP messages via
+     *         {@link SipDelegate#notifyMessageReceiveError(String, int)} once the transport
+     *         transitions to the fully closed state.
+     * @param resultConsumer The consumer called when the message transport has been closed. It will
+     *         return {@code true} if the procedure completed successfully or {@link false} if the
+     *         transport needed to be closed forcefully due to the application not responding before
+     *         a timeout occurred.
+     */
+    public void closeGracefully(int delegateClosingReason, int closedReason,
+            Consumer<Boolean> resultConsumer) {
+        logi("closeGracefully: closingReason=" + delegateClosingReason + ", closedReason="
+                + closedReason + ", resultConsumer(" + resultConsumer.hashCode() + ")");
+        mSipSessionTracker.closeSessionsGracefully((openCallIds) -> {
+            logi("closeGracefully resultConsumer(" + resultConsumer.hashCode()
+                    + "): open call IDs:{" + openCallIds + "}");
+            closeTransport(openCallIds);
+            // propagate event to the consumer
+            resultConsumer.accept(openCallIds.isEmpty() /*successfullyClosed*/);
+        }, delegateClosingReason, closedReason);
+    }
+
+    /**
+     * Close all ongoing SIP sessions immediately and respond to any incoming/outgoing messages with
+     * the provided reason.
+     * @param closedReason The failure reason to provide to incoming/outgoing SIP messages
+     *         if an attempt is made to send/receive a message after this method is called.
+     */
+    public void close(int closedReason) {
+        Set<String> openSessions = mSipSessionTracker.closeSessions(closedReason);
+        logi("close: closedReason=" + closedReason + "open call IDs:{" + openSessions + "}");
+        closeTransport(openSessions);
+    }
+
+    // Clean up all state related to the existing SipDelegate immediately.
+    private void closeTransport(Set<String> openCallIds) {
+        for (String id : openCallIds) {
+            cleanupSessionInternal(id);
+        }
+        mSipDelegate = null;
+    }
+
+    private void cleanupSessionInternal(String callId) {
+        logi("cleanupSessionInternal: clean up session with callId: " + callId);
+        try {
+            if (mSipDelegate == null) {
+                logw("cleanupSessionInternal: SipDelegate is not associated, callId: " + callId);
+            } else {
+                // This will close the transport, so call cleanup on ImsService first.
+                mSipDelegate.cleanupSession(callId);
+            }
+        } catch (RemoteException e) {
+            logw("cleanupSessionInternal: remote not available when cleanupSession was called "
+                    + "for call id: " + callId);
+        }
+        mSipSessionTracker.onSipSessionCleanup(callId);
+    }
+
+    private ValidationResult maybeOverrideValidationForTesting(ValidationResult result) {
+        Boolean isValidatedOverride = mValidatorOverride.getValidatorOverrideState();
+        if (isValidatedOverride == null) {
+            return result;
+        }
+        if (isValidatedOverride) {
+            return ValidationResult.SUCCESS;
+        } else if (result.isValidated) {
+            // if override is set to false and the original result was validated, return a new
+            // restricted result with UNKNOWN reason.
+            return new ValidationResult(SipDelegateManager.MESSAGE_FAILURE_REASON_UNKNOWN,
+                    "validation failed due to a testing override being set");
+        }
+        return result;
+    }
+
+    private void notifyDelegateSendError(String logReason, SipMessage message, int reasonCode) {
+        String transactionId = SipMessageParsingUtils.getTransactionId(message.getHeaderSection());
+        logi("Error sending SipMessage[id: " + transactionId + ", code: " + reasonCode
+                + "] -> SipDelegate for reason: " + logReason);
+        try {
+            mAppCallback.onMessageSendFailure(transactionId, reasonCode);
+        } catch (RemoteException e) {
+            logw("notifyDelegateSendError, SipDelegate is not available: " + e);
+        }
+    }
+
+    private void notifyAppReceiveError(String logReason, SipMessage message, int reasonCode) {
+        String transactionId = SipMessageParsingUtils.getTransactionId(message.getHeaderSection());
+        logi("Error sending SipMessage[id: " + transactionId + ", code: " + reasonCode + "] -> "
+                + "SipDelegateConnection for reason: " + logReason);
+        try {
+            mSipDelegate.notifyMessageReceiveError(transactionId, reasonCode);
+        } catch (RemoteException e) {
+            logw("notifyAppReceiveError, SipDelegate is not available: " + e);
+        }
+    }
+
+    private void logi(String log) {
+        Log.w(SipTransportController.LOG_TAG, TAG + "[" + mSubId + "] " + log);
+        mLocalLog.log("[I] " + log);
+    }
+
+    private void logw(String log) {
+        Log.w(SipTransportController.LOG_TAG, TAG + "[" + mSubId + "] " + log);
+        mLocalLog.log("[W] " + log);
+    }
+}
diff --git a/src/com/android/services/telephony/rcs/RcsFeatureController.java b/src/com/android/services/telephony/rcs/RcsFeatureController.java
index 3eefdb0..7834903 100644
--- a/src/com/android/services/telephony/rcs/RcsFeatureController.java
+++ b/src/com/android/services/telephony/rcs/RcsFeatureController.java
@@ -20,9 +20,7 @@
 import android.content.Context;
 import android.net.Uri;
 import android.telephony.ims.ImsException;
-import android.telephony.ims.ImsRcsManager;
 import android.telephony.ims.ImsReasonInfo;
-import android.telephony.ims.RegistrationManager;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
 import android.telephony.ims.aidl.IImsRegistrationCallback;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -135,6 +133,7 @@
                         logw("connectionReady returned null RcsFeatureManager");
                         return;
                     }
+                    logd("connectionReady");
                     try {
                         // May throw ImsException if for some reason the connection to the
                         // ImsService is gone.
@@ -153,6 +152,7 @@
                     if (reason == FeatureConnector.UNAVAILABLE_REASON_SERVER_UNAVAILABLE) {
                         loge("unexpected - connectionUnavailable due to server unavailable");
                     }
+                    logd("connectionUnavailable");
                     // Call before disabling connection to manager.
                     removeConnectionToService();
                     updateConnectionStatus(null /*manager*/);
@@ -411,6 +411,7 @@
     }
 
     private void setupConnectionToService(RcsFeatureManager manager) throws ImsException {
+        logd("setupConnectionToService");
         // Open persistent listener connection, sends RcsFeature#onFeatureReady.
         manager.openConnection();
         manager.updateCapabilities(mAssociatedSubId);
@@ -418,6 +419,7 @@
     }
 
     private void removeConnectionToService() {
+        logd("removeConnectionToService");
         RcsFeatureManager manager = getFeatureManager();
         if (manager != null) {
             manager.unregisterImsRegistrationCallback(
@@ -472,6 +474,10 @@
         }
     }
 
+    private void logd(String log) {
+        Log.d(LOG_TAG, getLogPrefix().append(log).toString());
+    }
+
     private void logw(String log) {
         Log.w(LOG_TAG, getLogPrefix().append(log).toString());
     }
diff --git a/src/com/android/services/telephony/rcs/SipDelegateBinderConnection.java b/src/com/android/services/telephony/rcs/SipDelegateBinderConnection.java
index 3f6f269..168a432 100644
--- a/src/com/android/services/telephony/rcs/SipDelegateBinderConnection.java
+++ b/src/com/android/services/telephony/rcs/SipDelegateBinderConnection.java
@@ -22,6 +22,7 @@
 import android.telephony.ims.DelegateRegistrationState;
 import android.telephony.ims.DelegateRequest;
 import android.telephony.ims.FeatureTagState;
+import android.telephony.ims.SipDelegateConfiguration;
 import android.telephony.ims.SipDelegateImsConfiguration;
 import android.telephony.ims.SipDelegateManager;
 import android.telephony.ims.aidl.IImsRegistration;
@@ -97,7 +98,8 @@
                     long token = Binder.clearCallingIdentity();
                     try {
                         mExecutor.execute(() -> {
-                            logi("onImsConfigurationChanged");
+                            logi("onImsConfigurationChanged: version="
+                                    + registeredSipConfig.getVersion());
                             for (StateCallback c : mStateCallbacks) {
                                 c.onImsConfigurationChanged(registeredSipConfig);
                             }
@@ -108,6 +110,22 @@
                 }
 
                 @Override
+                public void onConfigurationChanged(
+                        SipDelegateConfiguration registeredSipConfig) {
+                    long token = Binder.clearCallingIdentity();
+                    try {
+                        mExecutor.execute(() -> {
+                            logi("onConfigurationChanged");
+                            for (StateCallback c : mStateCallbacks) {
+                                c.onConfigurationChanged(registeredSipConfig);
+                            }
+                        });
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
+
+                @Override
                 public void onDestroyed(int reason) {
                     long token = Binder.clearCallingIdentity();
                     try {
diff --git a/src/com/android/services/telephony/rcs/SipDelegateController.java b/src/com/android/services/telephony/rcs/SipDelegateController.java
index 2d6d4f0..30edca1 100644
--- a/src/com/android/services/telephony/rcs/SipDelegateController.java
+++ b/src/com/android/services/telephony/rcs/SipDelegateController.java
@@ -28,6 +28,7 @@
 import android.telephony.ims.aidl.ISipTransport;
 import android.telephony.ims.stub.DelegateConnectionStateCallback;
 import android.telephony.ims.stub.SipDelegate;
+import android.util.ArraySet;
 import android.util.LocalLog;
 import android.util.Log;
 import android.util.Pair;
@@ -42,6 +43,7 @@
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ScheduledExecutorService;
+import java.util.stream.Collectors;
 
 /**
  * Created when an IMS application wishes to open up a {@link SipDelegateConnection} and manages the
@@ -78,7 +80,7 @@
     private final String mPackageName;
     private final DelegateRequest mInitialRequest;
     private final ScheduledExecutorService mExecutorService;
-    private final MessageTransportStateTracker mMessageTransportStateTracker;
+    private final MessageTransportWrapper mMessageTransportWrapper;
     private final DelegateStateTracker mDelegateStateTracker;
     private final DelegateBinderStateManager.Factory mBinderConnectionFactory;
     private final LocalLog mLocalLog = new LocalLog(SipTransportController.LOG_SIZE);
@@ -97,10 +99,10 @@
         mExecutorService = executorService;
         mBinderConnectionFactory = new BinderConnectionFactory(transportImpl, registrationImpl);
 
-        mMessageTransportStateTracker = new MessageTransportStateTracker(mSubId, executorService,
+        mMessageTransportWrapper = new MessageTransportWrapper(mSubId, executorService,
                 messageCallback);
         mDelegateStateTracker = new DelegateStateTracker(mSubId, stateCallback,
-                mMessageTransportStateTracker.getDelegateConnection());
+                mMessageTransportWrapper.getDelegateConnection());
     }
 
     /**
@@ -109,14 +111,14 @@
     @VisibleForTesting
     public SipDelegateController(int subId, DelegateRequest initialRequest, String packageName,
             ScheduledExecutorService executorService,
-            MessageTransportStateTracker messageTransportStateTracker,
+            MessageTransportWrapper messageTransportWrapper,
             DelegateStateTracker delegateStateTracker,
             DelegateBinderStateManager.Factory connectionFactory) {
         mSubId = subId;
         mInitialRequest = initialRequest;
         mPackageName = packageName;
         mExecutorService = executorService;
-        mMessageTransportStateTracker = messageTransportStateTracker;
+        mMessageTransportWrapper = messageTransportWrapper;
         mDelegateStateTracker = delegateStateTracker;
         mBinderConnectionFactory = connectionFactory;
     }
@@ -136,8 +138,18 @@
         return mPackageName;
     }
 
+    /**
+     * @return The ImsService's SIP delegate binder impl associated with this controller.
+     */
     public ISipDelegate getSipDelegateInterface() {
-        return mMessageTransportStateTracker.getDelegateConnection();
+        return mMessageTransportWrapper.getDelegateConnection();
+    }
+
+    /**
+     * @return The IMS app's message callback binder.
+     */
+    public ISipDelegateMessageCallback getAppMessageCallback() {
+        return mMessageTransportWrapper.getAppMessageCallback();
     }
 
     /**
@@ -173,7 +185,12 @@
             }
             mBinderConnection = connection;
             logi("create: created, delegate denied: " + resultPair.second);
-            mMessageTransportStateTracker.openTransport(resultPair.first, resultPair.second);
+            Set<String> allowedTags = new ArraySet<>(supportedSet);
+            // Start with the supported set and remove all tags that were denied.
+            allowedTags.removeAll(resultPair.second.stream().map(FeatureTagState::getFeatureTag)
+                    .collect(Collectors.toSet()));
+            mMessageTransportWrapper.openTransport(resultPair.first, allowedTags,
+                    resultPair.second);
             mDelegateStateTracker.sipDelegateConnected(resultPair.second);
             return true;
         });
@@ -252,7 +269,7 @@
                         DelegateRegistrationState.DEREGISTERING_REASON_DESTROY_PENDING,
                         destroyReason);
         return pendingOperationComplete.thenApplyAsync((reasonFromDelegate) -> {
-            logi("destroy, operation complete, notifying trackers, reason" + reasonFromDelegate);
+            logi("destroy, operation complete, notifying trackers, reason " + reasonFromDelegate);
             mDelegateStateTracker.sipDelegateDestroyed(reasonFromDelegate);
             return reasonFromDelegate;
         }, mExecutorService);
@@ -313,10 +330,10 @@
         CompletableFuture<Boolean> pendingTransportClosed = new CompletableFuture<>();
         if (force) {
             logi("destroySipDelegate, forced");
-            mMessageTransportStateTracker.close(messageDestroyedReason);
+            mMessageTransportWrapper.close(messageDestroyedReason);
             pendingTransportClosed.complete(true);
         } else {
-            mMessageTransportStateTracker.closeGracefully(messageDestroyingReason,
+            mMessageTransportWrapper.closeGracefully(messageDestroyingReason,
                     messageDestroyedReason, pendingTransportClosed::complete);
         }
 
@@ -346,7 +363,7 @@
             DelegateBinderStateManager connection) {
         CompletableFuture<Pair<ISipDelegate, Set<FeatureTagState>>> createdFuture =
                 new CompletableFuture<>();
-        boolean isStarted = connection.create(mMessageTransportStateTracker.getMessageCallback(),
+        boolean isStarted = connection.create(mMessageTransportWrapper.getMessageCallback(),
                 (delegate, delegateDeniedTags) ->
                         createdFuture.complete(new Pair<>(delegate, delegateDeniedTags)));
         if (!isStarted) {
@@ -362,7 +379,7 @@
 
         List<DelegateBinderStateManager.StateCallback> stateCallbacks = new ArrayList<>(2);
         stateCallbacks.add(mDelegateStateTracker);
-        stateCallbacks.add(mMessageTransportStateTracker);
+        stateCallbacks.add(mMessageTransportWrapper);
 
         return mBinderConnectionFactory.create(mSubId,
                 new DelegateRequest(supportedSet), deniedSet, mExecutorService, stateCallbacks);
@@ -390,7 +407,7 @@
         pw.println();
         pw.println("MessageStateTracker:");
         pw.increaseIndent();
-        mMessageTransportStateTracker.dump(pw);
+        mMessageTransportWrapper.dump(pw);
         pw.decreaseIndent();
 
         pw.decreaseIndent();
diff --git a/src/com/android/services/telephony/rcs/SipDialog.java b/src/com/android/services/telephony/rcs/SipDialog.java
new file mode 100644
index 0000000..508d515
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/SipDialog.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2021 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.rcs;
+
+import android.telephony.ims.SipMessage;
+import android.text.TextUtils;
+
+import com.android.internal.telephony.SipMessageParsingUtils;
+
+import java.time.Instant;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Track the state of a SIP Dialog.
+ * <p>
+ * SIP Dialogs follow the following initialization flow:
+ * <pre>
+ * (INVITE) ---> EARLY -(2XX)-> CONFIRMED -(BYE)-----> CLOSED
+ *          ^     |   \                           ^
+ *          |--(1XX)   -(3XX-7XX) ----------------|
+ * </pre>
+ * <p> A special note on forking INVITE requests:
+ * During the EARLY phase, a 1XX or 2XX response can carry a To header tag param. This To header
+ * tag param will be set once a INVITE reaches the remote and responds. If the proxy has multiple
+ * endpoints available for the same contact, the INVITE may fork and multiple responses may be
+ * received for the same INVITE request, each with a different To header tag parameter (but the
+ * same call-id). This will generate another SIP dialog within the same SIP session.
+ */
+public class SipDialog {
+
+    /**
+     * The device has sent out a dialog starting event and is awaiting a confirmation.
+     */
+    public static final int STATE_EARLY = 0;
+
+    /**
+     * The device has received a 2XX response to the early dialog.
+     */
+    public static final int STATE_CONFIRMED = 1;
+
+    /**
+     * The device has received either a 3XX+ response to a pending dialog request or a BYE
+     * request has been sent on this dialog.
+     */
+    public static final int STATE_CLOSED = 2;
+
+    private final String mBranchId;
+    private final String mCallId;
+    private final String mFromTag;
+    private final Set<String> mAcceptContactFeatureTags;
+    private String mToTag;
+    private int mState = STATE_EARLY;
+    private Instant mLastInteraction;
+
+    /**
+     * @return A SipDialog instance representing the SIP request.
+     */
+    public static SipDialog fromSipMessage(SipMessage m) {
+        if (!SipMessageParsingUtils.isSipRequest(m.getStartLine())) return null;
+        String fromTag = SipMessageParsingUtils.getFromTag(m.getHeaderSection());
+        Set<String> acceptContactTags = SipMessageParsingUtils.getAcceptContactFeatureTags(
+                m.getHeaderSection());
+        return new SipDialog(m.getViaBranchParameter(), m.getCallIdParameter(), fromTag,
+                acceptContactTags);
+    }
+
+    /**
+     * Track a new SIP dialog, which will be starting in {@link #STATE_EARLY}.
+     *
+     * @param branchId The via branch param of the INVITE request, which is used to match
+     *                 responses.
+     * @param callId   The callId of the SIP dialog.
+     * @param fromTag  The from header's tag parameter.
+     */
+    private SipDialog(String branchId, String callId, String fromTag, Set<String> featureTags) {
+        mBranchId = branchId;
+        mCallId = callId;
+        mFromTag = fromTag;
+        mAcceptContactFeatureTags = featureTags;
+        mLastInteraction = Instant.now();
+    }
+
+    /**
+     * @return The call id associated with the SIP dialog.
+     */
+    public String getCallId() {
+        return mCallId;
+    }
+
+    /**
+     * @return the state of the SIP dialog, either {@link #STATE_EARLY},
+     * {@link #STATE_CONFIRMED}, {@link #STATE_CLOSED}.
+     */
+    public int getState() {
+        return mState;
+    }
+
+    /**
+     * @return The to header's tag parameter if this dialog has gotten a response from the remote
+     * party or {@code null} if it has not.
+     */
+    public String getToTag() {
+        return mToTag;
+    }
+
+    /**
+     * @return The feature tags contained in the "Accept-Contact" header.
+     */
+    public Set<String> getAcceptContactFeatureTags() {
+        return mAcceptContactFeatureTags;
+    }
+
+    /**
+     * @return A new instance with branch param, call-id value, and from tag param populated.
+     */
+    public SipDialog forkDialog() {
+        return new SipDialog(mBranchId, mCallId, mFromTag, mAcceptContactFeatureTags);
+    }
+
+    /**
+     * A early response has been received (101-199) and contains a to tag, which will create a
+     * dialog.
+     * @param toTag The to tag of the SIP response.
+     */
+    public void earlyResponse(String toTag) {
+        if (TextUtils.isEmpty(toTag) || mState != STATE_EARLY) {
+            // invalid state
+            return;
+        }
+        mLastInteraction = Instant.now();
+        // Only accept To tag if one has not been assigned yet.
+        if (mToTag == null) {
+            mToTag = toTag;
+        }
+    }
+
+    /**
+     * The early dialog has been confirmed and
+     * @param toTag The To header's tag parameter.
+     */
+    public void confirm(String toTag) {
+        if (mState != STATE_EARLY) {
+            // Invalid state
+            return;
+        }
+        mLastInteraction = Instant.now();
+        mState = STATE_CONFIRMED;
+        // Only accept a To tag if one has not been assigned yet.
+        if (mToTag == null) {
+            mToTag = toTag;
+        }
+    }
+
+    /**
+     * Close the SIP dialog
+     */
+    public void close() {
+        mLastInteraction = Instant.now();
+        mState = STATE_CLOSED;
+    }
+
+    /**
+     * @return {@code true} if a SIP response's branch, call-id, and from tags match this dialog,
+     * {@code false} if it does not. This may match multiple Dialogs in the case of SIP INVITE
+     * forking.
+     */
+    public boolean isResponseAssociatedWithDialog(SipMessage m) {
+        if (!mBranchId.equals(m.getViaBranchParameter())) return false;
+        if (!mCallId.equals(m.getCallIdParameter())) return false;
+        String fromTag = SipMessageParsingUtils.getFromTag(m.getHeaderSection());
+        return mFromTag.equals(fromTag);
+    }
+
+    /**
+     * @return {@code true} if the SIP request is part of the SIP Dialog, {@code false} if it is
+     * not.
+     */
+    public boolean isRequestAssociatedWithDialog(SipMessage m) {
+        if (!mCallId.equals(m.getCallIdParameter())) return false;
+        String fromTag = SipMessageParsingUtils.getFromTag(m.getHeaderSection());
+        String toTag = SipMessageParsingUtils.getToTag(m.getHeaderSection());
+        // Requests can only be associated if both to and from tag of message are populated. The
+        // dialog's to tag must also be non-null meaning we got a response from the remote.
+        if (fromTag == null || toTag == null || mToTag == null) return false;
+        // For outgoing requests, recorded from tag will match their from tag and for incoming
+        // requests recorded from tag will match their to tag. Same with our recorded to tag.
+        return (mFromTag.equals(fromTag) || mFromTag.equals(toTag))
+                && (mToTag.equals(toTag) || mToTag.equals(fromTag));
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder b = new StringBuilder("SipDialog[");
+        switch (mState) {
+            case STATE_EARLY:
+                b.append("early");
+                break;
+            case STATE_CONFIRMED:
+                b.append("confirmed");
+                break;
+            case STATE_CLOSED:
+                b.append("closed");
+                break;
+            default:
+                b.append(mState);
+        }
+        b.append("] bId=");
+        b.append(mBranchId);
+        b.append(", cId=");
+        b.append(mCallId);
+        b.append(", f=");
+        b.append(mFromTag);
+        b.append(", t=");
+        b.append(mToTag);
+        b.append(", Last Interaction: ");
+        b.append(mLastInteraction);
+        return b.toString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        SipDialog sipDialog = (SipDialog) o;
+        // Does not include mState and last interaction time, as a dialog is only the same if
+        // its branch, callId, and to/from tags are equal.
+        return mBranchId.equals(sipDialog.mBranchId)
+                && Objects.equals(mCallId, sipDialog.mCallId)
+                && Objects.equals(mFromTag, sipDialog.mFromTag)
+                && Objects.equals(mToTag, sipDialog.mToTag);
+    }
+
+    @Override
+    public int hashCode() {
+        // Does not include mState and last interaction time, as a dialog is only the same if
+        // its branch, callId, and to/from tags are equal.
+        return Objects.hash(mBranchId, mCallId, mFromTag, mToTag);
+    }
+}
diff --git a/src/com/android/services/telephony/rcs/SipSessionTracker.java b/src/com/android/services/telephony/rcs/SipSessionTracker.java
new file mode 100644
index 0000000..77bf3f3
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/SipSessionTracker.java
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2021 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.rcs;
+
+import android.telephony.ims.SipMessage;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.LocalLog;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.SipMessageParsingUtils;
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Tracks the state of SIP sessions started by a SIP INVITE (see RFC 3261)
+ * <p>
+ * Each SIP session created will consist of one or more SIP with, each dialog in the session
+ * having the same call-ID. Each SIP dialog will be in one of three states: EARLY, CONFIRMED, and
+ * CLOSED.
+ * <p>
+ * The SIP session will be closed once all of the associated dialogs are closed.
+ */
+public class SipSessionTracker {
+    private static final String TAG = "SessionT";
+
+    /**
+     * SIP request methods that will start a new SIP Dialog and move it into the PENDING state
+     * while we wait for a response. Note: INVITE is not the only SIP dialog that will create a
+     * dialog, however it is the only one that we wish to track for this use case.
+     */
+    public static final String[] SIP_REQUEST_DIALOG_START_METHODS = new String[] { "invite" };
+
+    /**
+     * The SIP request method that will close a SIP Dialog in the ACTIVE state with the same
+     * Call-Id.
+     */
+    private static final String SIP_CLOSE_DIALOG_REQUEST_METHOD = "bye";
+
+    private final LocalLog mLocalLog = new LocalLog(SipTransportController.LOG_SIZE);
+    private final ArrayList<SipDialog> mTrackedDialogs = new ArrayList<>();
+    // Operations that are pending an ack from the remote application processing the message before
+    // they can be applied here. Maps the via header branch parameter of the message to the
+    // associated pending operation.
+    private final ArrayMap<String, Runnable> mPendingAck = new ArrayMap<>();
+
+    /**
+     * Filter a SIP message to determine if it will result in a new SIP dialog. This will need to be
+     * successfully acknowledged by the remote IMS stack using
+     * {@link #acknowledgePendingMessage(String)} before we do any further processing.
+     *
+     * @param message The Incoming SIP message.
+     */
+    public void filterSipMessage(SipMessage message) {
+        final Runnable r;
+        if (startsEarlyDialog(message)) {
+            r = getCreateDialogRunnable(message);
+        } else if (closesDialog(message)) {
+            r = getCloseDialogRunnable(message);
+        } else if (SipMessageParsingUtils.isSipResponse(message.getStartLine())) {
+            r = getDialogStateChangeRunnable(message);
+        } else {
+            r = null;
+        }
+
+        if (r != null) {
+            if (mPendingAck.containsKey(message.getViaBranchParameter())) {
+                Runnable lastEvent = mPendingAck.get(message.getViaBranchParameter());
+                logw("Adding new message when there was already a pending event for branch: "
+                        + message.getViaBranchParameter());
+                Runnable concatRunnable = () -> {
+                    // No choice but to concatenate the Runnables together.
+                    if (lastEvent != null) lastEvent.run();
+                    r.run();
+                };
+                mPendingAck.put(message.getViaBranchParameter(), concatRunnable);
+            } else {
+                mPendingAck.put(message.getViaBranchParameter(), r);
+            }
+        }
+    }
+
+    /**
+     * The pending SIP message has been received by the remote IMS stack. We can now track dialogs
+     * associated with this message.
+     * message.
+     * @param viaBranchId The SIP message's Via header's branch parameter, which is used as a
+     *                    unique token.
+     */
+    public void acknowledgePendingMessage(String viaBranchId) {
+        Runnable r = mPendingAck.get(viaBranchId);
+        if (r != null) {
+            mPendingAck.remove(viaBranchId);
+            r.run();
+        }
+    }
+
+    /**
+     * The pending SIP message has failed to be sent to the remote so remove the pending task.
+     * @param viaBranchId The failed message's Via header's branch parameter.
+     */
+    public void pendingMessageFailed(String viaBranchId) {
+        mPendingAck.remove(viaBranchId);
+    }
+
+    /**
+     * A SIP session tracked by the remote application's IMS stack has been closed, so we can stop
+     * tracking it.
+     * @param callId The callId of the SIP session that has been closed.
+     */
+    public void cleanupSession(String callId) {
+        List<SipDialog> dialogsToCleanup = mTrackedDialogs.stream()
+                .filter(d -> d.getCallId().equals(callId))
+                .collect(Collectors.toList());
+        if (dialogsToCleanup.isEmpty()) return;
+        logi("Cleanup dialogs associated with call id: " + callId);
+        for (SipDialog d : dialogsToCleanup) {
+            d.close();
+            logi("Dialog closed: " + d);
+        }
+        mTrackedDialogs.removeAll(dialogsToCleanup);
+    }
+
+    /**
+     * @return the call IDs of the dialogs associated with the provided feature tags.
+     */
+    public Set<String> getCallIdsAssociatedWithFeatureTag(Set<String> featureTags) {
+        if (featureTags.isEmpty()) return Collections.emptySet();
+        Set<String> associatedIds = new ArraySet<>();
+        for (String featureTag : featureTags) {
+            for (SipDialog dialog : mTrackedDialogs) {
+                boolean isAssociated = dialog.getAcceptContactFeatureTags().stream().anyMatch(
+                        d -> d.equalsIgnoreCase(featureTag));
+                if (isAssociated) associatedIds.add(dialog.getCallId());
+            }
+        }
+        return associatedIds;
+    }
+
+    /**
+     * @return All dialogs that have not received a final response yet 2XX or 3XX+.
+     */
+    public Set<SipDialog> getEarlyDialogs() {
+        return mTrackedDialogs.stream().filter(d -> d.getState() == SipDialog.STATE_EARLY)
+                .collect(Collectors.toSet());
+    }
+
+    /**
+     * @return All confirmed dialogs that have received a 2XX response and are active.
+     */
+    public Set<SipDialog> getConfirmedDialogs() {
+        return mTrackedDialogs.stream().filter(d -> d.getState() == SipDialog.STATE_CONFIRMED)
+                .collect(Collectors.toSet());
+    }
+
+    /**
+     * @return Dialogs that have been closed via a BYE or 3XX+ response and
+     * {@link #cleanupSession(String)} has not been called yet.
+     */
+    @VisibleForTesting
+    public Set<SipDialog> getClosedDialogs() {
+        return mTrackedDialogs.stream().filter(d -> d.getState() == SipDialog.STATE_CLOSED)
+                .collect(Collectors.toSet());
+    }
+
+    /**
+     * @return All of the tracked dialogs, even the ones that have been closed but
+     * {@link #cleanupSession(String)} has not been called.
+     */
+    public Set<SipDialog> getTrackedDialogs() {
+        return new ArraySet<>(mTrackedDialogs);
+    }
+
+    /**
+     * Clears all tracked sessions.
+     */
+    public void clearAllSessions() {
+        mTrackedDialogs.clear();
+        mPendingAck.clear();
+    }
+
+    /**
+     * Dump the state of this tracker to the provided PrintWriter.
+     */
+    public void dump(PrintWriter printWriter) {
+        IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
+        pw.println("SipSessionTracker:");
+        pw.increaseIndent();
+        pw.print("Early Call IDs: ");
+        pw.println(getEarlyDialogs().stream().map(SipDialog::getCallId)
+                .collect(Collectors.toSet()));
+        pw.print("Confirmed Call IDs: ");
+        pw.println(getConfirmedDialogs().stream().map(SipDialog::getCallId)
+                .collect(Collectors.toSet()));
+        pw.print("Closed Call IDs: ");
+        pw.println(getClosedDialogs().stream().map(SipDialog::getCallId)
+                .collect(Collectors.toSet()));
+        pw.println("Tracked Dialogs:");
+        pw.increaseIndent();
+        for (SipDialog d : mTrackedDialogs) {
+            pw.println(d);
+        }
+        pw.decreaseIndent();
+        pw.println();
+        pw.println("Local Logs");
+        mLocalLog.dump(pw);
+        pw.decreaseIndent();
+    }
+
+    /**
+     * @return {@code true}, if the SipMessage passed in should start a new SIP dialog,
+     * {@code false} if it should not.
+     */
+    private boolean startsEarlyDialog(SipMessage m) {
+        if (!SipMessageParsingUtils.isSipRequest(m.getStartLine())) {
+            return false;
+        }
+        String[] startLineSegments = SipMessageParsingUtils.splitStartLineAndVerify(
+                m.getStartLine());
+        if (startLineSegments == null) {
+            return false;
+        }
+        return Arrays.stream(SIP_REQUEST_DIALOG_START_METHODS)
+                .anyMatch(r -> r.equalsIgnoreCase(startLineSegments[0]));
+    }
+
+    /**
+     * @return {@code true}, if the SipMessage passed in should close a confirmed dialog,
+     * {@code false} if it should not.
+     */
+    private boolean closesDialog(SipMessage m) {
+        if (!SipMessageParsingUtils.isSipRequest(m.getStartLine())) {
+            return false;
+        }
+        String[] startLineSegments = SipMessageParsingUtils.splitStartLineAndVerify(
+                m.getStartLine());
+        if (startLineSegments == null) {
+            return false;
+        }
+        return SIP_CLOSE_DIALOG_REQUEST_METHOD.equalsIgnoreCase(startLineSegments[0]);
+    }
+
+    private Runnable getCreateDialogRunnable(SipMessage m) {
+        return () -> {
+            List<SipDialog> duplicateDialogs = mTrackedDialogs.stream()
+                    .filter(d -> d.getCallId().equals(m.getCallIdParameter()))
+                    .collect(Collectors.toList());
+            if (duplicateDialogs.size() > 0) {
+                logi("trying to create a dialog for a call ID that already exists, skip: "
+                        + duplicateDialogs);
+                return;
+            }
+            SipDialog dialog = SipDialog.fromSipMessage(m);
+            logi("Starting new SipDialog: " + dialog);
+            mTrackedDialogs.add(dialog);
+        };
+    }
+
+    private Runnable getCloseDialogRunnable(SipMessage m) {
+        return () -> {
+            List<SipDialog> dialogsToClose = mTrackedDialogs.stream()
+                    .filter(d -> d.isRequestAssociatedWithDialog(m))
+                    .collect(Collectors.toList());
+            if (dialogsToClose.isEmpty()) return;
+            logi("Closing dialogs associated with: " + m);
+            for (SipDialog d : dialogsToClose) {
+                d.close();
+                logi("Dialog closed: " + d);
+            }
+        };
+    }
+
+    private Runnable getDialogStateChangeRunnable(SipMessage m) {
+        return () -> {
+            // This will return a dialog and all of its potential forks
+            List<SipDialog> associatedDialogs = mTrackedDialogs.stream()
+                    .filter(d -> d.isResponseAssociatedWithDialog(m))
+                    .collect(Collectors.toList());
+            if (associatedDialogs.isEmpty()) return;
+            String messageToTag = SipMessageParsingUtils.getToTag(m.getHeaderSection());
+            // If the to tag matches (or message to tag doesn't exist in dialog yet because this is
+            // the first response), then we are done.
+            SipDialog match = associatedDialogs.stream()
+                    .filter(d -> d.getToTag() == null || d.getToTag().equals(messageToTag))
+                    .findFirst().orElse(null);
+            if (match == null) {
+                // If it doesn't then we have a situation where we need to fork the existing dialog.
+                // The dialog used to fork doesn't matter, since the required params are the same,
+                // so simply use the first one in the returned list.
+                logi("Dialog forked");
+                match = associatedDialogs.get(0).forkDialog();
+                mTrackedDialogs.add(match);
+            }
+            if (match != null) {
+                logi("Dialog: " + match + " is associated with: " + m);
+                updateSipDialogState(match, m);
+                logi("Dialog state updated to " + match);
+            } else {
+                logi("No Dialogs are associated with: " + m);
+            }
+        };
+    }
+
+    private void updateSipDialogState(SipDialog d, SipMessage m) {
+        String[] startLineSegments = SipMessageParsingUtils.splitStartLineAndVerify(
+                m.getStartLine());
+        if (startLineSegments == null) {
+            logw("Could not parse start line for SIP message: " + m.getStartLine());
+            return;
+        }
+        int statusCode = 0;
+        try {
+            statusCode = Integer.parseInt(startLineSegments[1]);
+        } catch (NumberFormatException e) {
+            logw("Could not parse status code for SIP message: " + m.getStartLine());
+            return;
+        }
+        String toTag = SipMessageParsingUtils.getToTag(m.getHeaderSection());
+        logi("updateSipDialogState: message has statusCode: " + statusCode + ", and to tag: "
+                + toTag);
+        // If specifically 100 Trying, then do not do anything.
+        if (statusCode <= 100) return;
+        // If 300+, then this dialog has received an error response and should move to closed state.
+        if (statusCode >= 300) {
+            d.close();
+            return;
+        }
+        if (toTag == null) logw("updateSipDialogState: No to tag for message: " + m);
+        if (statusCode >= 200) {
+            d.confirm(toTag);
+            return;
+        }
+        // 1XX responses still require updates to dialogs.
+        d.earlyResponse(toTag);
+    }
+
+    private void logi(String log) {
+        Log.w(SipTransportController.LOG_TAG, TAG + ": " + log);
+        mLocalLog.log("[I] " + log);
+    }
+
+    private void logw(String log) {
+        Log.w(SipTransportController.LOG_TAG, TAG + ": " + log);
+        mLocalLog.log("[W] " + log);
+    }
+}
diff --git a/src/com/android/services/telephony/rcs/SipTransportController.java b/src/com/android/services/telephony/rcs/SipTransportController.java
index cecc8a2..f37c360 100644
--- a/src/com/android/services/telephony/rcs/SipTransportController.java
+++ b/src/com/android/services/telephony/rcs/SipTransportController.java
@@ -20,6 +20,7 @@
 import android.app.role.RoleManager;
 import android.content.Context;
 import android.os.PersistableBundle;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.telephony.CarrierConfigManager;
@@ -84,8 +85,8 @@
  */
 public class SipTransportController implements RcsFeatureController.Feature,
         OnRoleHoldersChangedListener {
+    public static final String LOG_TAG = "SipTransportC";
     static final int LOG_SIZE = 50;
-    static final String LOG_TAG = "SipTransportC";
 
     /**See {@link TimerAdapter#getReevaluateThrottleTimerMilliseconds()}.*/
     private static final int REEVALUATE_THROTTLE_DEFAULT_MS = 1000;
@@ -172,6 +173,34 @@
     }
 
     /**
+     * Extends RemoteCallbackList to track callbacks to the IMS applications with
+     * SipDelegateConnections and cleans them up if they die.
+     */
+    private class TrackedAppBinders extends RemoteCallbackList<ISipDelegateMessageCallback> {
+        @Override
+        public void onCallbackDied(ISipDelegateMessageCallback callback, Object cookie) {
+            mExecutorService.execute(() -> {
+                if (cookie instanceof SipDelegateController) {
+                    SipDelegateController c = (SipDelegateController) cookie;
+                    logi("onCallbackDied - Cleaning up delegates associated with package: "
+                            + c.getPackageName());
+                    boolean isNewDestroyQueued = addPendingDestroy(c,
+                            SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
+                    if (isNewDestroyQueued) {
+                        CompletableFuture<Void> f = new CompletableFuture<>();
+                        scheduleReevaluateNow(f);
+                        f.thenRun(() -> logi("onCallbackDied - clean up complete for package: "
+                                + c.getPackageName()));
+                    }
+                } else {
+                    logw("onCallbackDied: unexpected - cookie is not an instance of "
+                            + "SipDelegateController");
+                }
+            });
+        }
+    }
+
+    /**
      * Used in {@link #destroySipDelegate(int, ISipDelegate, int)} to store pending destroy
      * requests.
      */
@@ -190,13 +219,16 @@
             if (this == o) return true;
             if (o == null || getClass() != o.getClass()) return false;
             DestroyRequest that = (DestroyRequest) o;
-            return reason == that.reason
-                    && controller.equals(that.controller);
+            // Only use controller for comparison, as we want to only have one DestroyRequest active
+            // per controller.
+            return controller.equals(that.controller);
         }
 
         @Override
         public int hashCode() {
-            return java.util.Objects.hash(controller, reason);
+            // Only use controller for hash, as we want to only have one DestroyRequest active per
+            // controller.
+            return java.util.Objects.hash(controller);
         }
 
         @Override
@@ -233,6 +265,8 @@
     private final List<SipDelegateController> mDelegatePendingCreate = new ArrayList<>();
     // SipDelegateControllers that are pending to be destroyed.
     private final List<DestroyRequest> mDelegatePendingDestroy = new ArrayList<>();
+    // Cache of Binders to remote IMS applications for tracking their potential death
+    private final TrackedAppBinders mActiveAppBinders = new TrackedAppBinders();
 
     // Future scheduled for operations that require the list of SipDelegateControllers to
     // be evaluated. When the timer expires and triggers the reevaluate method, this controller
@@ -254,7 +288,7 @@
     // Callback to monitor rcs provisioning change
     private CarrierConfigManager mCarrierConfigManager;
     // Cached allowed feature tags from carrier config
-    ArraySet<String> mFeatureTagsAllowed = new ArraySet<>();
+    private ArraySet<String> mFeatureTagsAllowed = new ArraySet<>();
 
     /**
      * Create an instance of SipTransportController.
@@ -660,6 +694,11 @@
             return;
         }
 
+        // Remove tracking for all SipDelegates being destroyed first
+        for (DestroyRequest d : mDelegatePendingDestroy) {
+            logi("reevaluateDelegates: starting destroy for: " + d.controller.getPackageName());
+            mActiveAppBinders.unregister(d.controller.getAppMessageCallback());
+        }
         // Destroy all pending destroy delegates first. Order doesn't matter.
         List<CompletableFuture<Void>> pendingDestroyList = mDelegatePendingDestroy.stream()
                 .map(d -> triggerDestroy(d.controller, d.reason)).collect(
@@ -673,7 +712,8 @@
         // Add newly created SipDelegates to end of queue before evaluating associated features.
         mDelegatePriorityQueue.addAll(mDelegatePendingCreate);
         for (SipDelegateController c : mDelegatePendingCreate) {
-            logi("reevaluateDelegates: pending create: " + c);
+            logi("reevaluateDelegates: pending create: " + c.getPackageName());
+            mActiveAppBinders.register(c.getAppMessageCallback(), c);
         }
         mDelegatePendingCreate.clear();
 
@@ -704,8 +744,12 @@
 
         // Executor doesn't matter here, schedule an event to update the IMS registration.
         mEvaluateCompleteFuture = pendingChange
-                .thenAccept((associatedFeatures) -> {
-                    logi("reevaluateDelegates: reevaluate complete," + " feature tags associated: "
+                .whenComplete((f, ex) -> {
+                    if (ex != null) {
+                        logw("reevaluateDelegates: Exception caught: " + ex);
+                    }
+                }).thenAccept((associatedFeatures) -> {
+                    logi("reevaluateDelegates: reevaluate complete, feature tags associated: "
                             + associatedFeatures);
                     scheduleUpdateRegistration();
                 });
diff --git a/src/com/android/services/telephony/rcs/TransportSipMessageValidator.java b/src/com/android/services/telephony/rcs/TransportSipMessageValidator.java
new file mode 100644
index 0000000..777026c
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/TransportSipMessageValidator.java
@@ -0,0 +1,551 @@
+/*
+ * Copyright (C) 2021 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.rcs;
+
+import android.telephony.ims.DelegateRegistrationState;
+import android.telephony.ims.FeatureTagState;
+import android.telephony.ims.SipDelegateConfiguration;
+import android.telephony.ims.SipDelegateImsConfiguration;
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+import android.util.LocalLog;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.services.telephony.rcs.validator.IncomingTransportStateValidator;
+import com.android.services.telephony.rcs.validator.MalformedSipMessageValidator;
+import com.android.services.telephony.rcs.validator.OutgoingTransportStateValidator;
+import com.android.services.telephony.rcs.validator.RestrictedOutgoingSipRequestValidator;
+import com.android.services.telephony.rcs.validator.RestrictedOutgoingSubscribeValidator;
+import com.android.services.telephony.rcs.validator.SipMessageValidator;
+import com.android.services.telephony.rcs.validator.ValidationResult;
+
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Track incoming and outgoing SIP messages passing through this delegate and verify these messages
+ * by doing the following:
+ *  <ul>
+ *    <li>Track the SipDelegate's registration state to ensure that a registration event has
+ *    occurred before allowing outgoing messages. Once it has occurred, filter outgoing SIP messages
+ *    based on the open/restricted feature tag registration state.</li>
+ *    <li>Track the SipDelegate's IMS configuration version and deny any outgoing SipMessages
+ *    associated with a stale IMS configuration version.</li>
+ *    <li>Track the SipDelegate open/close state to allow/deny outgoing messages based on the
+ *    session's state.</li>
+ *    <li>Validate outgoing SIP messages for both restricted request methods as well as restricted/
+ *    malformed headers.</li>
+ * </ul>
+ */
+public class TransportSipMessageValidator {
+
+    private static final String LOG_TAG = "SipMessageV";
+
+    /**
+     * the time in milliseconds that we will wait for SIP sessions to close before we will timeout
+     * and force the sessions to be cleaned up.
+     */
+    private static final int PENDING_CLOSE_TIMEOUT_MS = 1000;
+    /**
+     * time in milliseconds that we will wait for SIP sessions to be closed before we timeout and
+     * force the sessions associated with the deregistering feature tags to be cleaned up.
+     */
+    private static final int PENDING_REGISTRATION_CHANGE_TIMEOUT_MS = 1000;
+
+    /**
+     * Timeouts used in this class that are visible for testing.
+     */
+    @VisibleForTesting
+    public interface Timeouts {
+        /**
+         * @return the time in milliseconds that we will wait for SIP sessions to close before we
+         * will timeout and force the sessions to be cleaned up.
+         */
+        int getPendingCloseTimeoutMs();
+
+        /**
+         * @return the time in milliseconds that we will wait for SIP sessions to be closed before
+         * we timeout and force the sessions associated with the deregistering feature tags to be
+         * cleaned up.
+         */
+        int getPendingRegistrationChangeTimeoutMs();
+    }
+
+    /**
+     * Tracks a pending task that has been scheduled on the associated Executor.
+     */
+    private abstract static class PendingTask implements Runnable {
+
+        private ScheduledFuture<?> mFuture;
+
+        public void scheduleDelayed(ScheduledExecutorService executor, int timeMs) {
+            mFuture = executor.schedule(this, timeMs, TimeUnit.MILLISECONDS);
+        }
+
+        public boolean isDone() {
+            return mFuture != null && mFuture.isDone();
+        }
+
+        public void cancel() {
+            if (mFuture == null) return;
+            mFuture.cancel(false /*interrupt*/);
+        }
+    }
+
+    /**
+     * Tracks a pending reg cleanup task that has been scheduled on the associated Executor.
+     */
+    private abstract static class PendingRegCleanupTask extends PendingTask {
+        public final Set<String> pendingCallIds;
+        public final Set<String> featureTags;
+
+        PendingRegCleanupTask(Set<String> tags, Set<String> callIds) {
+            featureTags = tags;
+            pendingCallIds = callIds;
+        }
+    }
+
+    private final int mSubId;
+    private final ScheduledExecutorService mExecutor;
+    private final LocalLog mLocalLog = new LocalLog(SipTransportController.LOG_SIZE);
+    private final SipSessionTracker mSipSessionTracker;
+    // Validators
+    private final IncomingTransportStateValidator mIncomingTransportStateValidator;
+    private final OutgoingTransportStateValidator mOutgoingTransportStateValidator;
+    private final SipMessageValidator mOutgoingMessageValidator;
+    private final SipMessageValidator mIncomingMessageValidator;
+
+    private Set<String> mSupportedFeatureTags;
+    private Set<FeatureTagState> mDeniedFeatureTags;
+    private long mConfigVersion = -1;
+    private Consumer<Set<String>> mClosingCompleteConsumer;
+    private PendingTask mPendingClose;
+    private PendingRegCleanupTask mPendingRegCleanup;
+    private Consumer<Set<String>> mRegistrationAppliedConsumer;
+
+    public TransportSipMessageValidator(int subId, ScheduledExecutorService executor) {
+        mSubId = subId;
+        mExecutor = executor;
+        mSipSessionTracker = new SipSessionTracker();
+        mOutgoingTransportStateValidator = new OutgoingTransportStateValidator(mSipSessionTracker);
+        mIncomingTransportStateValidator = new IncomingTransportStateValidator();
+        mOutgoingMessageValidator = new MalformedSipMessageValidator().andThen(
+                new RestrictedOutgoingSipRequestValidator()).andThen(
+                new RestrictedOutgoingSubscribeValidator()).andThen(
+                        mOutgoingTransportStateValidator);
+        mIncomingMessageValidator = mIncomingTransportStateValidator;
+    }
+
+    @VisibleForTesting
+    public TransportSipMessageValidator(int subId, ScheduledExecutorService executor,
+            SipSessionTracker sipSessionTracker,
+            OutgoingTransportStateValidator outgoingStateValidator,
+            IncomingTransportStateValidator incomingStateValidator) {
+        mSubId = subId;
+        mExecutor = executor;
+        mSipSessionTracker = sipSessionTracker;
+        mOutgoingTransportStateValidator = outgoingStateValidator;
+        mIncomingTransportStateValidator = incomingStateValidator;
+        mOutgoingMessageValidator = mOutgoingTransportStateValidator;
+        mIncomingMessageValidator = mIncomingTransportStateValidator;
+    }
+
+    /**
+     * Notify this tracker that a registration state change has occurred.
+     * <p>
+     * In some scenarios, this will require that existing SIP dialogs are closed (for example, when
+     * moving a feature tag from REGISTERED->DEREGISTERING). This method allows the caller to
+     * provide a Consumer that will be called when either there are no SIP dialogs active on
+     * DEREGISTERING feature tags, or a timeout has occurred. In the case that a timeout has
+     * occurred, this Consumer will accept a list of callIds that will be manually closed by the
+     * framework to unblock the IMS stack.
+     * <p>
+     * @param stateChangeComplete A one time Consumer that when completed, will contain a List of
+     *         callIds corresponding to SIP Dialogs that have not been closed yet. It is the callers
+     *         responsibility to close the dialogs associated with the provided callIds. If another
+     *         state update occurs before the previous was completed, the previous consumer will be
+     *         completed with an empty list and the new Consumer will be executed when the new state
+     *         changes.
+     * @param regState The new registration state.
+     */
+    public void onRegistrationStateChanged(Consumer<Set<String>> stateChangeComplete,
+            DelegateRegistrationState regState) {
+        if (mRegistrationAppliedConsumer != null) {
+            logw("onRegistrationStateChanged: pending registration change, completing now.");
+            // complete the pending consumer with no dialogs pending, this will be re-evaluated
+            // and new configuration will be applied.
+            cleanupAndNotifyRegistrationAppliedConsumer(Collections.emptySet());
+        }
+        Set<String> restrictedTags = Stream.concat(
+                regState.getDeregisteringFeatureTags().stream(),
+                regState.getDeregisteredFeatureTags().stream()).map(FeatureTagState::getFeatureTag)
+                .collect(Collectors.toSet());
+        mOutgoingTransportStateValidator.restrictFeatureTags(restrictedTags);
+        mRegistrationAppliedConsumer = stateChangeComplete;
+        if (mPendingClose == null || mPendingClose.isDone()) {
+            // Only update the pending registration cleanup task if we do not already have a pending
+            // close in progress.
+            updatePendingRegCleanupTask(restrictedTags);
+        } else {
+            logi("skipping update reg cleanup due to pending close task.");
+        }
+    }
+
+    /**
+     * Notify this tracker that the IMS configuration has changed.
+     *
+     * Parameters contained in the IMS configuration will be used to validate outgoing messages,
+     * such as the configuration version.
+     * @param c The newest IMS configuration.
+     */
+    public void onImsConfigurationChanged(SipDelegateImsConfiguration c) {
+        if (c.getVersion() == mConfigVersion) {
+            return;
+        }
+        logi("onImsConfigurationChanged: " + mConfigVersion + "->" + c.getVersion());
+        mConfigVersion = c.getVersion();
+    }
+
+    /**
+     * Notify this tracker that the IMS configuration has changed.
+     *
+     * Parameters contained in the IMS configuration will be used to validate outgoing messages,
+     * such as the configuration version.
+     * @param c The newest IMS configuration.
+     */
+    public void onConfigurationChanged(SipDelegateConfiguration c) {
+        if (c.getVersion() == mConfigVersion) {
+            return;
+        }
+        logi("onConfigurationChanged: " + mConfigVersion + "->" + c.getVersion());
+        mConfigVersion = c.getVersion();
+    }
+
+    /**
+     * A new message transport has been opened to a SipDelegate.
+     * <p>
+     * Initializes this tracker and resets any state required to process messages.
+     * @param supportedFeatureTags feature tags that are supported and should pass message
+     *                             verification.
+     * @param deniedFeatureTags feature tags that were denied and should fail message verification.
+     */
+    public void onTransportOpened(Set<String> supportedFeatureTags,
+            Set<FeatureTagState> deniedFeatureTags) {
+        logi("onTransportOpened: moving to open state");
+        mSupportedFeatureTags = supportedFeatureTags;
+        mDeniedFeatureTags = deniedFeatureTags;
+        mOutgoingTransportStateValidator.open(supportedFeatureTags, deniedFeatureTags.stream().map(
+                FeatureTagState::getFeatureTag).collect(Collectors.toSet()));
+        mIncomingTransportStateValidator.open();
+    }
+
+    /**
+     * A SIP session has been cleaned up and should no longer be tracked.
+     * @param callId The call ID associated with the SIP session.
+     */
+    public void onSipSessionCleanup(String callId) {
+        mSipSessionTracker.cleanupSession(callId);
+        onCallIdsChanged();
+    }
+
+    /**
+     * Move this tracker into a restricted state, where only outgoing SIP messages associated with
+     * an ongoing SIP Session may be sent. Any out-of-dialog outgoing SIP messages will be denied.
+     * This does not affect incoming SIP messages (for example, an incoming SIP INVITE).
+     * <p>
+     * This tracker will stay in this state until either all open SIP Sessions are closed by the
+     * remote application, or a timeout occurs. Once this happens, the provided Consumer will accept
+     * a List of call IDs associated with the open SIP Sessions that did not close before the
+     * timeout. The caller must then close all open SIP Sessions before closing the transport.
+     * @param closingCompleteConsumer A Consumer that will be called when the transport can be
+     *         closed and may contain a list of callIds associated with SIP sessions that have not
+     *         been closed.
+     * @param closingReason The reason that will be provided if an outgoing out-of-dialog SIP
+     *         message is sent while the transport is closing.
+     * @param closedReason The reason that will be provided if any outgoing SIP message is sent
+     *         once the transport is closed.
+     */
+    public void closeSessionsGracefully(Consumer<Set<String>> closingCompleteConsumer,
+            int closingReason, int closedReason) {
+        if (closingCompleteConsumer == null) {
+            logw("closeSessionsGracefully: unexpected - called with null consumer... closing now");
+            closeSessions(closedReason);
+            return;
+        }
+        if (mClosingCompleteConsumer != null) {
+            // In this case, all we can do is combine the consumers and wait for the other pending
+            // close to complete, finishing both.
+            logw("closeSessionsGracefully: unexpected - existing close pending, combining"
+                    + " consumers.");
+            mClosingCompleteConsumer = callIds -> {
+                mClosingCompleteConsumer.accept(callIds);
+                closingCompleteConsumer.accept(callIds);
+            };
+            return;
+        } else {
+            mClosingCompleteConsumer = closingCompleteConsumer;
+        }
+        if (getTrackedSipSessionCallIds().isEmpty()) {
+            logi("closeSessionsGracefully: moving to closed state now, reason=" + closedReason);
+            closeSessionsInternal(closedReason);
+            cancelClosingTimeoutAndSendComplete(Collections.emptySet());
+            return;
+        }
+        cancelPendingRegCleanupTask();
+        logi("closeSessionsGracefully: moving to restricted state, reason=" + closingReason);
+        mOutgoingTransportStateValidator.restrict(closingReason);
+        mPendingClose = new PendingTask() {
+            @Override
+            public void run() {
+                closeSessions(closingReason);
+            }
+        };
+        mPendingClose.scheduleDelayed(mExecutor, PENDING_CLOSE_TIMEOUT_MS);
+    }
+
+    /**
+     * Close the transport now. If there are any open SIP sessions and this is closed due to a
+     * configuration change (SIM subscription change, user disabled RCS, the service is dead,
+     * etc...) then we will return the call IDs of all open sessions and ask them to be closed.
+     * @param closedReason The error reason for why the message transport was closed that will be
+     *         sent back to the caller if a new SIP message is sent.
+     * @return A List of call IDs associated with sessions that were still open at the time that the
+     * tracker closed the transport.
+     */
+    public Set<String> closeSessions(int closedReason) {
+        Set<String> openCallIds = getTrackedSipSessionCallIds();
+        logi("closeSessions: moving to closed state, reason=" + closedReason + ", open call ids: "
+                + openCallIds);
+        closeSessionsInternal(closedReason);
+        boolean consumerHandledPendingSessions = cancelClosingTimeoutAndSendComplete(openCallIds);
+        if (consumerHandledPendingSessions) {
+            logw("closeSessions: call ID closure handled through consumer");
+            // sent the open call IDs through the pending complete mechanism to unblock any previous
+            // graceful close command and close them early.
+            return Collections.emptySet();
+        }
+        return openCallIds;
+    }
+
+    /**
+     * Verify a new outgoing SIP message before sending to the SipDelegate (ImsService).
+     * @param message The SIP message being verified
+     * @return The result of verifying the outgoing message.
+     */
+
+    public ValidationResult verifyOutgoingMessage(SipMessage message, long configVersion) {
+        if (mConfigVersion != configVersion) {
+            return new ValidationResult(
+                    SipDelegateManager.MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION,
+                    "stale IMS configuration: "  + configVersion + ", expected: "
+                            + mConfigVersion);
+        }
+        ValidationResult result = mOutgoingMessageValidator.validate(message);
+        logi("verifyOutgoingMessage: " + result + ", message=" + message);
+        if (result.isValidated) mSipSessionTracker.filterSipMessage(message);
+        return result;
+    }
+
+    /**
+     * Verify a new incoming SIP message before sending it to the
+     * DelegateConnectionMessageCallback (remote application).
+     * @param message The SipMessage to verify.
+     * @return The result of verifying the incoming message.
+     */
+    public ValidationResult verifyIncomingMessage(SipMessage message) {
+        ValidationResult result = mIncomingMessageValidator.validate(message);
+        logi("verifyIncomingMessage: " + result + ", message=" + message);
+        if (result.isValidated) mSipSessionTracker.filterSipMessage(message);
+        return result;
+    }
+
+    /**
+     * Acknowledge that a pending incoming or outgoing SIP message has been delivered successfully
+     * to the remote.
+     * @param transactionId The transaction ID associated with the message.
+     */
+    public void acknowledgePendingMessage(String transactionId) {
+        logi("acknowledgePendingMessage: id=" + transactionId);
+        mSipSessionTracker.acknowledgePendingMessage(transactionId);
+        onCallIdsChanged();
+    }
+
+    /**
+     * A pending incoming or outgoing SIP message has failed and should not be tracked.
+     * @param transactionId The transaction ID associated with the message.
+     */
+    public void notifyPendingMessageFailed(String transactionId) {
+        logi("notifyPendingMessageFailed: id=" + transactionId);
+        mSipSessionTracker.pendingMessageFailed(transactionId);
+    }
+
+    /** Dump state about this tracker that should be included in the dumpsys */
+    public void dump(PrintWriter printWriter) {
+        IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
+        pw.println("Supported Tags:" + mSupportedFeatureTags);
+        pw.println("Denied Tags:" + mDeniedFeatureTags);
+        pw.println(mOutgoingTransportStateValidator);
+        pw.println(mIncomingTransportStateValidator);
+        pw.println("Reg consumer pending: " + (mRegistrationAppliedConsumer != null));
+        pw.println("Close consumer pending: " + (mClosingCompleteConsumer != null));
+        pw.println();
+        mSipSessionTracker.dump(pw);
+        pw.println();
+        pw.println("Most recent logs:");
+        mLocalLog.dump(printWriter);
+    }
+
+    /**
+     * A event has occurred that can change the list of active call IDs.
+     */
+    private void onCallIdsChanged() {
+        if (getTrackedSipSessionCallIds().isEmpty() && mPendingClose != null
+                && !mPendingClose.isDone()) {
+            logi("onCallIdsChanged: no open sessions, completing any pending close events.");
+            // do not wait for timeout if pending sessions closed.
+            mPendingClose.cancel();
+            mPendingClose.run();
+        }
+        if (mPendingRegCleanup != null && !mPendingRegCleanup.isDone()) {
+            logi("onCallIdsChanged: updating pending reg cleanup task.");
+            // Recalculate the open call IDs based on the same feature tag set in the case that the
+            // call ID change has caused a change in pending reg cleanup task.
+            updatePendingRegCleanupTask(mPendingRegCleanup.featureTags);
+        }
+    }
+
+    /**
+     * If there are any pending registration clean up tasks, cancel them and clean up consumers.
+     */
+    private void cancelPendingRegCleanupTask() {
+        if (mPendingRegCleanup != null && !mPendingRegCleanup.isDone()) {
+            logi("cancelPendingRegCleanupTask: cancelling...");
+            mPendingRegCleanup.cancel();
+        }
+        cleanupAndNotifyRegistrationAppliedConsumer(Collections.emptySet());
+    }
+
+    /**
+     * Update the pending registration change clean up task based on the new set of restricted
+     * feature tags generated from the deregistering/deregistered feature tags.
+     *
+     * <p>
+     * This set of restricted tags will generate a set of call IDs associated to dialogs that
+     * are active and associated with the restricted tags. If there is no pending cleanup task, it
+     * will create a new one. If there was already a pending reg cleanup task, it will compare them
+     * and create a new one and cancel the old one if the new set of call ids is different from the
+     * old one.
+     */
+    private void updatePendingRegCleanupTask(Set<String> restrictedTags) {
+        Set<String> pendingCallIds = mSipSessionTracker.getCallIdsAssociatedWithFeatureTag(
+                restrictedTags);
+        if (pendingCallIds.isEmpty()) {
+            if (mPendingRegCleanup != null && !mPendingRegCleanup.isDone()) {
+                logi("updatePendingRegCleanupTask: no remaining call ids, finish cleanup task "
+                        + "now.");
+                mPendingRegCleanup.cancel();
+                mPendingRegCleanup.run();
+            } else {
+                if (mRegistrationAppliedConsumer != null) {
+                    logi("updatePendingRegCleanupTask: notify no pending call ids.");
+                    cleanupAndNotifyRegistrationAppliedConsumer(Collections.emptySet());
+                }
+            }
+            return;
+        }
+        if (mPendingRegCleanup != null && !mPendingRegCleanup.isDone()) {
+            if (mPendingRegCleanup.pendingCallIds.equals(pendingCallIds)) {
+                logi("updatePendingRegCleanupTask: pending reg change has same set of pending call"
+                        + " IDs, so keeping pending task");
+                return;
+            }
+            logi("updatePendingRegCleanupTask: cancelling, call ids have changed.");
+            mPendingRegCleanup.cancel();
+        }
+        mPendingRegCleanup = new PendingRegCleanupTask(restrictedTags, pendingCallIds) {
+            @Override
+            public void run() {
+                cleanupAndNotifyRegistrationAppliedConsumer(pendingCallIds);
+            }
+        };
+        logi("updatePendingRegCleanupTask: scheduling for call ids: " + pendingCallIds);
+        mPendingRegCleanup.scheduleDelayed(mExecutor, PENDING_REGISTRATION_CHANGE_TIMEOUT_MS);
+    }
+
+    /**
+     * Notify the pending registration applied consumer of the call ids that need to be cleaned up.
+     */
+    private void cleanupAndNotifyRegistrationAppliedConsumer(Set<String> pendingCallIds) {
+        if (mRegistrationAppliedConsumer != null) {
+            mRegistrationAppliedConsumer.accept(pendingCallIds);
+            mRegistrationAppliedConsumer = null;
+        }
+    }
+
+    /**
+     * Cancel any pending timeout to close pending sessions and send the provided call IDs to any
+     * pending closing complete consumer.
+     * @return {@code true} if a consumer was notified, {@code false} if there were no consumers.
+     */
+    private boolean cancelClosingTimeoutAndSendComplete(Set<String> openCallIds) {
+        if (mPendingClose != null && !mPendingClose.isDone()) {
+            logi("completing pending close consumer");
+            mPendingClose.cancel();
+        }
+        // Complete the pending consumer with no open sessions.
+        if (mClosingCompleteConsumer != null) {
+            mClosingCompleteConsumer.accept(openCallIds);
+            mClosingCompleteConsumer = null;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Close and clear all stateful trackers and validators.
+     */
+    private void closeSessionsInternal(int closedReason) {
+        cancelPendingRegCleanupTask();
+        mOutgoingTransportStateValidator.close(closedReason);
+        mIncomingTransportStateValidator.close(closedReason);
+        mSipSessionTracker.clearAllSessions();
+    }
+
+    private Set<String> getTrackedSipSessionCallIds() {
+        return mSipSessionTracker.getTrackedDialogs().stream().map(SipDialog::getCallId)
+                .collect(Collectors.toSet());
+    }
+
+    private void logi(String log) {
+        Log.i(SipTransportController.LOG_TAG, LOG_TAG + "[" + mSubId + "] " + log);
+        mLocalLog.log("[I] " + log);
+    }
+
+    private void logw(String log) {
+        Log.w(SipTransportController.LOG_TAG, LOG_TAG + "[" + mSubId + "] " + log);
+        mLocalLog.log("[W] " + log);
+    }
+}
diff --git a/src/com/android/services/telephony/rcs/UceControllerManager.java b/src/com/android/services/telephony/rcs/UceControllerManager.java
index d62fb5e..2897113 100644
--- a/src/com/android/services/telephony/rcs/UceControllerManager.java
+++ b/src/com/android/services/telephony/rcs/UceControllerManager.java
@@ -16,8 +16,10 @@
 
 package com.android.services.telephony.rcs;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.net.Uri;
+import android.telephony.SubscriptionManager;
 import android.telephony.ims.ImsException;
 import android.telephony.ims.RcsContactUceCapability;
 import android.telephony.ims.RcsUceAdapter;
@@ -52,37 +54,38 @@
     private final Context mContext;
     private final ExecutorService mExecutorService;
 
-    private volatile int mSubId;
-    private volatile UceController mUceController;
-    private volatile RcsFeatureManager mRcsFeatureManager;
+    private volatile @Nullable UceController mUceController;
+    private volatile @Nullable RcsFeatureManager mRcsFeatureManager;
 
     public UceControllerManager(Context context, int slotId, int subId) {
         Log.d(LOG_TAG, "create: slotId=" + slotId + ", subId=" + subId);
-
         mSlotId = slotId;
-        mSubId = subId;
         mContext = context;
         mExecutorService = Executors.newSingleThreadExecutor();
-        mUceController = new UceController(mContext, subId);
+        initUceController(subId);
     }
 
     /**
      * Constructor to inject dependencies for testing.
      */
     @VisibleForTesting
-    public UceControllerManager(Context context, int slotId, int subId, ExecutorService executor) {
+    public UceControllerManager(Context context, int slotId, ExecutorService executor,
+            UceController uceController) {
         mSlotId = slotId;
-        mSubId = subId;
         mContext = context;
         mExecutorService = executor;
-        mUceController = new UceController(mContext, subId);
+        mUceController = uceController;
     }
 
     @Override
     public void onRcsConnected(RcsFeatureManager manager) {
         mExecutorService.submit(() -> {
             mRcsFeatureManager = manager;
-            mUceController.onRcsConnected(manager);
+            if (mUceController != null) {
+                mUceController.onRcsConnected(manager);
+            } else {
+                Log.d(LOG_TAG, "onRcsConnected: UceController is null");
+            }
         });
     }
 
@@ -90,14 +93,22 @@
     public void onRcsDisconnected() {
         mExecutorService.submit(() -> {
             mRcsFeatureManager = null;
-            mUceController.onRcsDisconnected();
+            if (mUceController != null) {
+                mUceController.onRcsDisconnected();
+            } else {
+                Log.d(LOG_TAG, "onRcsDisconnected: UceController is null");
+            }
         });
     }
 
     @Override
     public void onDestroy() {
-        Log.d(LOG_TAG, "onDestroy");
-        mExecutorService.submit(() -> mUceController.onDestroy());
+        mExecutorService.submit(() -> {
+            Log.d(LOG_TAG, "onDestroy");
+            if (mUceController != null) {
+                mUceController.onDestroy();
+            }
+        });
         // When the shutdown is called, it will refuse any new tasks and let existing tasks finish.
         mExecutorService.shutdown();
     }
@@ -107,22 +118,17 @@
      * changed.
      */
     @Override
-    public void onAssociatedSubscriptionUpdated(int subId) {
+    public void onAssociatedSubscriptionUpdated(int newSubId) {
         mExecutorService.submit(() -> {
             Log.i(LOG_TAG, "onAssociatedSubscriptionUpdated: slotId=" + mSlotId
-                    + ", subId=" + mSubId + ", newSubId=" + subId);
-            if (mSubId == subId) {
-                Log.w(LOG_TAG, "onAssociatedSubscriptionUpdated called with the same subId");
-                return;
-            }
-            mSubId = subId;
-            // Destroy existing UceController and create a new one.
-            mUceController.onDestroy();
-            mUceController = new UceController(mContext, subId);
+                    + ", newSubId=" + newSubId);
+
+            // Check and create the UceController with the new updated subscription ID.
+            initUceController(newSubId);
 
             // The RCS should be connected when the mRcsFeatureManager is not null. Set it to the
             // new UceController instance.
-            if (mRcsFeatureManager != null) {
+            if (mUceController != null && mRcsFeatureManager != null) {
                 mUceController.onRcsConnected(mRcsFeatureManager);
             }
         });
@@ -135,16 +141,15 @@
     @Override
     public void onCarrierConfigChanged() {
         mExecutorService.submit(() -> {
-            Log.i(LOG_TAG, "onCarrierConfigChanged: subId=" + mSubId);
-            mUceController.onCarrierConfigChanged();
+            Log.i(LOG_TAG, "onCarrierConfigChanged");
+            if (mUceController != null) {
+                mUceController.onCarrierConfigChanged();
+            } else {
+                Log.d(LOG_TAG, "onCarrierConfigChanged: UceController is null");
+            }
         });
     }
 
-    @VisibleForTesting
-    public void setUceController(UceController uceController) {
-        mUceController = uceController;
-    }
-
     /**
      * Request the capabilities for contacts.
      *
@@ -328,6 +333,32 @@
     }
 
     /**
+     * Remove UCE requests cannot be sent to the network status.
+     * @return true if this command is successful.
+     */
+    public boolean removeUceRequestDisallowedStatus() throws ImsException {
+        Future<Boolean> future = mExecutorService.submit(() -> {
+            if (mUceController == null) {
+                throw new ImsException("UCE controller is null",
+                        ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+            }
+            mUceController.removeRequestDisallowedStatus();
+            return true;
+        });
+
+        try {
+            return future.get();
+        } catch (ExecutionException | InterruptedException e) {
+            Log.w(LOG_TAG, "removeUceRequestDisallowedStatus exception: " + e);
+            Throwable cause = e.getCause();
+            if (cause instanceof ImsException) {
+                throw (ImsException) cause;
+            }
+            return false;
+        }
+    }
+
+    /**
      * Register the Publish state changed callback.
      *
      * @throws ImsException if the ImsService connected to this controller is currently down.
@@ -368,6 +399,31 @@
         }
     }
 
+    /**
+     * Initialize the UceController instance associated with the given subscription ID.
+     * The existing UceController will be destroyed if the original subscription ID is different
+     * from the new subscription ID.
+     * If the new subscription ID is invalid, the UceController instance will be null.
+     */
+    private void initUceController(int newSubId) {
+        Log.d(LOG_TAG, "initUceController: newSubId=" + newSubId + ", current UceController subId="
+                + ((mUceController == null) ? "null" : mUceController.getSubId()));
+        if (mUceController == null) {
+            // Create new UceController only when the subscription ID is valid.
+            if (SubscriptionManager.isValidSubscriptionId(newSubId)) {
+                mUceController = new UceController(mContext, newSubId);
+            }
+        } else if (mUceController.getSubId() != newSubId) {
+            // The subscription ID is updated. Remove the old UceController instance.
+            mUceController.onDestroy();
+            mUceController = null;
+            // Create new UceController only when the subscription ID is valid.
+            if (SubscriptionManager.isValidSubscriptionId(newSubId)) {
+                mUceController = new UceController(mContext, newSubId);
+            }
+        }
+    }
+
     private boolean checkUceControllerState() throws ImsException {
         if (mUceController == null || mUceController.isUnavailable()) {
             throw new ImsException("UCE controller is unavailable",
@@ -376,13 +432,26 @@
         return true;
     }
 
+    /**
+     * Get the UceController instance.
+     * <p>
+     * Used for testing ONLY.
+     */
+    @VisibleForTesting
+    public UceController getUceController() {
+        return mUceController;
+    }
 
     @Override
     public void dump(PrintWriter printWriter) {
         IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
         pw.println("UceControllerManager" + "[" + mSlotId + "]:");
         pw.increaseIndent();
-        mUceController.dump(pw);
+        if (mUceController != null) {
+            mUceController.dump(pw);
+        } else {
+            pw.println("UceController is null.");
+        }
         pw.decreaseIndent();
     }
 }
diff --git a/src/com/android/services/telephony/rcs/validator/IncomingTransportStateValidator.java b/src/com/android/services/telephony/rcs/validator/IncomingTransportStateValidator.java
new file mode 100644
index 0000000..24ab45e
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/validator/IncomingTransportStateValidator.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2021 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.rcs.validator;
+
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+import android.util.ArrayMap;
+
+/**
+ * Tracks the incoming SIP message transport state from the ImsService to the remote IMS
+ * application. Validates incoming SIP messages based on this state.
+ */
+public class IncomingTransportStateValidator implements SipMessageValidator {
+
+    /**
+     * The message transport is closed, meaning there can be no more incoming messages
+     */
+    private static final int STATE_CLOSED = 0;
+
+    /**
+     * The message transport is open and incoming traffic is not restricted.
+     */
+    private static final int STATE_OPEN = 1;
+
+    private static final ArrayMap<Integer, String> ENUM_TO_STRING_MAP  = new ArrayMap<>(2);
+    static {
+        ENUM_TO_STRING_MAP.append(STATE_CLOSED, "CLOSED");
+        ENUM_TO_STRING_MAP.append(STATE_OPEN, "OPEN");
+    }
+
+    private int mState = STATE_CLOSED;
+    private int mReason = SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED;
+
+    /**
+     * The SIP message transport is open and will successfully validate SIP messages.
+     */
+    public void open() {
+        mState = STATE_OPEN;
+        mReason = -1;
+    }
+
+    /**
+     * The SIP message transport is closed for incoming SIP messages.
+     * @param reason The error reason sent in response to any incoming SIP messages requests.
+     */
+    public void close(int reason) {
+        mState = STATE_CLOSED;
+        mReason = reason;
+    }
+
+    @Override
+    public ValidationResult validate(SipMessage message) {
+        if (mState != STATE_OPEN) {
+            return new ValidationResult(mReason,
+                    "incoming transport closed");
+        }
+        return ValidationResult.SUCCESS;
+    }
+
+    @Override
+    public String toString() {
+        return "Incoming Transport State: " + ENUM_TO_STRING_MAP.getOrDefault(mState,
+                String.valueOf(mState)) + ", reason: "
+                + SipDelegateManager.MESSAGE_FAILURE_REASON_STRING_MAP.getOrDefault(mReason,
+                String.valueOf(mReason));
+    }
+}
diff --git a/src/com/android/services/telephony/rcs/validator/MalformedSipMessageValidator.java b/src/com/android/services/telephony/rcs/validator/MalformedSipMessageValidator.java
new file mode 100644
index 0000000..a76ac3e
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/validator/MalformedSipMessageValidator.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 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.rcs.validator;
+
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+
+import com.android.internal.telephony.SipMessageParsingUtils;
+
+/**
+ * Validates that the SipMessage is not malformed before sending the message to the vendor
+ * ImsService by ensuring:
+ * <ul>The SipMessage is a valid SIP request or SIP response.</ul>
+ */
+public class MalformedSipMessageValidator implements SipMessageValidator {
+
+    @Override
+    public ValidationResult validate(SipMessage message) {
+        // Verify the request and response start lines are valid.
+        if (!SipMessageParsingUtils.isSipRequest(message.getStartLine())
+                && !SipMessageParsingUtils.isSipResponse(message.getStartLine())) {
+            return new ValidationResult(
+                    SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_START_LINE,
+                    "malformed start line: " + message.getStartLine());
+        }
+        return ValidationResult.SUCCESS;
+    }
+}
diff --git a/src/com/android/services/telephony/rcs/validator/OutgoingTransportStateValidator.java b/src/com/android/services/telephony/rcs/validator/OutgoingTransportStateValidator.java
new file mode 100644
index 0000000..72d22f8
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/validator/OutgoingTransportStateValidator.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2021 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.rcs.validator;
+
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.telephony.SipMessageParsingUtils;
+import com.android.services.telephony.rcs.SipDialog;
+import com.android.services.telephony.rcs.SipSessionTracker;
+import com.android.services.telephony.rcs.SipTransportController;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Tracks the state of the outgoing SIP message transport from the remote IMS application to the
+ * ImsService. Used to validate outgoing SIP messages based off of this state.
+ */
+public class OutgoingTransportStateValidator implements SipMessageValidator {
+
+    /**
+     * The message transport is closed, meaning there can be no more outgoing messages
+     */
+    private static final int STATE_CLOSED = 0;
+
+    /**
+     * The message transport is restricted to only in-dialog outgoing traffic
+     */
+    private static final int STATE_RESTRICTED = 1;
+
+    /**
+     * The message transport is open and outgoing traffic is not restricted.
+     */
+    private static final int STATE_OPEN = 2;
+
+    private static final ArrayMap<Integer, String> ENUM_TO_STRING_MAP  = new ArrayMap<>(3);
+    static {
+        ENUM_TO_STRING_MAP.append(STATE_CLOSED, "CLOSED");
+        ENUM_TO_STRING_MAP.append(STATE_RESTRICTED, "RESTRICTED");
+        ENUM_TO_STRING_MAP.append(STATE_OPEN, "OPEN");
+    }
+
+    private final SipSessionTracker mSipSessionTracker;
+    private int mState = STATE_CLOSED;
+    private int mReason = SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED;
+    private Set<String> mAllowedTags = Collections.emptySet();
+    private Set<String> mDeniedTags = Collections.emptySet();
+    private Set<String> mRestrictedFeatureTags;
+
+    public OutgoingTransportStateValidator(SipSessionTracker sessionTracker) {
+        mSipSessionTracker = sessionTracker;
+    }
+
+    /**
+     * The SIP message transport is open and will successfully validate both in and out of dialog
+     * SIP messages.
+     */
+    public void open(Set<String> allowedFeatureTags, Set<String> deniedFeatureTags) {
+        mState = STATE_OPEN;
+        mReason = -1;
+        // This is for validation, so try to reduce matching errors due to upper/lower case.
+        mAllowedTags = allowedFeatureTags.stream().map(String::trim).map(String::toLowerCase)
+                .collect(Collectors.toSet());
+        mDeniedTags = deniedFeatureTags.stream().map(String::trim).map(String::toLowerCase)
+                .collect(Collectors.toSet());
+        mRestrictedFeatureTags = null;
+    }
+
+    /**
+     * Restrict the starting of dialogs for specific feature tags, excluding requests associated
+     * with ongoing sessions.
+     * @param restrictedFeatureTags The feature tags that are deregistering or deregistered and can
+     *                              not have new dialogs associated with them.
+     */
+    public void restrictFeatureTags(Set<String> restrictedFeatureTags) {
+        // This is for validation, so try to reduce matching errors due to upper/lower case.
+        mRestrictedFeatureTags = restrictedFeatureTags.stream().map(String::trim)
+                .map(String::toLowerCase).collect(Collectors.toSet());
+    }
+
+    /**
+     * The SIP message transport is restricted and only allows in-dialog outgoing messages.
+     * @param reason The reason that will be returned to outgoing out-of-dialog SIP messages that
+     *               are denied.
+     */
+    public void restrict(int reason) {
+        mState = STATE_RESTRICTED;
+        mReason = reason;
+    }
+
+    /**
+     * The SIP message transport is closed for outgoing SIP messages.
+     * @param reason The error reason sent in response to any outgoing SIP messages requests.
+     */
+    public void close(int reason) {
+        mState = STATE_CLOSED;
+        mReason = reason;
+        mAllowedTags = Collections.emptySet();
+    }
+
+    @Override
+    public ValidationResult validate(SipMessage message) {
+        switch (mState) {
+            case STATE_CLOSED:
+                return new ValidationResult(mReason, "outgoing transport closed.");
+            case STATE_RESTRICTED:
+                return verifyRestrictedMessage(message);
+            case STATE_OPEN:
+                return verifyOpenMessage(message);
+            default:
+                Log.w(SipTransportController.LOG_TAG, "OutgoingTSV - warning, unexpected state");
+                return ValidationResult.SUCCESS;
+        }
+    }
+
+    public Set<String> getAllowedCallIds() {
+        return Stream.concat(mSipSessionTracker.getEarlyDialogs().stream(),
+                mSipSessionTracker.getConfirmedDialogs().stream()).map(SipDialog::getCallId)
+                .collect(Collectors.toSet());
+    }
+
+    @Override
+    public String toString() {
+        return "Outgoing Transport State: " + ENUM_TO_STRING_MAP.getOrDefault(mState,
+                String.valueOf(mState)) + ", reason: "
+                + SipDelegateManager.MESSAGE_FAILURE_REASON_STRING_MAP.getOrDefault(mReason,
+                String.valueOf(mReason)) + ", allowed tags: " + mAllowedTags + ", restricted tags: "
+                + mRestrictedFeatureTags + ", denied tags: " + mDeniedTags;
+    }
+
+    private ValidationResult verifyOpenMessage(SipMessage m) {
+        // No need to validate responses to requests.
+        if (!SipMessageParsingUtils.isSipRequest(m.getStartLine())) {
+            return ValidationResult.SUCCESS;
+        }
+        if (mRestrictedFeatureTags == null) {
+            return new ValidationResult(SipDelegateManager.MESSAGE_FAILURE_REASON_NOT_REGISTERED,
+                    "no reg state from vendor");
+        }
+        String[] segments = SipMessageParsingUtils.splitStartLineAndVerify(m.getStartLine());
+        if (segments == null) {
+            return new ValidationResult(
+                    SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_START_LINE,
+                    "couldn't parse start line: " + m.getStartLine());
+        }
+        // Only need to validate requests that start dialogs.
+        boolean startsDialog = Arrays.stream(SipSessionTracker.SIP_REQUEST_DIALOG_START_METHODS)
+                .anyMatch(req -> req.equals(segments[0].trim().toLowerCase()));
+        // If part of an existing dialog, then no need to validate.
+        boolean needsFeatureValidation = startsDialog && !getAllowedCallIds()
+                .contains(m.getCallIdParameter());
+        if (needsFeatureValidation) {
+            return validateMessageFeatureTag(m);
+        }
+        return ValidationResult.SUCCESS;
+    }
+
+    /**
+     * Compares the "Accept-Contact" header against the supported/denied feature tags and ensures
+     * that there are no restricted or denied tags included.
+     */
+    private ValidationResult validateMessageFeatureTag(SipMessage m) {
+        Set<String> featureTags = SipMessageParsingUtils.getAcceptContactFeatureTags(
+                m.getHeaderSection());
+        // Get rid of potential formatting issues first.
+        featureTags = featureTags.stream().map(String::toLowerCase).map(String::trim)
+                .collect(Collectors.toSet());
+        long acceptedFeatureTagCount = featureTags.stream()
+                .filter(f -> mAllowedTags.contains(f)).count();
+        long deniedFeatureTagCount = featureTags.stream()
+                .filter(f -> mDeniedTags.contains(f)).count();
+        long restrictedFeatureTagCount = featureTags.stream()
+                .filter(f -> mRestrictedFeatureTags.contains(f)).count();
+        // we should not have any feature tags that are denied/restricted and there should be at
+        // least one accepted tag
+        if (deniedFeatureTagCount > 0) {
+            return new ValidationResult(
+                    SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG,
+                    "contains denied tags in Accept-Contact: " + featureTags);
+        }
+        if (restrictedFeatureTagCount > 0) {
+            return new ValidationResult(
+                    SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG,
+                    "contains restricted tags in Accept-Contact: " + featureTags);
+        }
+
+        if (acceptedFeatureTagCount == 0) {
+            return new ValidationResult(
+                    SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG,
+                    "No Accept-Contact feature tags are in accepted feature tag list: "
+                            + featureTags);
+        }
+
+        return ValidationResult.SUCCESS;
+    }
+
+    private ValidationResult verifyRestrictedMessage(SipMessage m) {
+        // The validator is in the restricted state, so only in dialog requests and all responses
+        // are allowed.
+        if (!SipMessageParsingUtils.isSipRequest(m.getStartLine())) {
+            return ValidationResult.SUCCESS;
+        }
+        String callId = m.getCallIdParameter();
+        if (TextUtils.isEmpty(callId)) {
+            return new ValidationResult(mReason, "empty call id");
+        }
+        Set<String> mAllowedCallIds = getAllowedCallIds();
+        if (!mAllowedCallIds.contains(callId)) {
+            return new ValidationResult(mReason, "call id " + callId + " is not associated with"
+                    + " any active sessions");
+        }
+        return ValidationResult.SUCCESS;
+    }
+}
diff --git a/src/com/android/services/telephony/rcs/validator/RestrictedOutgoingSipRequestValidator.java b/src/com/android/services/telephony/rcs/validator/RestrictedOutgoingSipRequestValidator.java
new file mode 100644
index 0000000..2c2632f
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/validator/RestrictedOutgoingSipRequestValidator.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 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.rcs.validator;
+
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+
+import com.android.internal.telephony.SipMessageParsingUtils;
+
+import java.util.Arrays;
+
+/**
+ * Validate that any outgoing SIP request message does not contain methods that are only generated
+ * internally by the ImsService implementation.
+ */
+public class RestrictedOutgoingSipRequestValidator implements SipMessageValidator {
+
+    /**
+     * These SIP requests are always handled by the ImsService and are restricted to being
+     * generated internally. Messages with these request methods should fail validation.
+     */
+    private static final String[] IMS_SERVICE_HANDLED_REQUEST_METHODS = new String[]{
+            "register", "options", "publish"};
+
+    @Override
+    public ValidationResult validate(SipMessage message) {
+        String startLine = message.getStartLine();
+        if (SipMessageParsingUtils.isSipRequest(startLine)) {
+            String[] segments = SipMessageParsingUtils.splitStartLineAndVerify(startLine);
+            if (segments == null) {
+                return new ValidationResult(
+                        SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_START_LINE,
+                        "malformed start line: " + message.getStartLine());
+            }
+            if (Arrays.stream(IMS_SERVICE_HANDLED_REQUEST_METHODS).anyMatch(
+                    s -> segments[0].toLowerCase().contains(s))) {
+                return new ValidationResult(
+                        SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_START_LINE,
+                        "restricted method: " + segments[0]);
+            }
+        }
+        return ValidationResult.SUCCESS;
+    }
+}
diff --git a/src/com/android/services/telephony/rcs/validator/RestrictedOutgoingSubscribeValidator.java b/src/com/android/services/telephony/rcs/validator/RestrictedOutgoingSubscribeValidator.java
new file mode 100644
index 0000000..41074ed
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/validator/RestrictedOutgoingSubscribeValidator.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 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.rcs.validator;
+
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+import android.util.Pair;
+
+import com.android.internal.telephony.SipMessageParsingUtils;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Ensure that if there is an outgoing SUBSCRIBE request, that it does not contain the "Event"
+ * header "presence"
+ */
+public class RestrictedOutgoingSubscribeValidator implements SipMessageValidator {
+
+    private static final String SUBSCRIBE_REQUEST = "subscribe";
+    private static final String SUBSCRIBE_EVENT_HEADER = "event";
+    private static final String[] RESTRICTED_EVENTS = new String[]{ "presence" };
+
+
+    @Override
+    public ValidationResult validate(SipMessage message) {
+        if (!SipMessageParsingUtils.isSipRequest(message.getStartLine())) {
+            return ValidationResult.SUCCESS;
+        }
+        String[] requestSegments = SipMessageParsingUtils.splitStartLineAndVerify(
+                message.getStartLine());
+        if (requestSegments == null) {
+            return new ValidationResult(
+                    SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_START_LINE,
+                    "malformed start line: " + message.getStartLine());
+        }
+        // Request-Line  =  Method SP Request-URI SP SIP-Version CRLF, verify Method
+        if (!requestSegments[0].equalsIgnoreCase(SUBSCRIBE_REQUEST)) {
+            return ValidationResult.SUCCESS;
+        }
+
+        List<Pair<String, String>> eventHeaders = SipMessageParsingUtils.parseHeaders(
+                message.getHeaderSection(), true /*stopAtFirstMatch*/, SUBSCRIBE_EVENT_HEADER);
+        if (eventHeaders.size() == 0) {
+            return ValidationResult.SUCCESS;
+        }
+        boolean isRestricted = eventHeaders.stream().map(e -> e.second)
+                .anyMatch(e -> Arrays.asList(RESTRICTED_EVENTS).contains(e.trim().toLowerCase()));
+
+        return isRestricted ? new ValidationResult(
+                SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS,
+                "matched a restricted header field: " + eventHeaders.stream().map(e -> e.second)
+                        .collect(Collectors.toSet())) :
+                ValidationResult.SUCCESS;
+    }
+}
diff --git a/src/com/android/services/telephony/rcs/validator/SipMessageValidator.java b/src/com/android/services/telephony/rcs/validator/SipMessageValidator.java
new file mode 100644
index 0000000..6bbfbf4
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/validator/SipMessageValidator.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 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.rcs.validator;
+
+import android.telephony.ims.SipMessage;
+
+/**
+ * Validates a SipMessage and returns the result via an instance of {@link ValidationResult}.
+ */
+public interface SipMessageValidator {
+    /**
+     * Validate that the SipMessage is allowed to be sent to the remote.
+     * @param message The SipMessage being validated.
+     * @return A {@link ValidationResult} that represents whether or not the message was validated.
+     * If not validated, it also returns a reason why the SIP message was not validated.
+     */
+    ValidationResult validate(SipMessage message);
+
+    /**
+     * Compose a SipMessageValidator out of two validators, this validator running before the next
+     * validator.
+     * @param next The next validator that will be run if this validator validates the message
+     *             successfully.
+     * @return A new SipMessageValidator composed of this validator and the next one.
+     */
+    default SipMessageValidator andThen(SipMessageValidator next) {
+        return (SipMessage m) -> {
+            ValidationResult result = validate(m);
+            if (!result.isValidated) return result;
+            return next.validate(m);
+        };
+    }
+}
diff --git a/src/com/android/services/telephony/rcs/validator/ValidationResult.java b/src/com/android/services/telephony/rcs/validator/ValidationResult.java
new file mode 100644
index 0000000..e434163
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/validator/ValidationResult.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2021 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.rcs.validator;
+
+import android.telephony.ims.SipDelegateManager;
+
+/**
+ * Communicates the result of validating whether a SIP message should be sent to a remote based on
+ * the contents of the SIP message as well as if the transport is in an appropriate state for the
+ * intended recipient of the message.
+ */
+public class ValidationResult {
+    public static final ValidationResult SUCCESS = new ValidationResult();
+
+    /**
+     * If {@code true}, the requested SIP message has been validated and may be sent to the remote.
+     * If {@code false}, the SIP message has failed validation and should not be sent to the
+     * remote. The {@link #restrictedReason} field will contain the reason for the validation
+     * failure.
+     */
+    public final boolean isValidated;
+
+    /**
+     * The reason associated with why the SIP message was not verified and generated a
+     * {@code false} result for {@link #isValidated}.
+     */
+    public final int restrictedReason;
+
+    /**
+     * The human readable reason for why the validation failed for logging.
+     */
+    public final String logReason;
+
+    /**
+     * Communicates a validated result of success. Use {@link #SUCCESS} instead.
+     */
+    private ValidationResult() {
+        isValidated = true;
+        restrictedReason = SipDelegateManager.MESSAGE_FAILURE_REASON_UNKNOWN;
+        logReason = "";
+    }
+
+    /**
+     * The result of validating that the SIP Message should be sent.
+     *
+     * @param reason The reason associated with why the SIP message was not validated and
+     *               generated a {@code false} result for {@link #isValidated}.
+     */
+    public ValidationResult(@SipDelegateManager.MessageFailureReason int reason, String log) {
+        isValidated = false;
+        restrictedReason = reason;
+        logReason = log;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder b = new StringBuilder();
+        b.append("ValidationResult{");
+        b.append("validated=");
+        b.append(isValidated);
+        if (!isValidated) {
+            b.append(", restrictedReason=");
+            b.append(restrictedReason);
+            b.append(", logReason=");
+            b.append(logReason);
+        }
+        b.append('}');
+        return b.toString();
+    }
+}
diff --git a/testapps/GbaTestApp/res/values-es/strings.xml b/testapps/GbaTestApp/res/values-es/strings.xml
index bde5d92..269ea86 100644
--- a/testapps/GbaTestApp/res/values-es/strings.xml
+++ b/testapps/GbaTestApp/res/values-es/strings.xml
@@ -10,7 +10,7 @@
     <string name="button_name_exit" msgid="8025683733431538975">"Salir"</string>
     <string name="label_test_result" msgid="892984695972956196">"Resultado de la prueba"</string>
     <string name="button_name_clear" msgid="436313515327318537">"Restablecer"</string>
-    <string name="button_name_done" msgid="6030406534322497491">"Listo"</string>
+    <string name="button_name_done" msgid="6030406534322497491">"Hecho"</string>
     <string name="title_activity_carrier_config" msgid="7807803900475957717">"CarrierConfigActivity"</string>
     <string name="title_activity_service_config" msgid="5394662739555577279">"ServiceConfigActivity"</string>
     <string name="title_activity_test_config" msgid="7585204485536359713">"TestConfigActivity"</string>
diff --git a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java
index 7f751d6..1407671 100644
--- a/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java
+++ b/testapps/TestRcsApp/TestApp/src/com/google/android/sample/rcsclient/DelegateActivity.java
@@ -26,8 +26,8 @@
 import android.telephony.ims.FeatureTagState;
 import android.telephony.ims.ImsException;
 import android.telephony.ims.ImsManager;
+import android.telephony.ims.SipDelegateConfiguration;
 import android.telephony.ims.SipDelegateConnection;
-import android.telephony.ims.SipDelegateImsConfiguration;
 import android.telephony.ims.SipDelegateManager;
 import android.telephony.ims.SipMessage;
 import android.telephony.ims.stub.DelegateConnectionMessageCallback;
@@ -125,15 +125,16 @@
                 }
 
                 @Override
-                public void onImsConfigurationChanged(
-                        SipDelegateImsConfiguration registeredSipConfig) {
-                    mCallbackResultStr += "onImsConfigurationChanged SipDelegateImsConfiguration:"
-                            + registeredSipConfig + "\r\n\r\n";
-                    Log.i(TAG, mCallbackResultStr);
+                public void onConfigurationChanged(
+                        SipDelegateConfiguration registeredSipConfig) {
+                    mCallbackResultStr += "onConfigurationChanged SipDelegateConfiguration:"
+                            + "\r\n\r\n";
+                    Log.i(TAG, "onConfigurationChanged: " + registeredSipConfig);
                     mHandler.sendMessage(mHandler.obtainMessage(MSG_RESULT));
                     dumpConfig(registeredSipConfig);
                 }
 
+
                 @Override
                 public void onFeatureTagStatusChanged(
                         @NonNull DelegateRegistrationState registrationState,
@@ -326,81 +327,33 @@
 
     }
 
-    private void dumpConfig(SipDelegateImsConfiguration config) {
-        Log.i(TAG, "KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING:" + config.getString(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING));
-        Log.i(TAG, "KEY_SIP_CONFIG_UE_PUBLIC_USER_ID_STRING:" + config.getString(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_PUBLIC_USER_ID_STRING));
-        Log.i(TAG, "KEY_SIP_CONFIG_UE_PRIVATE_USER_ID_STRING:" + config.getString(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_PRIVATE_USER_ID_STRING));
-        Log.i(TAG, "KEY_SIP_CONFIG_HOME_DOMAIN_STRING:" + config.getString(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_HOME_DOMAIN_STRING));
-        Log.i(TAG, "KEY_SIP_CONFIG_IMEI_STRING:" + config.getString(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING));
-        Log.i(TAG, "KEY_SIP_CONFIG_IPTYPE_STRING:" + config.getString(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_IPTYPE_STRING));
-        Log.i(TAG, "KEY_SIP_CONFIG_UE_DEFAULT_IPADDRESS_STRING:" + config.getString(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_DEFAULT_IPADDRESS_STRING));
-        Log.i(TAG, "KEY_SIP_CONFIG_SERVER_DEFAULT_IPADDRESS_STRING:" + config.getString(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_SERVER_DEFAULT_IPADDRESS_STRING));
-        Log.i(TAG, "KEY_SIP_CONFIG_UE_PUBLIC_IPADDRESS_WITH_NAT_STRING:" + config.getString(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_PUBLIC_IPADDRESS_WITH_NAT_STRING));
-        Log.i(TAG, "KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING:" + config.getString(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING));
-        Log.i(TAG, "KEY_SIP_CONFIG_AUTHENTICATION_HEADER_STRING:" + config.getString(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_AUTHENTICATION_HEADER_STRING));
-        Log.i(TAG, "KEY_SIP_CONFIG_AUTHENTICATION_NONCE_STRING:" + config.getString(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_AUTHENTICATION_NONCE_STRING));
-        Log.i(TAG, "KEY_SIP_CONFIG_SERVICE_ROUTE_HEADER_STRING:" + config.getString(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_SERVICE_ROUTE_HEADER_STRING));
-        Log.i(TAG, "KEY_SIP_CONFIG_SECURITY_VERIFY_HEADER_STRING:" + config.getString(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_SECURITY_VERIFY_HEADER_STRING));
-        Log.i(TAG, "KEY_SIP_CONFIG_PATH_HEADER_STRING:" + config.getString(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_PATH_HEADER_STRING));
-        Log.i(TAG, "KEY_SIP_CONFIG_URI_USER_PART_STRING:" + config.getString(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_URI_USER_PART_STRING));
-        Log.i(TAG, "KEY_SIP_CONFIG_P_ACCESS_NETWORK_INFO_HEADER_STRING:"
-                + config.getString(SipDelegateImsConfiguration
-                .KEY_SIP_CONFIG_P_ACCESS_NETWORK_INFO_HEADER_STRING));
-        Log.i(TAG, "KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING:"
-                + config.getString(SipDelegateImsConfiguration
-                .KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING));
-        Log.i(TAG, "KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING:"
-                + config.getString(SipDelegateImsConfiguration
-                .KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING));
-        Log.i(TAG, "KEY_SIP_CONFIG_USER_AGENT_HEADER_STRING:" + config.getString(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_USER_AGENT_HEADER_STRING));
-
-        Log.i(TAG, "KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT:" + config.getInt(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT, -99));
-        Log.i(TAG, "KEY_SIP_CONFIG_UE_DEFAULT_PORT_INT:" + config.getInt(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_DEFAULT_PORT_INT, -99));
-        Log.i(TAG, "KEY_SIP_CONFIG_SERVER_DEFAULT_PORT_INT:" + config.getInt(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_SERVER_DEFAULT_PORT_INT, -99));
-        Log.i(TAG, "KEY_SIP_CONFIG_UE_PUBLIC_PORT_WITH_NAT_INT:" + config.getInt(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_PUBLIC_PORT_WITH_NAT_INT, -99));
-        Log.i(TAG, "KEY_SIP_CONFIG_UE_IPSEC_CLIENT_PORT_INT:" + config.getInt(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_IPSEC_CLIENT_PORT_INT, -99));
-        Log.i(TAG, "KEY_SIP_CONFIG_UE_IPSEC_SERVER_PORT_INT:" + config.getInt(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_IPSEC_SERVER_PORT_INT, -99));
-        Log.i(TAG, "KEY_SIP_CONFIG_UE_IPSEC_OLD_CLIENT_PORT_INT:" + config.getInt(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_IPSEC_OLD_CLIENT_PORT_INT, -99));
-        Log.i(TAG, "KEY_SIP_CONFIG_SERVER_IPSEC_CLIENT_PORT_INT:" + config.getInt(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_SERVER_IPSEC_CLIENT_PORT_INT, -99));
-        Log.i(TAG, "KEY_SIP_CONFIG_SERVER_IPSEC_SERVER_PORT_INT:" + config.getInt(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_SERVER_IPSEC_SERVER_PORT_INT, -99));
-        Log.i(TAG, "KEY_SIP_CONFIG_SERVER_IPSEC_OLD_CLIENT_PORT_INT:" + config.getInt(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_SERVER_IPSEC_OLD_CLIENT_PORT_INT, -99));
-
-        Log.i(TAG, "KEY_SIP_CONFIG_IS_COMPACT_FORM_ENABLED_BOOL:" + config.getBoolean(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_COMPACT_FORM_ENABLED_BOOL, false));
-        Log.i(TAG, "KEY_SIP_CONFIG_IS_KEEPALIVE_ENABLED_BOOL:" + config.getBoolean(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_KEEPALIVE_ENABLED_BOOL, false));
-        Log.i(TAG, "KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL:" + config.getBoolean(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL, false));
-        Log.i(TAG, "KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL:" + config.getBoolean(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL, false));
-        Log.i(TAG, "KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL:" + config.getBoolean(
-                SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL, false));
+    private void dumpConfig(SipDelegateConfiguration config) {
+        String result = "SipDelegateConfiguration{"
+                + "mVersion=" + config.getVersion()
+                + ", \n\tmTransportType=" + config.getTransportType()
+                + ", \n\tmLocalIpAddr=" + config.getLocalAddress()
+                + ", \n\tmSipServerAddr=" + config.getSipServerAddress()
+                + ", \n\tmIsSipCompactFormEnabled=" + config.isSipCompactFormEnabled()
+                + ", \n\tmIsSipKeepaliveEnabled=" + config.isSipKeepaliveEnabled()
+                + ", \n\tmMaxUdpPayloadSize=" + config.getMaxUdpPayloadSizeBytes()
+                + ", \n\tmPublicUserIdentifier=" + config.getPublicUserIdentifier()
+                + ", \n\tmPrivateUserIdentifier=" + config.getPrivateUserIdentifier()
+                + ", \n\tmHomeDomain=" + config.getHomeDomain()
+                + ", \n\tmImei=" + config.getImei()
+                + ", \n\tmGruu=" + config.getPublicGruuUri()
+                + ", \n\tmSipAuthHeader=" + config.getSipAuthenticationHeader()
+                + ", \n\tmSipAuthNonce=" + config.getSipAuthenticationNonce()
+                + ", \n\tmServiceRouteHeader=" + config.getSipServiceRouteHeader()
+                + ", \n\tmPathHeader=" + config.getSipPathHeader()
+                + ", \n\tmUserAgentHeader=" + config.getSipUserAgentHeader()
+                + ", \n\tmContactUserParam=" + config.getSipContactUserParameter()
+                + ", \n\tmPaniHeader=" + config.getSipPaniHeader()
+                + ", \n\tmPlaniHeader=" + config.getSipPlaniHeader()
+                + ", \n\tmCniHeader=" + config.getSipCniHeader()
+                + ", \n\tmAssociatedUriHeader=" + config.getSipAssociatedUriHeader()
+                + ", \n\tmIpSecConfiguration=" + config.getIpSecConfiguration()
+                + ", \n\tmNatConfiguration=" + config.getNatSocketAddress() + '}';
+        Log.i(TAG, result);
     }
+
 }
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java
index 9ababc3..6a70f3d 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/registration/RegistrationControllerImpl.java
@@ -22,8 +22,8 @@
 import android.telephony.ims.FeatureTagState;
 import android.telephony.ims.ImsException;
 import android.telephony.ims.ImsManager;
+import android.telephony.ims.SipDelegateConfiguration;
 import android.telephony.ims.SipDelegateConnection;
-import android.telephony.ims.SipDelegateImsConfiguration;
 import android.telephony.ims.SipDelegateManager;
 import android.telephony.ims.SipMessage;
 import android.telephony.ims.stub.DelegateConnectionMessageCallback;
@@ -109,7 +109,7 @@
         private final SettableFuture<SipSession> sessionFuture = SettableFuture.create();
 
         protected SipDelegateConnection sipDelegateConnection;
-        private SipDelegateImsConfiguration configuration;
+        private SipDelegateConfiguration mConfiguration;
         private final DelegateConnectionStateCallback connectionCallback =
                 new DelegateConnectionStateCallback() {
 
@@ -119,16 +119,15 @@
                     }
 
                     @Override
-                    public void onImsConfigurationChanged(
-                            SipDelegateImsConfiguration registeredSipConfig) {
+                    public void onConfigurationChanged(
+                            SipDelegateConfiguration registeredSipConfig) {
                         Log.d(
                                 TAG,
                                 "onSipConfigurationChanged: version="
-                                        + registeredSipConfig.getVersion()
-                                        + " bundle="
-                                        + registeredSipConfig.copyBundle());
+                                        + registeredSipConfig.getVersion());
+                        Log.i(TAG, "onSipConfigurationChanged: " + registeredSipConfig);
                         dumpConfig(registeredSipConfig);
-                        RegistrationContext.this.configuration = registeredSipConfig;
+                        RegistrationContext.this.mConfiguration = registeredSipConfig;
                     }
 
                     @Override
@@ -233,84 +232,33 @@
             Log.i(TAG, result);
         }
 
-        private void dumpConfig(SipDelegateImsConfiguration config) {
-            Log.i(TAG, "KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING:" + config.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING));
-            Log.i(TAG, "KEY_SIP_CONFIG_UE_PUBLIC_USER_ID_STRING:" + config.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_PUBLIC_USER_ID_STRING));
-            Log.i(TAG, "KEY_SIP_CONFIG_UE_PRIVATE_USER_ID_STRING:" + config.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_PRIVATE_USER_ID_STRING));
-            Log.i(TAG, "KEY_SIP_CONFIG_HOME_DOMAIN_STRING:" + config.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_HOME_DOMAIN_STRING));
-            Log.i(TAG, "KEY_SIP_CONFIG_IMEI_STRING:" + config.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING));
-            Log.i(TAG, "KEY_SIP_CONFIG_IPTYPE_STRING:" + config.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_IPTYPE_STRING));
-            Log.i(TAG, "KEY_SIP_CONFIG_UE_DEFAULT_IPADDRESS_STRING:" + config.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_DEFAULT_IPADDRESS_STRING));
-            Log.i(TAG, "KEY_SIP_CONFIG_SERVER_DEFAULT_IPADDRESS_STRING:" + config.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_SERVER_DEFAULT_IPADDRESS_STRING));
-            Log.i(TAG, "KEY_SIP_CONFIG_UE_PUBLIC_IPADDRESS_WITH_NAT_STRING:" +
-                    config.getString(SipDelegateImsConfiguration.
-                            KEY_SIP_CONFIG_UE_PUBLIC_IPADDRESS_WITH_NAT_STRING));
-            Log.i(TAG, "KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING:" + config.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING));
-            Log.i(TAG, "KEY_SIP_CONFIG_AUTHENTICATION_HEADER_STRING:" + config.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_AUTHENTICATION_HEADER_STRING));
-            Log.i(TAG, "KEY_SIP_CONFIG_AUTHENTICATION_NONCE_STRING:" + config.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_AUTHENTICATION_NONCE_STRING));
-            Log.i(TAG, "KEY_SIP_CONFIG_SERVICE_ROUTE_HEADER_STRING:" + config.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_SERVICE_ROUTE_HEADER_STRING));
-            Log.i(TAG, "KEY_SIP_CONFIG_SECURITY_VERIFY_HEADER_STRING:" + config.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_SECURITY_VERIFY_HEADER_STRING));
-            Log.i(TAG, "KEY_SIP_CONFIG_PATH_HEADER_STRING:" + config.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_PATH_HEADER_STRING));
-            Log.i(TAG, "KEY_SIP_CONFIG_URI_USER_PART_STRING:" + config.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_URI_USER_PART_STRING));
-            Log.i(TAG, "KEY_SIP_CONFIG_P_ACCESS_NETWORK_INFO_HEADER_STRING:" +
-                    config.getString(SipDelegateImsConfiguration.
-                            KEY_SIP_CONFIG_P_ACCESS_NETWORK_INFO_HEADER_STRING));
-            Log.i(TAG, "KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING:" +
-                    config.getString(SipDelegateImsConfiguration.
-                            KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING));
-            Log.i(TAG, "KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING:" + config.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING));
-            Log.i(TAG, "KEY_SIP_CONFIG_USER_AGENT_HEADER_STRING:" + config.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_USER_AGENT_HEADER_STRING));
-
-            Log.i(TAG, "KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT:" + config.getInt(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT, -99));
-            Log.i(TAG, "KEY_SIP_CONFIG_UE_DEFAULT_PORT_INT:" + config.getInt(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_DEFAULT_PORT_INT, -99));
-            Log.i(TAG, "KEY_SIP_CONFIG_SERVER_DEFAULT_PORT_INT:" + config.getInt(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_SERVER_DEFAULT_PORT_INT, -99));
-            Log.i(TAG, "KEY_SIP_CONFIG_UE_PUBLIC_PORT_WITH_NAT_INT:" + config.getInt(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_PUBLIC_PORT_WITH_NAT_INT, -99));
-            Log.i(TAG, "KEY_SIP_CONFIG_UE_IPSEC_CLIENT_PORT_INT:" + config.getInt(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_IPSEC_CLIENT_PORT_INT, -99));
-            Log.i(TAG, "KEY_SIP_CONFIG_UE_IPSEC_SERVER_PORT_INT:" + config.getInt(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_IPSEC_SERVER_PORT_INT, -99));
-            Log.i(TAG, "KEY_SIP_CONFIG_UE_IPSEC_OLD_CLIENT_PORT_INT:" + config.getInt(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_IPSEC_OLD_CLIENT_PORT_INT, -99));
-            Log.i(TAG, "KEY_SIP_CONFIG_SERVER_IPSEC_CLIENT_PORT_INT:" + config.getInt(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_SERVER_IPSEC_CLIENT_PORT_INT, -99));
-            Log.i(TAG, "KEY_SIP_CONFIG_SERVER_IPSEC_SERVER_PORT_INT:" + config.getInt(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_SERVER_IPSEC_SERVER_PORT_INT, -99));
-            Log.i(TAG, "KEY_SIP_CONFIG_SERVER_IPSEC_OLD_CLIENT_PORT_INT:" + config.getInt(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_SERVER_IPSEC_OLD_CLIENT_PORT_INT,
-                    -99));
-
-            Log.i(TAG, "KEY_SIP_CONFIG_IS_COMPACT_FORM_ENABLED_BOOL:" + config.getBoolean(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_COMPACT_FORM_ENABLED_BOOL,
-                    false));
-            Log.i(TAG, "KEY_SIP_CONFIG_IS_KEEPALIVE_ENABLED_BOOL:" + config.getBoolean(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_KEEPALIVE_ENABLED_BOOL, false));
-            Log.i(TAG, "KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL:" + config.getBoolean(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL, false));
-            Log.i(TAG, "KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL:" + config.getBoolean(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL, false));
-            Log.i(TAG, "KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL:" + config.getBoolean(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL, false));
+        private void dumpConfig(SipDelegateConfiguration config) {
+            String result = "SipDelegateConfiguration{"
+                    + "mVersion=" + config.getVersion()
+                    + ", \n\tmTransportType=" + config.getTransportType()
+                    + ", \n\tmLocalAddr=" + config.getLocalAddress()
+                    + ", \n\tmSipServerAddr=" + config.getSipServerAddress()
+                    + ", \n\tmIsSipCompactFormEnabled=" + config.isSipCompactFormEnabled()
+                    + ", \n\tmIsSipKeepaliveEnabled=" + config.isSipKeepaliveEnabled()
+                    + ", \n\tmMaxUdpPayloadSize=" + config.getMaxUdpPayloadSizeBytes()
+                    + ", \n\tmPublicUserIdentifier=" + config.getPublicUserIdentifier()
+                    + ", \n\tmPrivateUserIdentifier=" + config.getPrivateUserIdentifier()
+                    + ", \n\tmHomeDomain=" + config.getHomeDomain()
+                    + ", \n\tmImei=" + config.getImei()
+                    + ", \n\tmGruu=" + config.getPublicGruuUri()
+                    + ", \n\tmSipAuthHeader=" + config.getSipAuthenticationHeader()
+                    + ", \n\tmSipAuthNonce=" + config.getSipAuthenticationNonce()
+                    + ", \n\tmServiceRouteHeader=" + config.getSipServiceRouteHeader()
+                    + ", \n\tmPathHeader=" + config.getSipPathHeader()
+                    + ", \n\tmUserAgentHeader=" + config.getSipUserAgentHeader()
+                    + ", \n\tmContactUserParam=" + config.getSipContactUserParameter()
+                    + ", \n\tmPaniHeader=" + config.getSipPaniHeader()
+                    + ", \n\tmPlaniHeader=" + config.getSipPlaniHeader()
+                    + ", \n\tmCniHeader=" + config.getSipCniHeader()
+                    + ", \n\tmAssociatedUriHeader=" + config.getSipAssociatedUriHeader()
+                    + ", \n\tmIpSecConfiguration=" + config.getIpSecConfiguration()
+                    + ", \n\tmNatConfiguration=" + config.getNatSocketAddress() + '}';
+            Log.i(TAG, result);
         }
 
         @Override
@@ -330,54 +278,48 @@
 
         @Override
         public long getVersion() {
-            return configuration.getVersion();
+            return mConfiguration.getVersion();
         }
 
         @Override
         public String getOutboundProxyAddr() {
-            return configuration.getString(SipDelegateImsConfiguration.
-                    KEY_SIP_CONFIG_SERVER_DEFAULT_IPADDRESS_STRING);
+            return mConfiguration.getSipServerAddress().getAddress().getHostAddress();
         }
 
         @Override
         public int getOutboundProxyPort() {
-            return configuration.getInt(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_SERVER_DEFAULT_PORT_INT, -1);
+            return mConfiguration.getSipServerAddress().getPort();
         }
 
         @Override
         public String getLocalIpAddress() {
-            return configuration.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_DEFAULT_IPADDRESS_STRING);
+            return mConfiguration.getLocalAddress().getAddress().getHostAddress();
         }
 
         @Override
         public int getLocalPort() {
-            return configuration.getInt(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_UE_DEFAULT_PORT_INT, -1);
+            return mConfiguration.getLocalAddress().getPort();
         }
 
         @Override
         public String getSipTransport() {
-            return configuration.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING);
+            int sipTransport = mConfiguration.getTransportType();
+            return (sipTransport == SipDelegateConfiguration.SIP_TRANSPORT_TCP) ? "TCP" : "UDP";
         }
 
         @Override
         public String getPublicUserIdentity() {
-            return null;
+            return mConfiguration.getPublicUserIdentifier();
         }
 
         @Override
         public String getDomain() {
-            return configuration.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_HOME_DOMAIN_STRING);
+            return mConfiguration.getHomeDomain();
         }
 
         @Override
         public List<String> getAssociatedUris() {
-            String associatedUris = configuration.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING);
+            String associatedUris = mConfiguration.getSipAssociatedUriHeader();
             if (!TextUtils.isEmpty(associatedUris)) {
                 return Splitter.on(',').trimResults(CharMatcher.anyOf("<>")).splitToList(
                         associatedUris);
@@ -388,15 +330,17 @@
 
         @Override
         public String getSecurityVerifyHeader() {
-            return configuration.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_SECURITY_VERIFY_HEADER_STRING);
+            SipDelegateConfiguration.IpSecConfiguration c = mConfiguration.getIpSecConfiguration();
+            if (c == null) {
+                return null;
+            }
+            return c.getSipSecurityVerifyHeader();
         }
 
         @Override
         public List<String> getServiceRouteHeaders() {
             String serviceRoutes =
-                    configuration.getString(
-                            SipDelegateImsConfiguration.KEY_SIP_CONFIG_SERVICE_ROUTE_HEADER_STRING);
+                    mConfiguration.getSipServiceRouteHeader();
             if (TextUtils.isEmpty(serviceRoutes)) {
                 return Collections.emptyList();
             }
@@ -405,38 +349,33 @@
 
         @Override
         public String getContactUser() {
-            return configuration.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_URI_USER_PART_STRING);
+            return mConfiguration.getSipContactUserParameter();
         }
 
         @Override
         public String getImei() {
-            return configuration.getString(SipDelegateImsConfiguration.KEY_SIP_CONFIG_IMEI_STRING);
+            return mConfiguration.getImei();
         }
 
         @Override
         public String getPaniHeader() {
-            return configuration.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_P_ACCESS_NETWORK_INFO_HEADER_STRING);
+            return mConfiguration.getSipPaniHeader();
         }
 
         @Override
         public String getPlaniHeader() {
-            return configuration.getString(
-                    SipDelegateImsConfiguration.
-                            KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING);
+            return mConfiguration.getSipPlaniHeader();
         }
 
         @Override
         public String getUserAgentHeader() {
-            return configuration.getString(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_USER_AGENT_HEADER_STRING);
+            return mConfiguration.getSipUserAgentHeader();
         }
 
         @Override
         public int getMaxPayloadSizeOnUdp() {
-            return configuration.getInt(
-                    SipDelegateImsConfiguration.KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT, 1500);
+            return mConfiguration.getMaxUdpPayloadSizeBytes() > 0
+                    ? mConfiguration.getMaxUdpPayloadSizeBytes() : 1500;
         }
 
         /**
diff --git a/tests/src/com/android/TestExecutorService.java b/tests/src/com/android/TestExecutorService.java
index fec502a..7685c6d 100644
--- a/tests/src/com/android/TestExecutorService.java
+++ b/tests/src/com/android/TestExecutorService.java
@@ -16,9 +16,11 @@
 
 package com.android;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.Callable;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Delayed;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
@@ -37,6 +39,8 @@
 
         private final Callable<T> mTask;
         private final long mDelayMs;
+        // Wrap callable in a CompletableFuture to support delays in execution.
+        private final CompletableFuture<T> mFuture = new CompletableFuture<>();
 
         CompletedFuture(Callable<T> task) {
             mTask = task;
@@ -50,36 +54,29 @@
 
         @Override
         public boolean cancel(boolean mayInterruptIfRunning) {
-            return false;
+            return mFuture.cancel(mayInterruptIfRunning);
         }
 
         @Override
         public boolean isCancelled() {
-            return false;
+            return mFuture.isCancelled();
         }
 
         @Override
         public boolean isDone() {
-            return true;
+            return mFuture.isDone();
         }
 
         @Override
         public T get() throws InterruptedException, ExecutionException {
-            try {
-                return mTask.call();
-            } catch (Exception e) {
-                throw new ExecutionException(e);
-            }
+            return mFuture.get();
         }
 
         @Override
         public T get(long timeout, TimeUnit unit)
                 throws InterruptedException, ExecutionException, TimeoutException {
-            try {
-                return mTask.call();
-            } catch (Exception e) {
-                throw new ExecutionException(e);
-            }
+            // delays not implemented, this should complete via completeTask for better control.
+            return mFuture.get(timeout, unit);
         }
 
         @Override
@@ -99,35 +96,71 @@
             if (o.getDelay(TimeUnit.MILLISECONDS) < mDelayMs) return 1;
             return 0;
         }
+
+        public void completeTask() {
+            try {
+                mFuture.complete(mTask.call());
+            } catch (Exception e) {
+                mFuture.completeExceptionally(e);
+            }
+        }
+    }
+
+    private final ArrayList<Runnable> mPendingRunnables = new ArrayList<>();
+    private final boolean mWaitToComplete;
+    private boolean mIsShutdown = false;
+
+    public TestExecutorService() {
+        mWaitToComplete = false;
+    }
+
+    /**
+     * Create a test executor service that also allows the constructor to provide a parameter to
+     * control when pending Runnables are executed.
+     * @param waitToComplete If true, this executor will wait to complete any pending Runnables
+     *                       until {@link #executePending()}} is called.
+     */
+    public TestExecutorService(boolean waitToComplete) {
+        mWaitToComplete = waitToComplete;
     }
 
     @Override
     public void shutdown() {
+        mIsShutdown = true;
+        for (Runnable r : mPendingRunnables) {
+            r.run();
+        }
     }
 
     @Override
     public List<Runnable> shutdownNow() {
-        return null;
+        mIsShutdown = true;
+        List<Runnable> runnables = new ArrayList<>(mPendingRunnables);
+        mPendingRunnables.clear();
+        return runnables;
     }
 
     @Override
     public boolean isShutdown() {
-        return false;
+        return mIsShutdown;
     }
 
     @Override
     public boolean isTerminated() {
-        return false;
+        return mIsShutdown;
     }
 
     @Override
     public boolean awaitTermination(long timeout, TimeUnit unit) {
-        return false;
+        shutdown();
+        return true;
     }
 
     @Override
     public <T> Future<T> submit(Callable<T> task) {
-        return new CompletedFuture<>(task);
+        CompletedFuture<T> f = new CompletedFuture<>(task);
+        onExecute(f::completeTask);
+        return f;
     }
 
     @Override
@@ -137,8 +170,12 @@
 
     @Override
     public Future<?> submit(Runnable task) {
-        task.run();
-        return new CompletedFuture<>(() -> null);
+        CompletedFuture<Void> f = new CompletedFuture<>(() -> {
+            task.run();
+            return null;
+        });
+        onExecute(f::completeTask);
+        return f;
     }
 
     @Override
@@ -164,14 +201,21 @@
 
     @Override
     public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
-        // No need to worry about delays yet
-        command.run();
-        return new CompletedFuture<>(() -> null, delay);
+        long millisDelay = TimeUnit.MILLISECONDS.convert(delay, unit);
+        CompletedFuture<Void> f = new CompletedFuture<>(() -> {
+            command.run();
+            return null;
+        }, millisDelay);
+        onExecute(f::completeTask);
+        return f;
     }
 
     @Override
     public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
-        return new CompletedFuture<>(callable, delay);
+        long millisDelay = TimeUnit.MILLISECONDS.convert(delay, unit);
+        CompletedFuture<V> f = new CompletedFuture<>(callable, millisDelay);
+        onExecute(f::completeTask);
+        return f;
     }
 
     @Override
@@ -188,6 +232,21 @@
 
     @Override
     public void execute(Runnable command) {
-        command.run();
+        onExecute(command);
+    }
+
+    private void onExecute(Runnable command) {
+        if (mWaitToComplete) {
+            mPendingRunnables.add(command);
+        } else {
+            command.run();
+        }
+    }
+
+    public void executePending() {
+        for (Runnable r : mPendingRunnables) {
+            r.run();
+        }
+        mPendingRunnables.clear();
     }
 }
diff --git a/tests/src/com/android/phone/CarrierConfigLoaderTest.java b/tests/src/com/android/phone/CarrierConfigLoaderTest.java
index f58e6cc..9c605da 100644
--- a/tests/src/com/android/phone/CarrierConfigLoaderTest.java
+++ b/tests/src/com/android/phone/CarrierConfigLoaderTest.java
@@ -133,6 +133,7 @@
     public void tearDown() throws Exception {
         mContext.revokeAllPermissions();
         mTestableLooper.destroy();
+        mHandlerThread.quit();
         super.tearDown();
     }
 
diff --git a/tests/src/com/android/phone/SimPhonebookProviderTest.java b/tests/src/com/android/phone/SimPhonebookProviderTest.java
index 4ab92a7..f897fac 100644
--- a/tests/src/com/android/phone/SimPhonebookProviderTest.java
+++ b/tests/src/com/android/phone/SimPhonebookProviderTest.java
@@ -51,6 +51,7 @@
 import androidx.test.rule.provider.ProviderTestRule;
 
 import com.android.internal.telephony.IIccPhoneBook;
+import com.android.internal.telephony.uicc.AdnCapacity;
 import com.android.internal.telephony.uicc.AdnRecord;
 import com.android.internal.telephony.uicc.IccConstants;
 
@@ -1394,15 +1395,18 @@
         }
 
         @Override
-        public boolean updateAdnRecordsInEfBySearch(int efid, String oldTag, String oldPhoneNumber,
-                String newTag, String newPhoneNumber, String pin2) {
-            return updateAdnRecordsInEfBySearchForSubscriber(
-                    mDefaultSubscriptionId, efid,
-                    oldTag, oldPhoneNumber, newTag, newPhoneNumber, pin2);
+        public boolean updateAdnRecordsInEfBySearchForSubscriber(int subId, int efid,
+                ContentValues values, String pin2) {
+            final String oldTag = values.getAsString(IccProvider.STR_TAG);
+            final String oldPhoneNumber = values.getAsString(IccProvider.STR_NUMBER);
+            final String newTag = values.getAsString(IccProvider.STR_NEW_TAG);
+            final String newPhoneNumber = values.getAsString(IccProvider.STR_NEW_NUMBER);
+            return updateAdnRecordsInEfBySearchForSubscriber(subId, efid, oldTag, oldPhoneNumber,
+                    newTag, newPhoneNumber, pin2);
+
         }
 
-        @Override
-        public boolean updateAdnRecordsInEfBySearchForSubscriber(int subId, int efid, String oldTag,
+        private boolean updateAdnRecordsInEfBySearchForSubscriber(int subId, int efid, String oldTag,
                 String oldPhoneNumber, String newTag, String newPhoneNumber, String pin2) {
             if (!oldTag.isEmpty() || !oldPhoneNumber.isEmpty()) {
                 throw new IllegalArgumentException(
@@ -1413,14 +1417,16 @@
         }
 
         @Override
-        public boolean updateAdnRecordsInEfByIndex(int efid, String newTag, String newPhoneNumber,
-                int index, String pin2) {
-            return updateAdnRecordsInEfByIndexForSubscriber(mDefaultSubscriptionId,
-                    efid, newTag, newPhoneNumber, index, pin2);
+        public boolean updateAdnRecordsInEfByIndexForSubscriber(int subId, int efid,
+                ContentValues values, int index, String pin2) {
+            final String newTag = values.getAsString(IccProvider.STR_NEW_TAG);
+            final String newPhoneNumber = values.getAsString(IccProvider.STR_NEW_NUMBER);
+            return updateAdnRecordsInEfByIndexForSubscriber(subId, efid, newTag, newPhoneNumber,
+                    index, pin2);
+
         }
 
-        @Override
-        public boolean updateAdnRecordsInEfByIndexForSubscriber(int subId, int efid, String newTag,
+        private boolean updateAdnRecordsInEfByIndexForSubscriber(int subId, int efid, String newTag,
                 String newPhoneNumber, int index, String pin2) {
             AdnRecord[] records = mRecords.computeIfAbsent(Pair.create(subId, efid), unused ->
                     createEmptyRecords(efid, 100));
@@ -1443,6 +1449,11 @@
             int count = mRecords.get(key).length;
             return new int[]{recordSize, recordSize * count, count};
         }
+
+        @Override
+        public AdnCapacity getAdnRecordsCapacityForSubscriber(int subId) {
+            return new AdnCapacity(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        }
     }
 
     /**
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index 07fe6a8..84ab543 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -30,6 +30,7 @@
 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;
 import static org.mockito.Mockito.never;
@@ -58,6 +59,8 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.TelephonyTestBase;
+import com.android.internal.telecom.IConnectionService;
+import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.Connection;
 import com.android.internal.telephony.Phone;
@@ -84,6 +87,24 @@
 
 @RunWith(AndroidJUnit4.class)
 public class TelephonyConnectionServiceTest extends TelephonyTestBase {
+    /**
+     * Unlike {@link TestTelephonyConnection}, a bare minimal {@link TelephonyConnection} impl
+     * that does not try to configure anything.
+     */
+    public static class SimpleTelephonyConnection extends TelephonyConnection {
+        public boolean wasDisconnected = false;
+
+        @Override
+        public TelephonyConnection cloneConnection() {
+            return null;
+        }
+
+
+        @Override
+        public void onDisconnect() {
+            wasDisconnected = true;
+        }
+    }
 
     private static final long TIMEOUT_MS = 100;
     private static final int SLOT_0_PHONE_ID = 0;
@@ -114,6 +135,12 @@
     @Mock PhoneSwitcher mPhoneSwitcher;
     @Mock RadioOnHelper mRadioOnHelper;
     @Mock ServiceStateTracker mSST;
+    @Mock Call mCall;
+    @Mock Call mCall2;
+    @Mock com.android.internal.telephony.Connection mInternalConnection;
+    @Mock com.android.internal.telephony.Connection mInternalConnection2;
+    private Phone mPhone0;
+    private Phone mPhone1;
 
     private static class TestTelephonyConnectionService extends TelephonyConnectionService {
 
@@ -132,6 +159,7 @@
     }
 
     private TelephonyConnectionService mTestConnectionService;
+    private IConnectionService.Stub mBinderStub;
 
     @Before
     public void setUp() throws Exception {
@@ -161,6 +189,7 @@
         mTestConnectionService.setDisconnectCauseFactory(mDisconnectCauseFactory);
         mTestConnectionService.onCreate();
         mTestConnectionService.setTelephonyManagerProxy(mTelephonyManagerProxy);
+        mBinderStub = (IConnectionService.Stub) mTestConnectionService.onBind(null);
     }
 
     @After
@@ -1155,6 +1184,204 @@
     }
 
     /**
+     * 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
+     */
+    @Test
+    @SmallTest
+    public void testIncomingDoesntRequestDisconnect() throws Exception {
+        setupForCallTest();
+
+        mBinderStub.createConnection(PHONE_ACCOUNT_HANDLE_1, "TC@1",
+                new ConnectionRequest(PHONE_ACCOUNT_HANDLE_1, Uri.parse("tel:16505551212"),
+                        new Bundle()),
+                true, false, null);
+        waitForHandlerAction(mTestConnectionService.getHandler(), TIMEOUT_MS);
+        assertEquals(1, mTestConnectionService.getAllConnections().size());
+
+        // Make sure the extras do not indicate that it answering will disconnect another call.
+        android.telecom.Connection connection = (android.telecom.Connection)
+                mTestConnectionService.getAllConnections().toArray()[0];
+        assertFalse(connection.getExtras() != null && connection.getExtras().containsKey(
+                android.telecom.Connection.EXTRA_ANSWERING_DROPS_FG_CALL));
+    }
+
+    /**
+     * Verifies where there is another call on the same sub, we don't set
+     * {@link android.telecom.Connection#EXTRA_ANSWERING_DROPS_FG_CALL} on the incoming call extras.
+     * @throws Exception
+     */
+    @Test
+    @SmallTest
+    public void testSecondCallSameSubWontDisconnect() throws Exception {
+        // Previous test gets us into a good enough state
+        testIncomingDoesntRequestDisconnect();
+
+        when(mCall.getState()).thenReturn(Call.State.ACTIVE);
+        when(mCall2.getState()).thenReturn(Call.State.WAITING);
+        when(mCall2.getLatestConnection()).thenReturn(mInternalConnection2);
+        when(mPhone0.getRingingCall()).thenReturn(mCall2);
+
+        mBinderStub.createConnection(PHONE_ACCOUNT_HANDLE_1, "TC@2",
+                new ConnectionRequest(PHONE_ACCOUNT_HANDLE_1, Uri.parse("tel:16505551213"),
+                        new Bundle()),
+                true, false, null);
+        waitForHandlerAction(mTestConnectionService.getHandler(), TIMEOUT_MS);
+        assertEquals(2, mTestConnectionService.getAllConnections().size());
+
+        // None of the connections should have the extra set.
+        assertEquals(0, mTestConnectionService.getAllConnections().stream()
+                .filter(c -> c.getExtras() != null && c.getExtras().containsKey(
+                        android.telecom.Connection.EXTRA_ANSWERING_DROPS_FG_CALL))
+                .count());
+    }
+
+    /**
+     * Verifies where there is another call on the same sub, we don't set
+     * {@link android.telecom.Connection#EXTRA_ANSWERING_DROPS_FG_CALL} on the incoming call extras.
+     * @throws Exception
+     */
+    @Test
+    @SmallTest
+    public void testSecondCallDifferentSubWillDisconnect() throws Exception {
+        // Previous test gets us into a good enough state
+        testIncomingDoesntRequestDisconnect();
+
+        when(mCall.getState()).thenReturn(Call.State.ACTIVE);
+        when(mCall2.getState()).thenReturn(Call.State.WAITING);
+        when(mCall2.getLatestConnection()).thenReturn(mInternalConnection2);
+        // At this point the call is ringing on the second phone.
+        when(mPhone0.getRingingCall()).thenReturn(null);
+        when(mPhone1.getRingingCall()).thenReturn(mCall2);
+
+        mBinderStub.createConnection(PHONE_ACCOUNT_HANDLE_2, "TC@2",
+                new ConnectionRequest(PHONE_ACCOUNT_HANDLE_2, Uri.parse("tel:16505551213"),
+                        new Bundle()),
+                true, false, null);
+        waitForHandlerAction(mTestConnectionService.getHandler(), TIMEOUT_MS);
+        assertEquals(2, mTestConnectionService.getAllConnections().size());
+
+        // The incoming connection should have the extra set.
+        assertEquals(1, mTestConnectionService.getAllConnections().stream()
+                .filter(c -> c.getExtras() != null && c.getExtras().containsKey(
+                        android.telecom.Connection.EXTRA_ANSWERING_DROPS_FG_CALL))
+                .count());
+    }
+
+    private static final PhoneAccountHandle SUB1_HANDLE = new PhoneAccountHandle(
+            new ComponentName("test", "class"), "1");
+    private static final PhoneAccountHandle SUB2_HANDLE = new PhoneAccountHandle(
+            new ComponentName("test", "class"), "2");
+
+    @Test
+    @SmallTest
+    public void testDontDisconnectSameSub() {
+        ArrayList<android.telecom.Connection> tcs = new ArrayList<>();
+        SimpleTelephonyConnection tc1 = createTestConnection(SUB1_HANDLE, 0, false);
+        tcs.add(tc1);
+        TelephonyConnectionService.maybeDisconnectCallsOnOtherSubs(tcs, SUB1_HANDLE);
+        // Would've preferred to use mockito, but can't mock out TelephonyConnection/Connection
+        // easily.
+        assertFalse(tc1.wasDisconnected);
+    }
+
+    @Test
+    @SmallTest
+    public void testDontDisconnectEmergency() {
+        ArrayList<android.telecom.Connection> tcs = new ArrayList<>();
+        SimpleTelephonyConnection tc1 = createTestConnection(SUB1_HANDLE, 0, true);
+        tcs.add(tc1);
+        TelephonyConnectionService.maybeDisconnectCallsOnOtherSubs(tcs, SUB2_HANDLE);
+        // Other call is an emergency call, so don't disconnect it.
+        assertFalse(tc1.wasDisconnected);
+    }
+
+    @Test
+    @SmallTest
+    public void testDontDisconnectExternal() {
+        ArrayList<android.telecom.Connection> tcs = new ArrayList<>();
+        SimpleTelephonyConnection tc1 = createTestConnection(SUB1_HANDLE,
+                android.telecom.Connection.PROPERTY_IS_EXTERNAL_CALL, false);
+        tcs.add(tc1);
+        TelephonyConnectionService.maybeDisconnectCallsOnOtherSubs(tcs, SUB2_HANDLE);
+        // Other call is an external call, so don't disconnect it.
+        assertFalse(tc1.wasDisconnected);
+    }
+
+    @Test
+    @SmallTest
+    public void testDisconnectDifferentSub() {
+        ArrayList<android.telecom.Connection> tcs = new ArrayList<>();
+        SimpleTelephonyConnection tc1 = createTestConnection(SUB1_HANDLE, 0, false);
+        tcs.add(tc1);
+        TelephonyConnectionService.maybeDisconnectCallsOnOtherSubs(tcs, SUB2_HANDLE);
+        assertTrue(tc1.wasDisconnected);
+    }
+
+    @Test
+    @SmallTest
+    public void testDisconnectDifferentSubTwoCalls() {
+        ArrayList<android.telecom.Connection> tcs = new ArrayList<>();
+        SimpleTelephonyConnection tc1 = createTestConnection(SUB1_HANDLE, 0, false);
+        SimpleTelephonyConnection tc2 = createTestConnection(SUB1_HANDLE, 0, false);
+
+        tcs.add(tc1);
+        tcs.add(tc2);
+        TelephonyConnectionService.maybeDisconnectCallsOnOtherSubs(tcs, SUB2_HANDLE);
+        assertTrue(tc1.wasDisconnected);
+        assertTrue(tc2.wasDisconnected);
+    }
+
+    private SimpleTelephonyConnection createTestConnection(PhoneAccountHandle handle,
+            int properties, boolean isEmergency) {
+        SimpleTelephonyConnection connection = new SimpleTelephonyConnection();
+        connection.setShouldTreatAsEmergencyCall(isEmergency);
+        connection.setConnectionProperties(properties);
+        connection.setPhoneAccountHandle(handle);
+        return connection;
+    }
+
+    /**
+     * Setup the mess of mocks for {@link #testSecondCallSameSubWontDisconnect()} and
+     * {@link #testIncomingDoesntRequestDisconnect()}.
+     */
+    private void setupForCallTest() {
+        // Setup a bunch of stuff.  Blech.
+        mTestConnectionService.setReadyForTest();
+        mPhone0 = makeTestPhone(0 /*phoneId*/, ServiceState.STATE_IN_SERVICE,
+                false /*isEmergencyOnly*/);
+        when(mCall.getState()).thenReturn(Call.State.INCOMING);
+        when(mCall.getPhone()).thenReturn(mPhone0);
+        when(mPhone0.getRingingCall()).thenReturn(mCall);
+        mPhone1 = makeTestPhone(1 /*phoneId*/, ServiceState.STATE_IN_SERVICE,
+                false /*isEmergencyOnly*/);
+        when(mCall2.getPhone()).thenReturn(mPhone1);
+        List<Phone> phones = new ArrayList<>(2);
+        doReturn(true).when(mPhone0).isRadioOn();
+        doReturn(true).when(mPhone1).isRadioOn();
+        doReturn(GSM_PHONE).when(mPhone0).getPhoneType();
+        doReturn(GSM_PHONE).when(mPhone1).getPhoneType();
+        phones.add(mPhone0);
+        phones.add(mPhone1);
+        setPhones(phones);
+        when(mPhoneUtilsProxy.getSubIdForPhoneAccountHandle(eq(PHONE_ACCOUNT_HANDLE_1)))
+                .thenReturn(0);
+        when(mSubscriptionManagerProxy.getPhoneId(0)).thenReturn(0);
+        when(mPhoneFactoryProxy.getPhone(eq(0))).thenReturn(mPhone0);
+        when(mPhoneUtilsProxy.getSubIdForPhoneAccountHandle(eq(PHONE_ACCOUNT_HANDLE_2)))
+                .thenReturn(1);
+        when(mSubscriptionManagerProxy.getPhoneId(1)).thenReturn(1);
+        when(mPhoneFactoryProxy.getPhone(eq(1))).thenReturn(mPhone1);
+        setupDeviceConfig(mPhone0, mPhone1, 1);
+
+        when(mInternalConnection.getCall()).thenReturn(mCall);
+        when(mInternalConnection.getState()).thenReturn(Call.State.ACTIVE);
+        when(mInternalConnection2.getCall()).thenReturn(mCall2);
+        when(mInternalConnection2.getState()).thenReturn(Call.State.WAITING);
+    }
+
+    /**
      * Set up a mock MSIM device with TEST_ADDRESS set as an emergency number.
      * @return the Phone associated with slot 0.
      */
@@ -1248,11 +1475,11 @@
         EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY);
     }
 
-    private void setupHandleToPhoneMap(PhoneAccountHandle handle,  Phone phone) {
+    private void setupHandleToPhoneMap(PhoneAccountHandle handle, Phone phone) {
         // use subId 0
-        when(mPhoneUtilsProxy.getSubIdForPhoneAccountHandle(handle)).thenReturn(0);
-        when(mSubscriptionManagerProxy.getPhoneId(0)).thenReturn(0);
-        when(mPhoneFactoryProxy.getPhone(0)).thenReturn(phone);
+        when(mPhoneUtilsProxy.getSubIdForPhoneAccountHandle(eq(handle))).thenReturn(0);
+        when(mSubscriptionManagerProxy.getPhoneId(eq(0))).thenReturn(0);
+        when(mPhoneFactoryProxy.getPhone(eq(0))).thenReturn(phone);
     }
 
     private AsyncResult getSuppServiceNotification(int notificationType, int code) {
@@ -1273,6 +1500,8 @@
         when(phone.getDefaultPhone()).thenReturn(phone);
         when(phone.getEmergencyNumberTracker()).thenReturn(mEmergencyNumberTracker);
         when(phone.getServiceStateTracker()).thenReturn(mSST);
+        doNothing().when(phone).registerForPreciseCallStateChanged(any(Handler.class), anyInt(),
+                any(Object.class));
         when(mEmergencyNumberTracker.getEmergencyNumber(anyString())).thenReturn(null);
         return phone;
     }
diff --git a/tests/src/com/android/services/telephony/rcs/DelegateStateTrackerTest.java b/tests/src/com/android/services/telephony/rcs/DelegateStateTrackerTest.java
index 4d40702..8236f44 100644
--- a/tests/src/com/android/services/telephony/rcs/DelegateStateTrackerTest.java
+++ b/tests/src/com/android/services/telephony/rcs/DelegateStateTrackerTest.java
@@ -24,9 +24,10 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.net.InetAddresses;
 import android.telephony.ims.DelegateRegistrationState;
 import android.telephony.ims.FeatureTagState;
-import android.telephony.ims.SipDelegateImsConfiguration;
+import android.telephony.ims.SipDelegateConfiguration;
 import android.telephony.ims.SipDelegateManager;
 import android.telephony.ims.aidl.ISipDelegate;
 import android.telephony.ims.aidl.ISipDelegateConnectionStateCallback;
@@ -44,6 +45,7 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 
+import java.net.InetSocketAddress;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
@@ -85,13 +87,17 @@
         DelegateRegistrationState regState = new DelegateRegistrationState.Builder()
                 .addRegisteredFeatureTag(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG)
                 .build();
-        SipDelegateImsConfiguration config = new SipDelegateImsConfiguration.Builder(1/*version*/)
-                .build();
+        InetSocketAddress localAddr = new InetSocketAddress(
+                InetAddresses.parseNumericAddress("1.1.1.1"), 80);
+        InetSocketAddress serverAddr = new InetSocketAddress(
+                InetAddresses.parseNumericAddress("2.2.2.2"), 81);
+        SipDelegateConfiguration c = new SipDelegateConfiguration.Builder(1,
+                SipDelegateConfiguration.SIP_TRANSPORT_TCP, localAddr, serverAddr).build();
         stateTracker.onRegistrationStateChanged(regState);
-        stateTracker.onImsConfigurationChanged(config);
+        stateTracker.onConfigurationChanged(c);
         verify(mAppCallback).onFeatureTagStatusChanged(eq(regState),
                 eq(new ArrayList<>(deniedTags)));
-        verify(mAppCallback).onImsConfigurationChanged(config);
+        verify(mAppCallback).onConfigurationChanged(c);
 
         verify(mAppCallback, never()).onDestroyed(anyInt());
     }
diff --git a/tests/src/com/android/services/telephony/rcs/MessageTransportStateTrackerTest.java b/tests/src/com/android/services/telephony/rcs/MessageTransportStateTrackerTest.java
deleted file mode 100644
index f69b9a8..0000000
--- a/tests/src/com/android/services/telephony/rcs/MessageTransportStateTrackerTest.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright (C) 2020 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.rcs;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.os.RemoteException;
-import android.telephony.ims.SipDelegateManager;
-import android.telephony.ims.SipMessage;
-import android.telephony.ims.aidl.ISipDelegate;
-import android.telephony.ims.aidl.ISipDelegateMessageCallback;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.TelephonyTestBase;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.concurrent.Executor;
-import java.util.function.Consumer;
-
-@RunWith(AndroidJUnit4.class)
-public class MessageTransportStateTrackerTest extends TelephonyTestBase {
-    private static final int TEST_SUB_ID = 1;
-
-    private static final SipMessage TEST_MESSAGE = new SipMessage(
-            "INVITE sip:callee@ex.domain.com SIP/2.0",
-            "Via: SIP/2.0/UDP ex.place.com;branch=z9hG4bK776asdhds",
-            new byte[0]);
-
-    // Use for finer-grained control of when the Executor executes.
-    private static class PendingExecutor implements Executor {
-        private final ArrayList<Runnable> mPendingRunnables = new ArrayList<>();
-
-        @Override
-        public void execute(Runnable command) {
-            mPendingRunnables.add(command);
-        }
-
-        public void executePending() {
-            for (Runnable r : mPendingRunnables) {
-                r.run();
-            }
-            mPendingRunnables.clear();
-        }
-    }
-
-    @Mock private ISipDelegateMessageCallback mDelegateMessageCallback;
-    @Mock private ISipDelegate mISipDelegate;
-    @Mock private Consumer<Boolean> mMockCloseConsumer;
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        super.tearDown();
-    }
-
-    @SmallTest
-    @Test
-    public void testDelegateConnectionSendOutgoingMessage() throws Exception {
-        MessageTransportStateTracker tracker = new MessageTransportStateTracker(TEST_SUB_ID,
-                Runnable::run, mDelegateMessageCallback);
-
-        tracker.openTransport(mISipDelegate, Collections.emptySet());
-        tracker.getDelegateConnection().sendMessage(TEST_MESSAGE, 1 /*version*/);
-        verify(mISipDelegate).sendMessage(TEST_MESSAGE, 1 /*version*/);
-
-        doThrow(new RemoteException()).when(mISipDelegate).sendMessage(any(), anyLong());
-        tracker.getDelegateConnection().sendMessage(TEST_MESSAGE, 1 /*version*/);
-        verify(mDelegateMessageCallback).onMessageSendFailure(any(),
-                eq(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD));
-
-        tracker.close(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED);
-        tracker.getDelegateConnection().sendMessage(TEST_MESSAGE, 1 /*version*/);
-        verify(mDelegateMessageCallback).onMessageSendFailure(any(),
-                eq(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED));
-    }
-
-    @SmallTest
-    @Test
-    public void testDelegateConnectionCloseGracefully() throws Exception {
-        PendingExecutor executor = new PendingExecutor();
-        MessageTransportStateTracker tracker = new MessageTransportStateTracker(TEST_SUB_ID,
-                executor, mDelegateMessageCallback);
-
-        tracker.openTransport(mISipDelegate, Collections.emptySet());
-        tracker.getDelegateConnection().sendMessage(TEST_MESSAGE, 1 /*version*/);
-        executor.executePending();
-        verify(mISipDelegate).sendMessage(TEST_MESSAGE, 1 /*version*/);
-        verify(mDelegateMessageCallback, never()).onMessageSendFailure(any(), anyInt());
-
-        // Use PendingExecutor a little weird here, we need to queue sendMessage first, even though
-        // closeGracefully will complete partly synchronously to test that the pending message will
-        // return MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION before the scheduled
-        // graceful close operation completes.
-        tracker.getDelegateConnection().sendMessage(TEST_MESSAGE, 1 /*version*/);
-        tracker.closeGracefully(
-                SipDelegateManager.MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION,
-                SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED,
-                mMockCloseConsumer);
-        verify(mMockCloseConsumer, never()).accept(any());
-        // resolve pending close operation
-        executor.executePending();
-        verify(mDelegateMessageCallback).onMessageSendFailure(any(),
-                eq(SipDelegateManager.MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION));
-        // Still should only report one call of sendMessage from before
-        verify(mISipDelegate).sendMessage(TEST_MESSAGE, 1 /*version*/);
-        verify(mMockCloseConsumer).accept(true);
-
-        // ensure that after close operation completes, we get the correct
-        // MESSAGE_FAILURE_REASON_DELEGATE_CLOSED message.
-        tracker.getDelegateConnection().sendMessage(TEST_MESSAGE, 1 /*version*/);
-        executor.executePending();
-        verify(mDelegateMessageCallback).onMessageSendFailure(any(),
-                eq(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED));
-        // Still should only report one call of sendMessage from before
-        verify(mISipDelegate).sendMessage(TEST_MESSAGE, 1 /*version*/);
-    }
-
-    @SmallTest
-    @Test
-    public void testDelegateConnectionNotifyMessageReceived() throws Exception {
-        MessageTransportStateTracker tracker = new MessageTransportStateTracker(TEST_SUB_ID,
-                Runnable::run, mDelegateMessageCallback);
-        tracker.openTransport(mISipDelegate, Collections.emptySet());
-        tracker.getDelegateConnection().notifyMessageReceived("z9hG4bK776asdhds");
-        verify(mISipDelegate).notifyMessageReceived("z9hG4bK776asdhds");
-    }
-
-    @SmallTest
-    @Test
-    public void testDelegateConnectionNotifyMessageReceiveError() throws Exception {
-        MessageTransportStateTracker tracker = new MessageTransportStateTracker(TEST_SUB_ID,
-                Runnable::run, mDelegateMessageCallback);
-        tracker.openTransport(mISipDelegate, Collections.emptySet());
-        tracker.getDelegateConnection().notifyMessageReceiveError("z9hG4bK776asdhds",
-                SipDelegateManager.MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE);
-        verify(mISipDelegate).notifyMessageReceiveError("z9hG4bK776asdhds",
-                SipDelegateManager.MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE);
-    }
-
-    @SmallTest
-    @Test
-    public void testDelegateConnectionCloseSession() throws Exception {
-        MessageTransportStateTracker tracker = new MessageTransportStateTracker(TEST_SUB_ID,
-                Runnable::run, mDelegateMessageCallback);
-        tracker.openTransport(mISipDelegate, Collections.emptySet());
-        tracker.getDelegateConnection().cleanupSession("testCallId");
-        verify(mISipDelegate).cleanupSession("testCallId");
-    }
-
-    @SmallTest
-    @Test
-    public void testDelegateOnMessageReceived() throws Exception {
-        MessageTransportStateTracker tracker = new MessageTransportStateTracker(TEST_SUB_ID,
-                Runnable::run, mDelegateMessageCallback);
-        tracker.openTransport(mISipDelegate, Collections.emptySet());
-
-        tracker.getMessageCallback().onMessageReceived(TEST_MESSAGE);
-        verify(mDelegateMessageCallback).onMessageReceived(TEST_MESSAGE);
-
-        doThrow(new RemoteException()).when(mDelegateMessageCallback).onMessageReceived(any());
-        tracker.getMessageCallback().onMessageReceived(TEST_MESSAGE);
-        verify(mISipDelegate).notifyMessageReceiveError(any(),
-                eq(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD));
-    }
-
-    @SmallTest
-    @Test
-    public void testDelegateOnMessageReceivedClosedGracefully() throws Exception {
-        PendingExecutor executor = new PendingExecutor();
-        MessageTransportStateTracker tracker = new MessageTransportStateTracker(TEST_SUB_ID,
-                executor, mDelegateMessageCallback);
-        tracker.openTransport(mISipDelegate, Collections.emptySet());
-
-        tracker.getMessageCallback().onMessageReceived(TEST_MESSAGE);
-        executor.executePending();
-        verify(mDelegateMessageCallback).onMessageReceived(TEST_MESSAGE);
-
-        tracker.getMessageCallback().onMessageReceived(TEST_MESSAGE);
-        tracker.closeGracefully(
-                SipDelegateManager.MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION,
-                SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED,
-                mMockCloseConsumer);
-        executor.executePending();
-        // Incoming SIP message should not be blocked by closeGracefully
-        verify(mDelegateMessageCallback, times(2)).onMessageReceived(TEST_MESSAGE);
-    }
-
-    @SmallTest
-    @Test
-    public void testDelegateOnMessageSent() throws Exception {
-        MessageTransportStateTracker tracker = new MessageTransportStateTracker(TEST_SUB_ID,
-                Runnable::run, mDelegateMessageCallback);
-        tracker.openTransport(mISipDelegate, Collections.emptySet());
-        tracker.getMessageCallback().onMessageSent("z9hG4bK776asdhds");
-        verify(mDelegateMessageCallback).onMessageSent("z9hG4bK776asdhds");
-    }
-
-    @SmallTest
-    @Test
-    public void testDelegateonMessageSendFailure() throws Exception {
-        MessageTransportStateTracker tracker = new MessageTransportStateTracker(TEST_SUB_ID,
-                Runnable::run, mDelegateMessageCallback);
-        tracker.openTransport(mISipDelegate, Collections.emptySet());
-        tracker.getMessageCallback().onMessageSendFailure("z9hG4bK776asdhds",
-                SipDelegateManager.MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE);
-        verify(mDelegateMessageCallback).onMessageSendFailure("z9hG4bK776asdhds",
-                SipDelegateManager.MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE);
-    }
-}
diff --git a/tests/src/com/android/services/telephony/rcs/MessageTransportWrapperTest.java b/tests/src/com/android/services/telephony/rcs/MessageTransportWrapperTest.java
new file mode 100644
index 0000000..5ced75c
--- /dev/null
+++ b/tests/src/com/android/services/telephony/rcs/MessageTransportWrapperTest.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2020 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.rcs;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.net.InetAddresses;
+import android.os.RemoteException;
+import android.telephony.ims.DelegateRegistrationState;
+import android.telephony.ims.FeatureTagState;
+import android.telephony.ims.SipDelegateConfiguration;
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+import android.telephony.ims.aidl.ISipDelegate;
+import android.telephony.ims.aidl.ISipDelegateMessageCallback;
+import android.util.ArraySet;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.TelephonyTestBase;
+import com.android.TestExecutorService;
+import com.android.services.telephony.rcs.validator.ValidationResult;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.function.Consumer;
+
+@RunWith(AndroidJUnit4.class)
+public class MessageTransportWrapperTest extends TelephonyTestBase {
+    private static final int TEST_SUB_ID = 1;
+
+    private static final SipMessage TEST_MESSAGE = new SipMessage(
+            "INVITE sip:callee@ex.domain.com SIP/2.0",
+            "Via: SIP/2.0/UDP ex.place.com;branch=z9hG4bK776asdhds",
+            new byte[0]);
+
+    // Derived from TEST_MESSAGE above.
+    private static final String TEST_TRANSACTION_ID = "z9hG4bK776asdhds";
+
+    @Mock private ISipDelegateMessageCallback mDelegateMessageCallback;
+    @Mock private TransportSipMessageValidator mTransportSipSessionValidator;
+    @Mock private ISipDelegate mISipDelegate;
+
+    // Test executor that just calls run on the Runnable provided in execute.
+    private ScheduledExecutorService mExecutor = new TestExecutorService();
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    @SmallTest
+    @Test
+    public void testImsConfigurationChanged() {
+        MessageTransportWrapper tracker = createTestMessageTransportWrapper();
+        InetSocketAddress localAddr = new InetSocketAddress(
+                InetAddresses.parseNumericAddress("1.1.1.1"), 80);
+        InetSocketAddress serverAddr = new InetSocketAddress(
+                InetAddresses.parseNumericAddress("2.2.2.2"), 81);
+        SipDelegateConfiguration c = new SipDelegateConfiguration.Builder(1,
+                SipDelegateConfiguration.SIP_TRANSPORT_TCP, localAddr, serverAddr).build();
+        // Ensure IMS config changes are propagated to the message tracker.
+        tracker.onConfigurationChanged(c);
+        verify(mTransportSipSessionValidator).onConfigurationChanged(c);
+    }
+
+    @SmallTest
+    @Test
+    public void testOpenTransport() {
+        HashSet<String> allowedTags = new HashSet<>(1);
+        allowedTags.add("testTag");
+        HashSet<FeatureTagState> deniedTags = new HashSet<>(1);
+        deniedTags.add(new FeatureTagState("testBadTag",
+                SipDelegateManager.DENIED_REASON_INVALID));
+        MessageTransportWrapper tracker = createTestMessageTransportWrapper();
+        // Ensure openTransport passes denied tags to the session tracker
+        tracker.openTransport(mISipDelegate, allowedTags, deniedTags);
+        verify(mTransportSipSessionValidator).onTransportOpened(allowedTags, deniedTags);
+    }
+
+    @SmallTest
+    @Test
+    public void testRegistrationStateChanged() throws Exception {
+        ArraySet<String> callIds = new ArraySet<>(2);
+        callIds.add("callId1");
+        callIds.add("callId2");
+        // empty registration state for testing
+        DelegateRegistrationState state = new DelegateRegistrationState.Builder().build();
+        MessageTransportWrapper tracker = createTestMessageTransportWrapper();
+        tracker.openTransport(mISipDelegate, Collections.emptySet(), Collections.emptySet());
+
+        Consumer<Set<String>> callIdConsumer = trackerRegStateChanged(tracker, state);
+        callIdConsumer.accept(callIds);
+        // Verify that the pending call IDs are closed properly.
+        for (String callId : callIds) {
+            verify(mTransportSipSessionValidator).onSipSessionCleanup(callId);
+            verify(mISipDelegate).cleanupSession(callId);
+        }
+    }
+
+    @SmallTest
+    @Test
+    public void testCloseGracefully() throws Exception {
+        int closingReason = DelegateRegistrationState.DEREGISTERING_REASON_PROVISIONING_CHANGE;
+        int closedReason = DelegateRegistrationState.DEREGISTERED_REASON_NOT_PROVISIONED;
+        MessageTransportWrapper tracker = createTestMessageTransportWrapper();
+
+        Boolean[] result = new Boolean[1];
+        Consumer<Set<String>> callIdConsumer = closeTrackerGracefully(tracker, closingReason,
+                closedReason, (r) -> result[0] = r);
+        callIdConsumer.accept(Collections.emptySet());
+        // Verify that the pending call IDs are closed properly.
+        verify(mTransportSipSessionValidator, never()).onSipSessionCleanup(anyString());
+        verify(mISipDelegate, never()).cleanupSession(anyString());
+        // Result is true in the case that all call IDs were successfully closed.
+        assertTrue(result[0]);
+    }
+
+    @SmallTest
+    @Test
+    public void testCloseGracefullyForceCloseCallIds() throws Exception {
+        ArraySet<String> callIds = new ArraySet<>(2);
+        callIds.add("callId1");
+        callIds.add("callId2");
+        int closingReason = DelegateRegistrationState.DEREGISTERING_REASON_PROVISIONING_CHANGE;
+        int closedReason = DelegateRegistrationState.DEREGISTERED_REASON_NOT_PROVISIONED;
+        MessageTransportWrapper tracker = createTestMessageTransportWrapper();
+        tracker.openTransport(mISipDelegate, Collections.emptySet(), Collections.emptySet());
+
+        Boolean[] result = new Boolean[1];
+        Consumer<Set<String>> callIdConsumer = closeTrackerGracefully(tracker, closingReason,
+                closedReason, (r) -> result[0] = r);
+        callIdConsumer.accept(callIds);
+        // Verify that the pending call IDs are closed properly.
+        for (String callId : callIds) {
+            verify(mTransportSipSessionValidator).onSipSessionCleanup(callId);
+            verify(mISipDelegate).cleanupSession(callId);
+        }
+        // Result is false in this case because there were still callIds left that were not
+        // successfully closed.
+        assertFalse(result[0]);
+    }
+
+    @SmallTest
+    @Test
+    public void testClose() throws Exception {
+        ArraySet<String> callIds = new ArraySet<>(2);
+        callIds.add("callId1");
+        callIds.add("callId2");
+        int closedReason = SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED;
+        doReturn(callIds).when(mTransportSipSessionValidator).closeSessions(closedReason);
+        MessageTransportWrapper tracker = createTestMessageTransportWrapper();
+        tracker.openTransport(mISipDelegate, Collections.emptySet(), Collections.emptySet());
+
+        tracker.close(closedReason);
+        // Verify that the pending call IDs are closed properly.
+        for (String callId : callIds) {
+            verify(mTransportSipSessionValidator).onSipSessionCleanup(callId);
+            verify(mISipDelegate).cleanupSession(callId);
+        }
+    }
+
+    @SmallTest
+    @Test
+    public void testDelegateConnectionSendOutgoingMessage() throws Exception {
+        MessageTransportWrapper tracker = createTestMessageTransportWrapper();
+
+        tracker.openTransport(mISipDelegate, Collections.emptySet(), Collections.emptySet());
+        doReturn(ValidationResult.SUCCESS)
+                .when(mTransportSipSessionValidator)
+                .verifyOutgoingMessage(TEST_MESSAGE, 1 /*version*/);
+        tracker.getDelegateConnection().sendMessage(TEST_MESSAGE, 1 /*version*/);
+        verify(mISipDelegate).sendMessage(TEST_MESSAGE, 1 /*version*/);
+
+        doThrow(new RemoteException()).when(mISipDelegate).sendMessage(any(), anyLong());
+        tracker.getDelegateConnection().sendMessage(TEST_MESSAGE, 1 /*version*/);
+        verify(mDelegateMessageCallback).onMessageSendFailure(any(),
+                eq(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD));
+
+        doReturn(new ValidationResult(
+                SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED, ""))
+                .when(mTransportSipSessionValidator)
+                .verifyOutgoingMessage(TEST_MESSAGE, 1 /*version*/);
+        tracker.getDelegateConnection().sendMessage(TEST_MESSAGE, 1 /*version*/);
+        verify(mDelegateMessageCallback).onMessageSendFailure(TEST_TRANSACTION_ID,
+                SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED);
+    }
+
+    @SmallTest
+    @Test
+    public void testDelegateConnectionNotifyMessageReceived() throws Exception {
+        MessageTransportWrapper tracker = createTestMessageTransportWrapper();
+        tracker.openTransport(mISipDelegate, Collections.emptySet(), Collections.emptySet());
+        tracker.getDelegateConnection().notifyMessageReceived(TEST_TRANSACTION_ID);
+        verify(mISipDelegate).notifyMessageReceived(TEST_TRANSACTION_ID);
+        verify(mTransportSipSessionValidator).acknowledgePendingMessage(TEST_TRANSACTION_ID);
+    }
+
+    @SmallTest
+    @Test
+    public void testDelegateConnectionNotifyMessageReceiveError() throws Exception {
+        MessageTransportWrapper tracker = createTestMessageTransportWrapper();
+        tracker.openTransport(mISipDelegate, Collections.emptySet(), Collections.emptySet());
+        tracker.getDelegateConnection().notifyMessageReceiveError(TEST_TRANSACTION_ID,
+                SipDelegateManager.MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE);
+        verify(mISipDelegate).notifyMessageReceiveError(TEST_TRANSACTION_ID,
+                SipDelegateManager.MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE);
+        verify(mTransportSipSessionValidator).notifyPendingMessageFailed(TEST_TRANSACTION_ID);
+    }
+
+    @SmallTest
+    @Test
+    public void testDelegateConnectionCloseSession() throws Exception {
+        MessageTransportWrapper tracker = createTestMessageTransportWrapper();
+        tracker.openTransport(mISipDelegate, Collections.emptySet(), Collections.emptySet());
+        tracker.getDelegateConnection().cleanupSession("testCallId");
+        verify(mISipDelegate).cleanupSession("testCallId");
+        verify(mTransportSipSessionValidator).onSipSessionCleanup("testCallId");
+    }
+
+    @SmallTest
+    @Test
+    public void testDelegateOnMessageReceived() throws Exception {
+        MessageTransportWrapper tracker = createTestMessageTransportWrapper();
+        tracker.openTransport(mISipDelegate, Collections.emptySet(), Collections.emptySet());
+
+        doReturn(ValidationResult.SUCCESS)
+                .when(mTransportSipSessionValidator).verifyIncomingMessage(TEST_MESSAGE);
+        tracker.getMessageCallback().onMessageReceived(TEST_MESSAGE);
+        verify(mDelegateMessageCallback).onMessageReceived(TEST_MESSAGE);
+
+        doThrow(new RemoteException()).when(mDelegateMessageCallback).onMessageReceived(any());
+        tracker.getMessageCallback().onMessageReceived(TEST_MESSAGE);
+        verify(mISipDelegate).notifyMessageReceiveError(TEST_TRANSACTION_ID,
+                SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD);
+
+        doReturn(new ValidationResult(
+                SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD, ""))
+                .when(mTransportSipSessionValidator).verifyIncomingMessage(TEST_MESSAGE);
+        tracker.getMessageCallback().onMessageReceived(TEST_MESSAGE);
+        verify(mISipDelegate, times(2)).notifyMessageReceiveError(TEST_TRANSACTION_ID,
+                SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD);
+    }
+
+    @SmallTest
+    @Test
+    public void testDelegateOnMessageSent() throws Exception {
+        MessageTransportWrapper tracker = createTestMessageTransportWrapper();
+        tracker.openTransport(mISipDelegate, Collections.emptySet(), Collections.emptySet());
+        tracker.getMessageCallback().onMessageSent(TEST_TRANSACTION_ID);
+        verify(mTransportSipSessionValidator).acknowledgePendingMessage(TEST_TRANSACTION_ID);
+        verify(mDelegateMessageCallback).onMessageSent(TEST_TRANSACTION_ID);
+    }
+
+    @SmallTest
+    @Test
+    public void testDelegateOnMessageSendFailure() throws Exception {
+        MessageTransportWrapper tracker = createTestMessageTransportWrapper();
+        tracker.openTransport(mISipDelegate, Collections.emptySet(), Collections.emptySet());
+        tracker.getMessageCallback().onMessageSendFailure(TEST_TRANSACTION_ID,
+                SipDelegateManager.MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE);
+        verify(mTransportSipSessionValidator).notifyPendingMessageFailed(TEST_TRANSACTION_ID);
+        verify(mDelegateMessageCallback).onMessageSendFailure(TEST_TRANSACTION_ID,
+                SipDelegateManager.MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE);
+    }
+
+    private MessageTransportWrapper createTestMessageTransportWrapper() {
+        return new MessageTransportWrapper(TEST_SUB_ID,
+                mExecutor, mDelegateMessageCallback, mTransportSipSessionValidator);
+    }
+
+    private Consumer<Set<String>> trackerRegStateChanged(MessageTransportWrapper tracker,
+            DelegateRegistrationState state) {
+        ArrayList<Consumer<Set<String>>> consumerCaptor = new ArrayList<>(1);
+        Mockito.doAnswer(it -> {
+            // Capture the consumer here.
+            consumerCaptor.add(it.getArgument(0));
+            return null;
+        }).when(mTransportSipSessionValidator).onRegistrationStateChanged(any(), eq(state));
+        tracker.onRegistrationStateChanged(state);
+        verify(mTransportSipSessionValidator).onRegistrationStateChanged(any(), eq(state));
+        assertFalse(consumerCaptor.isEmpty());
+        return consumerCaptor.get(0);
+    }
+
+    private Consumer<Set<String>> closeTrackerGracefully(MessageTransportWrapper tracker,
+            int closingReason, int closedReason, Consumer<Boolean> resultConsumer) {
+        ArrayList<Consumer<Set<String>>> consumerCaptor = new ArrayList<>(1);
+        Mockito.doAnswer(it -> {
+            // Capture the consumer here.
+            consumerCaptor.add(it.getArgument(0));
+            return null;
+        }).when(mTransportSipSessionValidator).closeSessionsGracefully(any(), eq(closingReason),
+                eq(closedReason));
+        tracker.closeGracefully(closingReason, closedReason, resultConsumer);
+        verify(mTransportSipSessionValidator).closeSessionsGracefully(any(), eq(closingReason),
+                eq(closedReason));
+        assertFalse(consumerCaptor.isEmpty());
+        return consumerCaptor.get(0);
+    }
+}
diff --git a/tests/src/com/android/services/telephony/rcs/SipDelegateBinderConnectionTest.java b/tests/src/com/android/services/telephony/rcs/SipDelegateBinderConnectionTest.java
index 360fa21..3d8e94b 100644
--- a/tests/src/com/android/services/telephony/rcs/SipDelegateBinderConnectionTest.java
+++ b/tests/src/com/android/services/telephony/rcs/SipDelegateBinderConnectionTest.java
@@ -25,12 +25,13 @@
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.verify;
 
+import android.net.InetAddresses;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.telephony.ims.DelegateRegistrationState;
 import android.telephony.ims.DelegateRequest;
 import android.telephony.ims.FeatureTagState;
-import android.telephony.ims.SipDelegateImsConfiguration;
+import android.telephony.ims.SipDelegateConfiguration;
 import android.telephony.ims.SipDelegateManager;
 import android.telephony.ims.aidl.IImsRegistration;
 import android.telephony.ims.aidl.ISipDelegate;
@@ -51,6 +52,7 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 
+import java.net.InetSocketAddress;
 import java.util.ArrayList;
 import java.util.Set;
 import java.util.function.BiConsumer;
@@ -194,9 +196,14 @@
         cb.onCreated(mMockDelegate, new ArrayList<>(deniedTags));
         verify(mMockCreatedCallback).accept(mMockDelegate, deniedTags);
 
-        SipDelegateImsConfiguration config = new SipDelegateImsConfiguration.Builder(1).build();
-        cb.onImsConfigurationChanged(config);
-        verify(mMockStateCallback).onImsConfigurationChanged(config);
+        InetSocketAddress localAddr = new InetSocketAddress(
+                InetAddresses.parseNumericAddress("1.1.1.1"), 80);
+        InetSocketAddress serverAddr = new InetSocketAddress(
+                InetAddresses.parseNumericAddress("2.2.2.2"), 81);
+        SipDelegateConfiguration c = new SipDelegateConfiguration.Builder(1,
+                SipDelegateConfiguration.SIP_TRANSPORT_TCP, localAddr, serverAddr).build();
+        cb.onConfigurationChanged(c);
+        verify(mMockStateCallback).onConfigurationChanged(c);
 
         DelegateRegistrationState regState = new DelegateRegistrationState.Builder()
                 .addRegisteredFeatureTags(request.getFeatureTags()).build();
diff --git a/tests/src/com/android/services/telephony/rcs/SipDelegateControllerTest.java b/tests/src/com/android/services/telephony/rcs/SipDelegateControllerTest.java
index 27f896b..5b0e7c5 100644
--- a/tests/src/com/android/services/telephony/rcs/SipDelegateControllerTest.java
+++ b/tests/src/com/android/services/telephony/rcs/SipDelegateControllerTest.java
@@ -58,13 +58,14 @@
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
+import java.util.stream.Collectors;
 
 @RunWith(AndroidJUnit4.class)
 public class SipDelegateControllerTest extends TelephonyTestBase {
     private static final int TEST_SUB_ID = 1;
 
     @Mock private ISipDelegate mMockSipDelegate;
-    @Mock private MessageTransportStateTracker mMockMessageTracker;
+    @Mock private MessageTransportWrapper mMockMessageTracker;
     @Mock private ISipDelegateMessageCallback mMockMessageCallback;
     @Mock private DelegateStateTracker mMockDelegateStateTracker;
     @Mock private DelegateBinderStateManager mMockBinderConnection;
@@ -104,12 +105,44 @@
         assertFalse(future.isDone());
         consumer.accept(mMockSipDelegate, Collections.emptySet());
         assertTrue(future.get());
-        verify(mMockMessageTracker).openTransport(mMockSipDelegate, Collections.emptySet());
+        verify(mMockMessageTracker).openTransport(mMockSipDelegate, request.getFeatureTags(),
+                Collections.emptySet());
         verify(mMockDelegateStateTracker).sipDelegateConnected(Collections.emptySet());
     }
 
     @SmallTest
     @Test
+    public void testCreateDeniedFeatures() throws Exception {
+        DelegateRequest request = getLargeDelegateRequest();
+        ArraySet<FeatureTagState> deniedTags = new ArraySet<>(1);
+        deniedTags.add(new FeatureTagState(ImsSignallingUtils.GROUP_CHAT_TAG,
+                SipDelegateManager.DENIED_REASON_NOT_ALLOWED));
+        SipDelegateController controller = getTestDelegateController(request,
+                deniedTags);
+
+        doReturn(true).when(mMockBinderConnection).create(eq(mMockMessageCallback), any());
+        CompletableFuture<Boolean> future = controller.create(request.getFeatureTags(),
+                deniedTags);
+        BiConsumer<ISipDelegate, Set<FeatureTagState>> consumer =
+                verifyConnectionCreated(1);
+        assertNotNull(consumer);
+
+        assertFalse(future.isDone());
+        // Send in additional tags denied by the service
+        deniedTags.add(new FeatureTagState(ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG,
+                SipDelegateManager.DENIED_REASON_NOT_ALLOWED));
+        consumer.accept(mMockSipDelegate, deniedTags);
+        assertTrue(future.get());
+        // Allowed tags should be initial request set - denied tags
+        ArraySet<String> allowedTags = new ArraySet<>(request.getFeatureTags());
+        allowedTags.removeAll(deniedTags.stream().map(FeatureTagState::getFeatureTag)
+                .collect(Collectors.toSet()));
+        verify(mMockMessageTracker).openTransport(mMockSipDelegate, allowedTags, deniedTags);
+        verify(mMockDelegateStateTracker).sipDelegateConnected(deniedTags);
+    }
+
+    @SmallTest
+    @Test
     public void testCreateDelegateTransportDied() throws Exception {
         DelegateRequest request = getBaseDelegateRequest();
         SipDelegateController controller = getTestDelegateController(request,
@@ -212,7 +245,9 @@
         consumer.accept(mMockSipDelegate, Collections.emptySet());
         assertTrue(pendingChange.get());
 
-        verify(mMockMessageTracker, times(2)).openTransport(mMockSipDelegate,
+        verify(mMockMessageTracker).openTransport(mMockSipDelegate, request.getFeatureTags(),
+                Collections.emptySet());
+        verify(mMockMessageTracker).openTransport(mMockSipDelegate, newFts,
                 Collections.emptySet());
         verify(mMockDelegateStateTracker, times(2)).sipDelegateConnected(Collections.emptySet());
     }
@@ -235,10 +270,22 @@
         return request;
     }
 
+    private ArraySet<String> getLargeFTSet() {
+        ArraySet<String> request = new ArraySet<>();
+        request.add(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG);
+        request.add(ImsSignallingUtils.GROUP_CHAT_TAG);
+        request.add(ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG);
+        return request;
+    }
+
     private DelegateRequest getBaseDelegateRequest() {
         return new DelegateRequest(getBaseFTSet());
     }
 
+    private DelegateRequest getLargeDelegateRequest() {
+        return new DelegateRequest(getLargeFTSet());
+    }
+
     private SipDelegateController getTestDelegateController(DelegateRequest request,
             Set<FeatureTagState> deniedSet) {
         return new SipDelegateController(TEST_SUB_ID, request, "", mExecutorService,
diff --git a/tests/src/com/android/services/telephony/rcs/SipDialogTest.java b/tests/src/com/android/services/telephony/rcs/SipDialogTest.java
new file mode 100644
index 0000000..17830c5
--- /dev/null
+++ b/tests/src/com/android/services/telephony/rcs/SipDialogTest.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2021 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.rcs;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import android.telephony.ims.SipMessage;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class SipDialogTest {
+
+    private static final String SIP_URI_ALICE = "sip:alice@client.example.com";
+    private static final String BASE_CONTACT_URI_ALICE = "Alice <" + SIP_URI_ALICE + ">";
+    private static final String SIP_URI_BOB = "sip:bob@client.example.com";
+    private static final String BASE_CONTACT_URI_BOB = "Bob <" + SIP_URI_BOB + ">";
+
+    @Test
+    public void testCreateEarlyDialog() {
+        String branchId = "testBranchId";
+        String fromTag = "abcd";
+        String callId = "testCallId";
+        SipMessage inviteRequest = SipMessageUtils.generateSipRequest(
+                SipMessageUtils.INVITE_SIP_METHOD,
+                BASE_CONTACT_URI_ALICE, BASE_CONTACT_URI_BOB, SIP_URI_BOB, branchId, callId,
+                fromTag, null /*toTag*/);
+        SipDialog dialog = SipDialog.fromSipMessage(inviteRequest);
+        assertNotNull(dialog);
+        assertEquals(SipDialog.STATE_EARLY, dialog.getState());
+        assertEquals(callId, dialog.getCallId());
+        assertNull(dialog.getToTag());
+        // receive an earlyResponse
+        String toTag = "testToTag";
+        dialog.earlyResponse(toTag);
+        assertEquals(toTag, dialog.getToTag());
+    }
+
+    @Test
+    public void testIsResponseAssociated() {
+        String branchId = "testBranchId";
+        String fromTag = "abcd";
+        String callId = "testCallId";
+        SipMessage inviteRequest = SipMessageUtils.generateSipRequest(
+                SipMessageUtils.INVITE_SIP_METHOD,
+                BASE_CONTACT_URI_ALICE, BASE_CONTACT_URI_BOB, SIP_URI_BOB, branchId, callId,
+                fromTag, null /*toTag*/);
+        SipDialog dialog = SipDialog.fromSipMessage(inviteRequest);
+        assertNotNull(dialog);
+
+        // A response with no to tag should match
+        SipMessage inviteTrying = SipMessageUtils.generateSipResponse("100", "Trying",
+                BASE_CONTACT_URI_ALICE, BASE_CONTACT_URI_BOB, branchId, callId, fromTag,
+                null /*toTag*/);
+        assertTrue(dialog.isResponseAssociatedWithDialog(inviteTrying));
+        // A response with a different to tag should match
+        inviteTrying = SipMessageUtils.generateSipResponse("100", "Trying",
+                BASE_CONTACT_URI_ALICE, BASE_CONTACT_URI_BOB, branchId, callId, fromTag,
+                "testToTag");
+        assertTrue(dialog.isResponseAssociatedWithDialog(inviteTrying));
+        // A response with a different from tag shouldn't match.
+        String fromTag2 = "testFromTag2";
+        inviteTrying = SipMessageUtils.generateSipResponse("100", "Trying",
+                BASE_CONTACT_URI_ALICE, BASE_CONTACT_URI_BOB, branchId, callId, fromTag2,
+                null /*toTag*/);
+        assertFalse(dialog.isResponseAssociatedWithDialog(inviteTrying));
+        // A response with a different branch ID shouldn't match.
+        String branchId2 = "testBranchId2";
+        inviteTrying = SipMessageUtils.generateSipResponse("100", "Trying",
+                BASE_CONTACT_URI_ALICE, BASE_CONTACT_URI_BOB, branchId2, callId, fromTag,
+                null /*toTag*/);
+        assertFalse(dialog.isResponseAssociatedWithDialog(inviteTrying));
+        // A response with a different call id shouldn't match.
+        String callId2 = "testCallId2";
+        inviteTrying = SipMessageUtils.generateSipResponse("100", "Trying",
+                BASE_CONTACT_URI_ALICE, BASE_CONTACT_URI_BOB, branchId, callId2, fromTag,
+                null /*toTag*/);
+        assertFalse(dialog.isResponseAssociatedWithDialog(inviteTrying));
+    }
+
+    @Test
+    public void testFork() {
+        String branchId = "testBranchId";
+        String fromTag = "abcd";
+        String callId = "testCallId";
+        SipMessage inviteRequest = SipMessageUtils.generateSipRequest(
+                SipMessageUtils.INVITE_SIP_METHOD,
+                BASE_CONTACT_URI_ALICE, BASE_CONTACT_URI_BOB, SIP_URI_BOB, branchId, callId,
+                fromTag, null /*toTag*/);
+        SipDialog dialog = SipDialog.fromSipMessage(inviteRequest);
+        assertNotNull(dialog);
+        assertEquals(SipDialog.STATE_EARLY, dialog.getState());
+        assertEquals(callId, dialog.getCallId());
+        // receive an earlyResponse
+        dialog.earlyResponse("testToTag");
+        assertEquals(SipDialog.STATE_EARLY, dialog.getState());
+        // fork dialog
+        SipDialog dialogFork = dialog.forkDialog();
+        assertEquals(SipDialog.STATE_EARLY, dialogFork.getState());
+        assertEquals(callId, dialogFork.getCallId());
+        assertNull(dialogFork.getToTag());
+    }
+
+    @Test
+    public void testConfirmDialog() {
+        String branchId = "testBranchId";
+        String fromTag = "abcd";
+        String callId = "testCallId";
+        SipMessage inviteRequest = SipMessageUtils.generateSipRequest(
+                SipMessageUtils.INVITE_SIP_METHOD,
+                BASE_CONTACT_URI_ALICE, BASE_CONTACT_URI_BOB, SIP_URI_BOB, branchId, callId,
+                fromTag, null /*toTag*/);
+        SipDialog dialog = SipDialog.fromSipMessage(inviteRequest);
+        assertNotNull(dialog);
+        assertEquals(SipDialog.STATE_EARLY, dialog.getState());
+        assertEquals(callId, dialog.getCallId());
+        // receive a confirm response
+        dialog.confirm("testToTag");
+        assertEquals(SipDialog.STATE_CONFIRMED, dialog.getState());
+        assertEquals(callId, dialog.getCallId());
+    }
+
+    @Test
+    public void testIsRequestAssociated() {
+        String branchId = "testBranchId";
+        String fromTag = "testFromTag";
+        String callId = "testCallId";
+        String toTag = "testToTag";
+        SipMessage inviteRequest = SipMessageUtils.generateSipRequest(
+                SipMessageUtils.INVITE_SIP_METHOD,
+                BASE_CONTACT_URI_ALICE, BASE_CONTACT_URI_BOB, SIP_URI_BOB, branchId, callId,
+                fromTag, null /*toTag*/);
+        SipDialog dialog = SipDialog.fromSipMessage(inviteRequest);
+        assertNotNull(dialog);
+        dialog.earlyResponse(toTag);
+
+        SipMessage cancelRequest = SipMessageUtils.generateSipRequest(
+                SipMessageUtils.CANCEL_SIP_METHOD, BASE_CONTACT_URI_ALICE, BASE_CONTACT_URI_BOB,
+                SIP_URI_BOB, branchId, callId, fromTag, toTag);
+        assertTrue(dialog.isRequestAssociatedWithDialog(cancelRequest));
+        // cancel request with no toTag should fail
+        cancelRequest = SipMessageUtils.generateSipRequest(
+                SipMessageUtils.INVITE_SIP_METHOD, BASE_CONTACT_URI_ALICE, BASE_CONTACT_URI_BOB,
+                SIP_URI_BOB, branchId, callId, fromTag, null /*toTag*/);
+        assertFalse(dialog.isRequestAssociatedWithDialog(cancelRequest));
+        // cancel request to a different dialog in the same session should fail
+        String toTag2 = "testToTag2";
+        cancelRequest = SipMessageUtils.generateSipRequest(
+                SipMessageUtils.INVITE_SIP_METHOD, BASE_CONTACT_URI_ALICE, BASE_CONTACT_URI_BOB,
+                SIP_URI_BOB, branchId, callId, fromTag, toTag2);
+        assertFalse(dialog.isRequestAssociatedWithDialog(cancelRequest));
+        // cancel request to a different session should fail (even with the same from/to)
+        String callId2 = "testCallId2";
+        cancelRequest = SipMessageUtils.generateSipRequest(
+                SipMessageUtils.INVITE_SIP_METHOD, BASE_CONTACT_URI_ALICE, BASE_CONTACT_URI_BOB,
+                SIP_URI_BOB, branchId, callId2, fromTag, toTag);
+        assertFalse(dialog.isRequestAssociatedWithDialog(cancelRequest));
+        // Same call id but different from and to (although not really possible) should fail.
+        String fromTag3 = "testFromTag3";
+        String toTag3 = "testToTag3";
+        cancelRequest = SipMessageUtils.generateSipRequest(
+                SipMessageUtils.INVITE_SIP_METHOD, BASE_CONTACT_URI_ALICE, BASE_CONTACT_URI_BOB,
+                SIP_URI_BOB, branchId, callId, fromTag3, toTag3);
+        assertFalse(dialog.isRequestAssociatedWithDialog(cancelRequest));
+    }
+
+    @Test
+    public void testCloseDialog() {
+        String branchId = "testBranchId";
+        String fromTag = "abcd";
+        String callId = "testCallId";
+        SipMessage inviteRequest = SipMessageUtils.generateSipRequest(
+                SipMessageUtils.INVITE_SIP_METHOD,
+                BASE_CONTACT_URI_ALICE, BASE_CONTACT_URI_BOB, SIP_URI_BOB, branchId, callId,
+                fromTag, null /*toTag*/);
+        SipDialog dialog = SipDialog.fromSipMessage(inviteRequest);
+        assertNotNull(dialog);
+        assertEquals(SipDialog.STATE_EARLY, dialog.getState());
+        assertEquals(callId, dialog.getCallId());
+
+        // receive a confirm response
+        dialog.confirm("testToTag");
+        assertEquals(SipDialog.STATE_CONFIRMED, dialog.getState());
+
+        dialog.close();
+        assertEquals(SipDialog.STATE_CLOSED, dialog.getState());
+    }
+}
diff --git a/tests/src/com/android/services/telephony/rcs/SipMessageParsingUtilsTest.java b/tests/src/com/android/services/telephony/rcs/SipMessageParsingUtilsTest.java
new file mode 100644
index 0000000..ff96eb6
--- /dev/null
+++ b/tests/src/com/android/services/telephony/rcs/SipMessageParsingUtilsTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2021 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.rcs;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+
+import android.util.ArraySet;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.internal.telephony.SipMessageParsingUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+public class SipMessageParsingUtilsTest {
+
+    @Test
+    public void testNoAcceptContactHeader() {
+        String header = "Via: SIP/2.0/UDP ex.place.com;branch=z9hG4bK776asdhds";
+        assertTrue(SipMessageParsingUtils.getAcceptContactFeatureTags(header).isEmpty());
+    }
+
+    @Test
+    public void testAcceptContactHeaderMultipleValues() {
+        Set<String> testFeatures = new ArraySet<>(2);
+        // "+a="b,c" should be split into +a="b" and +a="c"
+        testFeatures.add("+a=\"b,c\"");
+        testFeatures.add("+d");
+        testFeatures.add("+e=\"f\"");
+        // These non-feature tags should be filtered out.
+        testFeatures.add("video");
+        testFeatures.add("blah=BLAH");
+        String header = "Via: SIP/2.0/UDP ex.place.com;branch=z9hG4bK776asdhds";
+        header = addFeatures(header, testFeatures);
+        Set<String> features = SipMessageParsingUtils.getAcceptContactFeatureTags(header);
+        assertNotNull(features);
+        assertEquals(4, features.size());
+        assertTrue(features.containsAll(Arrays.asList("+a=\"b\"", "+a=\"c\"", "+d", "+e=\"f\"")));
+    }
+
+    private String addFeatures(String headers, Set<String> features) {
+        StringBuilder newHeader = new StringBuilder(headers + "\n");
+        newHeader.append("Accept-Contact:*");
+        for (String feature : features) {
+            newHeader.append(";").append(feature);
+        }
+        return newHeader.toString();
+    }
+}
diff --git a/tests/src/com/android/services/telephony/rcs/SipMessageUtils.java b/tests/src/com/android/services/telephony/rcs/SipMessageUtils.java
new file mode 100644
index 0000000..8ad0f2a
--- /dev/null
+++ b/tests/src/com/android/services/telephony/rcs/SipMessageUtils.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2021 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.rcs;
+
+import android.telephony.ims.SipMessage;
+
+public class SipMessageUtils {
+
+    public static final String INVITE_SIP_METHOD = "INVITE";
+    public static final String CANCEL_SIP_METHOD = "CANCEL";
+    public static final String BYE_SIP_METHOD = "BYE";
+    public static final String ACK_SIP_METHOD = "ACK";
+    public static final String BASE_ADDRESS = "client.example.com";
+
+    private static final String PARAM_SEPARATOR = ";";
+    private static final String PARAM_KEY_VALUE_SEPARATOR = "=";
+    private static final String BASE_VIA_HEADER_VALUE = "SIP/2.0/TCP " + BASE_ADDRESS + ":5060";
+
+    /**
+     * @return A new SIP request from the given parameters.
+     */
+    public static SipMessage generateSipRequest(String requestMethod, String fromContact,
+            String toContact, String toUri, String branchId, String callId, String fromTag,
+            String toTag) {
+        String header = "Via: " + addParamToHeader(BASE_VIA_HEADER_VALUE, "branch", branchId);
+        header += "\n";
+        header += "From: " + addParamToHeader(fromContact, "tag", fromTag);
+        header += "\n";
+        // To tag is optional
+        header += "To: " + ((toTag != null)
+                ? addParamToHeader(toContact, "tag", toTag) : toContact);
+        header += "\n";
+        header += "Call-ID: " + callId;
+        return new SipMessage(requestMethod + " " + toUri + " SIP/2.0", header, new byte[0]);
+    }
+
+    /**
+     * @return Generates a SIP response.
+     */
+    public static SipMessage generateSipResponse(String statusCode, String statusString,
+            String fromContact, String toContact, String branchId, String callId, String fromTag,
+            String toTag) {
+        String header = "Via: " + addParamToHeader(BASE_VIA_HEADER_VALUE, "branch", branchId);
+        header += "\n";
+        header += "From: " + addParamToHeader(fromContact, "tag", fromTag);
+        header += "\n";
+        // To tag is optional
+        header += "To: " + ((toTag != null)
+                ? addParamToHeader(toContact, "tag", toTag) : toContact);
+        header += "\n";
+        header += "Call-ID: " + callId;
+        return new SipMessage("SIP/2.0 " + statusCode + " " + statusString, header,
+                new byte[0]);
+    }
+
+    private static String addParamToHeader(String headerValue, String paramKey, String paramValue) {
+        headerValue += PARAM_SEPARATOR + paramKey.trim() + PARAM_KEY_VALUE_SEPARATOR
+                + paramValue.trim();
+        return headerValue;
+    }
+}
diff --git a/tests/src/com/android/services/telephony/rcs/SipSessionTrackerTest.java b/tests/src/com/android/services/telephony/rcs/SipSessionTrackerTest.java
new file mode 100644
index 0000000..823a8be
--- /dev/null
+++ b/tests/src/com/android/services/telephony/rcs/SipSessionTrackerTest.java
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2021 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.rcs;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+
+import android.net.Uri;
+import android.telephony.ims.SipMessage;
+import android.util.Base64;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@RunWith(AndroidJUnit4.class)
+public class SipSessionTrackerTest {
+
+    private class DialogAttributes {
+        public final String branchId;
+        public final String callId;
+        public final String fromHeader;
+        public final String fromTag;
+        public final String toUri;
+        public final String toHeader;
+        private final String mFromUri;
+        // This may be populated later.
+        public String toTag;
+
+        DialogAttributes() {
+            branchId = getNextString();
+            callId = getNextString();
+            mFromUri = generateRandomSipUri();
+            fromHeader = generateContactUri(mFromUri);
+            fromTag = getNextString();
+            toUri = generateRandomSipUri();
+            toHeader = generateContactUri(toUri);
+        }
+
+        private DialogAttributes(String branchId, String callId, String fromUri,
+                String fromTag, String toUri, String toTag) {
+            this.branchId = branchId;
+            this.callId = callId;
+            this.mFromUri = fromUri;
+            this.fromHeader = generateContactUri(fromUri);
+            this.fromTag = fromTag;
+            this.toUri = toUri;
+            this.toHeader = generateContactUri(toUri);
+            this.toTag = toTag;
+        }
+
+        public void setToTag() {
+            if (toTag == null) {
+                toTag = getNextString();
+            }
+        }
+
+        public DialogAttributes fromExisting() {
+            return new DialogAttributes(branchId, callId, mFromUri, fromTag, toUri, null);
+        }
+
+        public DialogAttributes invertFromTo() {
+            return new DialogAttributes(branchId, callId, toUri, fromTag, mFromUri, toTag);
+        }
+    }
+
+    // Keep track of the string entry so we can generate unique strings.
+    private int mStringEntryCounter = 0;
+    private SipSessionTracker mTrackerUT;
+
+    @Before
+    public void setUp() {
+        mStringEntryCounter = 0;
+        mTrackerUT = new SipSessionTracker();
+    }
+
+    @Test
+    public void testEarlyDialogToConfirmed() {
+        DialogAttributes attr = new DialogAttributes();
+        // INVITE A -> B
+        SipMessage inviteRequest = generateSipRequest(SipMessageUtils.INVITE_SIP_METHOD, attr);
+        filterMessage(inviteRequest, attr);
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getEarlyDialogs(), attr);
+        // 100 TRYING A <- proxy
+        SipMessage inviteTrying = generateSipResponse("100", "Trying", attr);
+        filterMessage(inviteTrying, attr);
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getEarlyDialogs(), attr);
+        // INVITE proxy -> B
+        // (BOB generates To tag)
+        attr.setToTag();
+        // 180 RINGING proxy <- B
+        // 180 RINGING A <- proxy
+        SipMessage inviteRinging = generateSipResponse("180", "Ringing", attr);
+        filterMessage(inviteRinging, attr);
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getEarlyDialogs(), attr);
+        // User answers phone
+        // 200 OK proxy <- B
+        // 200 OK A <- proxy
+        SipMessage inviteConfirm = generateSipResponse("200", "OK", attr);
+        filterMessage(inviteConfirm, attr);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getConfirmedDialogs(), attr);
+    }
+
+    @Test
+    public void testForkDialog() {
+        DialogAttributes attrB1 = new DialogAttributes();
+        // INVITE A -> B
+        SipMessage inviteRequest = generateSipRequest(SipMessageUtils.INVITE_SIP_METHOD, attrB1);
+        filterMessage(inviteRequest, attrB1);
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getEarlyDialogs(), attrB1);
+        // INVITE proxy -> B
+        // (BOB generates To tag)
+        attrB1.setToTag();
+        // 180 RINGING proxy <- B1
+        // 180 RINGING A <- proxy
+        SipMessage inviteRingingB1 = generateSipResponse("180", "Ringing", attrB1);
+        filterMessage(inviteRingingB1, attrB1);
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getEarlyDialogs(), attrB1);
+        // Now get another RINGING indication from another device associated with the same user.
+        // 180 RINGING proxy <- B2
+        // 180 RINGING A <- proxy
+        DialogAttributes attrB2 = attrB1.fromExisting();
+        // set different To tag
+        attrB2.setToTag();
+        SipMessage inviteRingingB2 = generateSipResponse("180", "Ringing", attrB2);
+        filterMessage(inviteRingingB2, attrB2);
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getEarlyDialogs(), attrB1, attrB2);
+        // User answers B1
+        // 200 OK proxy <- B1
+        // 200 OK A <- proxy
+        SipMessage inviteConfirm = generateSipResponse("200", "OK", attrB1);
+        filterMessage(inviteConfirm, attrB1);
+        verifyContainsCallIds(mTrackerUT.getEarlyDialogs(), attrB2);
+        verifyContainsCallIds(mTrackerUT.getConfirmedDialogs(), attrB1);
+        // Receive indication that B2 is terminated because user answered on B1
+        // 487 A <- proxy
+        SipMessage terminatedResponse = generateSipResponse("487",
+                "Request Terminated", attrB2);
+        filterMessage(terminatedResponse, attrB2);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getConfirmedDialogs(), attrB1);
+        verifyContainsCallIds(mTrackerUT.getClosedDialogs(), attrB2);
+        SipMessage byeRequest = generateSipRequest(SipMessageUtils.BYE_SIP_METHOD, attrB1);
+        // Send BYE request for the open dialog.
+        filterMessage(byeRequest, attrB1);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getClosedDialogs(), attrB1, attrB2);
+        // Clean up the session and ensure the close dialog is completely removed from the tracker.
+        mTrackerUT.cleanupSession(attrB1.callId);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        assertTrue(mTrackerUT.getClosedDialogs().isEmpty());
+    }
+
+    @Test
+    public void testCloseLocalDialog() {
+        DialogAttributes attr = new DialogAttributes();
+        attr.setToTag();
+        createConfirmedDialog(attr);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getConfirmedDialogs(), attr);
+
+        // Send BYE request for a dialog that was started locally and ensure that we see the call id
+        // move to the closed list.
+        SipMessage byeRequest = generateSipRequest(SipMessageUtils.BYE_SIP_METHOD, attr);
+        filterMessage(byeRequest, attr);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getClosedDialogs(), attr);
+        // Clean up the session and ensure the close dialog is completely removed from the tracker.
+        mTrackerUT.cleanupSession(attr.callId);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        assertTrue(mTrackerUT.getClosedDialogs().isEmpty());
+    }
+
+    @Test
+    public void testAcceptContactFts() {
+        DialogAttributes attr = new DialogAttributes();
+        attr.setToTag();
+        SipMessage inviteRequest = generateSipRequest(
+                SipMessageUtils.INVITE_SIP_METHOD,
+                attr);
+        // add accept contact header
+        inviteRequest = new SipMessage(inviteRequest.getStartLine(),
+                inviteRequest.getHeaderSection() + "\nAccept-Contact:*;+test",
+                new byte[0]);
+        filterMessage(inviteRequest, attr);
+        assertTrue(mTrackerUT.getCallIdsAssociatedWithFeatureTag(Collections.singleton("+test"))
+                .contains(attr.callId));
+    }
+
+    @Test
+    public void testCloseRemoteDialog() {
+        DialogAttributes remoteAttr = new DialogAttributes();
+        remoteAttr.setToTag();
+        createConfirmedDialog(remoteAttr);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getConfirmedDialogs(), remoteAttr);
+
+        // Send BYE request on a dialog that was started from the remote party.
+        DialogAttributes localAttr = remoteAttr.invertFromTo();
+        SipMessage byeRequest = generateSipRequest(SipMessageUtils.BYE_SIP_METHOD, localAttr);
+        filterMessage(byeRequest, localAttr);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getClosedDialogs(), remoteAttr);
+        // Clean up the session and ensure the dialog is completely removed from the tracker.
+        mTrackerUT.cleanupSession(remoteAttr.callId);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        assertTrue(mTrackerUT.getClosedDialogs().isEmpty());
+    }
+
+    @Test
+    public void testCleanupConfirmedDialog() {
+        DialogAttributes attr = new DialogAttributes();
+        attr.setToTag();
+        createConfirmedDialog(attr);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getConfirmedDialogs(), attr);
+        // Clean up the session and ensure the dialog is completely removed from the tracker.
+        mTrackerUT.cleanupSession(attr.callId);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        assertTrue(mTrackerUT.getClosedDialogs().isEmpty());
+    }
+
+    @Test
+    public void testMultipleDialogs() {
+        DialogAttributes attr1 = new DialogAttributes();
+        createConfirmedDialog(attr1);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getConfirmedDialogs(), attr1);
+        // add a second dialog
+        DialogAttributes attr2 = new DialogAttributes();
+        createConfirmedDialog(attr2);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getConfirmedDialogs(), attr1, attr2);
+        // Send BYE request on dialogs
+        SipMessage byeRequest = generateSipRequest(SipMessageUtils.BYE_SIP_METHOD, attr1);
+        filterMessage(byeRequest, attr1);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getConfirmedDialogs(), attr2);
+        verifyContainsCallIds(mTrackerUT.getClosedDialogs(), attr1);
+        mTrackerUT.cleanupSession(attr1.callId);
+        // Send BYE request on dialogs
+        byeRequest = generateSipRequest(SipMessageUtils.BYE_SIP_METHOD, attr2);
+        filterMessage(byeRequest, attr2);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getClosedDialogs(), attr2);
+        mTrackerUT.cleanupSession(attr2.callId);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        assertTrue(mTrackerUT.getClosedDialogs().isEmpty());
+    }
+
+    @Test
+    public void testAcknowledgeMessageFailed() {
+        DialogAttributes attr = new DialogAttributes();
+        SipMessage inviteRequest = generateSipRequest(SipMessageUtils.INVITE_SIP_METHOD, attr);
+        mTrackerUT.filterSipMessage(inviteRequest);
+        // Do not acknowledge the request and ensure that the operation has not been applied yet.
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        // send message ack failed event, the operation shouldn't have been applied
+        mTrackerUT.pendingMessageFailed(attr.branchId);
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+    }
+
+    @Test
+    public void testAcknowledgeBatchEvents() {
+        DialogAttributes attr = new DialogAttributes();
+        SipMessage inviteRequest = generateSipRequest(SipMessageUtils.INVITE_SIP_METHOD, attr);
+        attr.setToTag();
+        SipMessage inviteConfirm = generateSipResponse("200", "OK", attr);
+        // We unexpectedly received two filter requests for the same branchId without
+        // acknowledgePendingMessage being called in between. Ensure that when it is called, it
+        // applies both operations.
+        mTrackerUT.filterSipMessage(inviteRequest);
+        mTrackerUT.filterSipMessage(inviteConfirm);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        assertTrue(mTrackerUT.getConfirmedDialogs().isEmpty());
+        // we should skip right to confirmed as both operations run back-to-back
+        mTrackerUT.acknowledgePendingMessage(attr.branchId);
+        assertTrue(mTrackerUT.getEarlyDialogs().isEmpty());
+        verifyContainsCallIds(mTrackerUT.getConfirmedDialogs(), attr);
+    }
+
+    private void filterMessage(SipMessage m, DialogAttributes attr) {
+        mTrackerUT.filterSipMessage(m);
+        mTrackerUT.acknowledgePendingMessage(attr.branchId);
+    }
+    private void verifyContainsCallIds(Set<SipDialog> callIdSet, DialogAttributes... attrs) {
+        Set<String> callIds = Arrays.stream(attrs).map(a -> a.callId).collect(
+                Collectors.toSet());
+        assertTrue(callIdSet.stream().map(SipDialog::getCallId).collect(Collectors.toSet())
+                .containsAll(callIds));
+    }
+
+    private SipMessage generateSipRequest(String requestMethod,
+            DialogAttributes attr) {
+        return SipMessageUtils.generateSipRequest(requestMethod, attr.fromHeader, attr.toHeader,
+                attr.toUri, attr.branchId, attr.callId, attr.fromTag, attr.toTag);
+    }
+    private SipMessage generateSipResponse(String statusCode, String statusString,
+            DialogAttributes attr) {
+        return SipMessageUtils.generateSipResponse(statusCode, statusString, attr.fromHeader,
+                attr.toHeader, attr.branchId, attr.callId, attr.fromTag, attr.toTag);
+    }
+
+    private String generateContactUri(String sipUri) {
+        Uri uri = Uri.parse(sipUri);
+        assertNotNull(uri);
+        String[] user = uri.getSchemeSpecificPart().split("@", 2);
+        assertNotNull(user);
+        assertEquals(2, user.length);
+        return user[0] + " <" + sipUri + ">";
+    }
+
+    private String generateRandomSipUri() {
+        return "sip:" + getNextString() + "@" + SipMessageUtils.BASE_ADDRESS;
+    }
+
+    private void createConfirmedDialog(DialogAttributes attr) {
+        // INVITE ALICE -> BOB
+        SipMessage inviteRequest = generateSipRequest(
+                SipMessageUtils.INVITE_SIP_METHOD,
+                attr);
+        filterMessage(inviteRequest, attr);
+        attr.setToTag();
+        // skip to confirmed state for test.
+        SipMessage inviteConfirm = generateSipResponse("200", "OK",
+                attr);
+        filterMessage(inviteConfirm, attr);
+    }
+
+    private String getNextString() {
+        // Get a string representation of the entry counter
+        byte[] idByteArray = ByteBuffer.allocate(4).putInt(mStringEntryCounter++).array();
+        return Base64.encodeToString(idByteArray,
+                Base64.NO_WRAP | Base64.NO_PADDING | Base64.URL_SAFE);
+    }
+}
diff --git a/tests/src/com/android/services/telephony/rcs/SipTransportControllerTest.java b/tests/src/com/android/services/telephony/rcs/SipTransportControllerTest.java
index d364fe4..0f139f8 100644
--- a/tests/src/com/android/services/telephony/rcs/SipTransportControllerTest.java
+++ b/tests/src/com/android/services/telephony/rcs/SipTransportControllerTest.java
@@ -62,6 +62,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 
 import java.util.ArrayList;
@@ -87,17 +88,25 @@
         public final String packageName;
         public final DelegateRequest delegateRequest;
         public final SipDelegateController delegateController;
-        public final ISipDelegate mMockDelegate;
-        public final IBinder mMockDelegateBinder;
+        private final ISipDelegate mMockDelegate;
+        public final IBinder mockDelegateBinder;
+        public final ISipDelegateConnectionStateCallback mockDelegateConnectionCallback;
+        public final ISipDelegateMessageCallback mockMessageCallback;
+        public final IBinder mockMessageCallbackBinder;
 
         SipDelegateControllerContainer(int id, String name, DelegateRequest request) {
             delegateController = mock(SipDelegateController.class);
             mMockDelegate = mock(ISipDelegate.class);
-            mMockDelegateBinder = mock(IBinder.class);
-            doReturn(mMockDelegateBinder).when(mMockDelegate).asBinder();
+            mockDelegateBinder = mock(IBinder.class);
+            doReturn(mockDelegateBinder).when(mMockDelegate).asBinder();
+            mockDelegateConnectionCallback = mock(ISipDelegateConnectionStateCallback.class);
+            mockMessageCallback = mock(ISipDelegateMessageCallback.class);
+            mockMessageCallbackBinder = mock(IBinder.class);
+            doReturn(mockMessageCallbackBinder).when(mockMessageCallback).asBinder();
             doReturn(name).when(delegateController).getPackageName();
             doReturn(request).when(delegateController).getInitialRequest();
             doReturn(mMockDelegate).when(delegateController).getSipDelegateInterface();
+            doReturn(mockMessageCallback).when(delegateController).getAppMessageCallback();
             subId = id;
             packageName = name;
             delegateRequest = request;
@@ -107,8 +116,6 @@
     @Mock private RcsFeatureManager mRcsManager;
     @Mock private ISipTransport mSipTransport;
     @Mock private IImsRegistration mImsRegistration;
-    @Mock private ISipDelegateConnectionStateCallback mMockStateCallback;
-    @Mock private ISipDelegateMessageCallback mMockMessageCallback;
     @Mock private SipTransportController.SipDelegateControllerFactory
             mMockDelegateControllerFactory;
     @Mock private SipTransportController.RoleManagerAdapter mMockRoleManager;
@@ -249,7 +256,8 @@
         try {
             controller.createSipDelegate(TEST_SUB_ID + 1,
                     new DelegateRequest(Collections.emptySet()), TEST_PACKAGE_NAME,
-                    mMockStateCallback, mMockMessageCallback);
+                    mock(ISipDelegateConnectionStateCallback.class),
+                    mock(ISipDelegateMessageCallback.class));
             fail();
         } catch (ImsException e) {
             assertEquals(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION, e.getCode());
@@ -265,7 +273,8 @@
         try {
             controller.createSipDelegate(TEST_SUB_ID,
                     new DelegateRequest(Collections.emptySet()), TEST_PACKAGE_NAME,
-                    mMockStateCallback, mMockMessageCallback);
+                    mock(ISipDelegateConnectionStateCallback.class),
+                    mock(ISipDelegateMessageCallback.class));
             fail();
         } catch (ImsException e) {
             assertEquals(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION, e.getCode());
@@ -282,7 +291,8 @@
         try {
             controller.createSipDelegate(TEST_SUB_ID,
                     new DelegateRequest(Collections.emptySet()), TEST_PACKAGE_NAME,
-                    mMockStateCallback, mMockMessageCallback);
+                    mock(ISipDelegateConnectionStateCallback.class),
+                    mock(ISipDelegateMessageCallback.class));
             fail();
         } catch (ImsException e) {
             assertEquals(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE, e.getCode());
@@ -296,9 +306,8 @@
 
         DelegateRequest r = getBaseDelegateRequest();
 
-        SipDelegateController c = injectMockDelegateController(TEST_PACKAGE_NAME, r);
-        createDelegateAndVerify(controller, c, r, r.getFeatureTags(), Collections.emptySet(),
-                TEST_PACKAGE_NAME);
+        SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME, r);
+        createDelegateAndVerify(controller, c, r.getFeatureTags(), Collections.emptySet());
         verifyDelegateRegistrationChangedEvent(1 /*times*/, 0 /*waitMs*/);
         triggerFullNetworkRegistrationAndVerify(controller, c);
     }
@@ -309,19 +318,45 @@
         SipTransportController controller = setupLiveTransportController();
 
         DelegateRequest r = getBaseDelegateRequest();
-        SipDelegateController c = injectMockDelegateController(TEST_PACKAGE_NAME, r);
-        createDelegateAndVerify(controller, c, r, r.getFeatureTags(), Collections.emptySet(),
-                TEST_PACKAGE_NAME);
+        SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME, r);
+        createDelegateAndVerify(controller, c, r.getFeatureTags(), Collections.emptySet());
+        verify(c.mockMessageCallbackBinder).linkToDeath(any(), anyInt());
         verifyDelegateRegistrationChangedEvent(1, 0 /*throttle*/);
 
         destroyDelegateAndVerify(controller, c, false,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+        verify(c.mockMessageCallbackBinder).unlinkToDeath(any(), anyInt());
         verifyDelegateRegistrationChangedEvent(2 /*times*/, 0 /*waitMs*/);
         triggerFullNetworkRegistrationAndVerifyNever(controller, c);
     }
 
     @SmallTest
     @Test
+    public void createDestroyAppDied() throws Exception {
+        SipTransportController controller = setupLiveTransportController();
+        DelegateRequest r = getBaseDelegateRequest();
+        SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME, r);
+        createDelegateAndVerify(controller, c, r.getFeatureTags(), Collections.emptySet());
+        ArgumentCaptor<IBinder.DeathRecipient> captor =
+                ArgumentCaptor.forClass(IBinder.DeathRecipient.class);
+        verify(c.mockMessageCallbackBinder).linkToDeath(captor.capture(), anyInt());
+        IBinder.DeathRecipient deathRecipient = captor.getValue();
+        assertNotNull(deathRecipient);
+        verifyDelegateRegistrationChangedEvent(1, 0 /*throttle*/);
+
+        CompletableFuture<Integer> pendingDestroy = setDestroyFuture(c.delegateController, true,
+                SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
+        // Simulate app dying
+        deathRecipient.binderDied();
+        waitForExecutorAction(mExecutorService, TIMEOUT_MS);
+        verifyDestroyDelegate(c.delegateController, pendingDestroy, true,
+                SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
+        // If binderDied is called, then unregister does not lead to unlinkToDeath
+        triggerFullNetworkRegistrationAndVerifyNever(controller, c);
+    }
+
+    @SmallTest
+    @Test
     public void testCreateButNotInRole() throws Exception {
         SipTransportController controller = setupLiveTransportController();
 
@@ -330,9 +365,8 @@
                 SipDelegateManager.DENIED_REASON_NOT_ALLOWED);
 
         // Try to create a SipDelegate for a package that is not the default sms role.
-        SipDelegateController c = injectMockDelegateController(TEST_PACKAGE_NAME_2, r);
-        createDelegateAndVerify(controller, c, r, Collections.emptySet(), getDeniedTags,
-                TEST_PACKAGE_NAME_2);
+        SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME_2, r);
+        createDelegateAndVerify(controller, c, Collections.emptySet(), getDeniedTags);
     }
 
     @SmallTest
@@ -345,10 +379,9 @@
         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
         firstDelegate.remove(ImsSignallingUtils.GROUP_CHAT_TAG);
         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
-        SipDelegateController c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
                 firstDelegateRequest);
-        createDelegateAndVerify(controller, c1, firstDelegateRequest, firstDelegate,
-                Collections.emptySet(), TEST_PACKAGE_NAME);
+        createDelegateAndVerify(controller, c1, firstDelegate, Collections.emptySet());
         // there is a delay in the indication to update reg, so it should not happen yet.
         verifyNoDelegateRegistrationChangedEvent();
 
@@ -360,10 +393,10 @@
         Pair<Set<String>, Set<FeatureTagState>> grantedAndDenied = getAllowedAndDeniedTagsForConfig(
                 secondDelegateRequest, SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE,
                 firstDelegate);
-        SipDelegateController c2 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c2 = injectMockDelegateController(TEST_PACKAGE_NAME,
                 secondDelegateRequest);
-        createDelegateAndVerify(controller, c2, secondDelegateRequest, grantedAndDenied.first,
-                grantedAndDenied.second, TEST_PACKAGE_NAME, 1);
+        createDelegateAndVerify(controller, c2, grantedAndDenied.first,
+                grantedAndDenied.second, 1);
         // a reg changed event should happen after wait.
         verifyDelegateRegistrationChangedEvent(1, 2 * THROTTLE_MS);
     }
@@ -377,10 +410,10 @@
         Set<FeatureTagState> firstDeniedTags = getDeniedTagsForReason(
                 firstDelegateRequest.getFeatureTags(),
                 SipDelegateManager.DENIED_REASON_NOT_ALLOWED);
-        SipDelegateController c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
                 firstDelegateRequest);
-        createDelegateAndVerify(controller, c1, firstDelegateRequest,
-                firstDelegateRequest.getFeatureTags(), Collections.emptySet(), TEST_PACKAGE_NAME);
+        createDelegateAndVerify(controller, c1, firstDelegateRequest.getFeatureTags(),
+                Collections.emptySet());
         verifyDelegateRegistrationChangedEvent(1 /*times*/, THROTTLE_MS);
 
         DelegateRequest secondDelegateRequest = getBaseDelegateRequest();
@@ -388,16 +421,16 @@
                 secondDelegateRequest.getFeatureTags(),
                 SipDelegateManager.DENIED_REASON_NOT_ALLOWED);
         // Try to create a SipDelegate for a package that is not the default sms role.
-        SipDelegateController c2 = injectMockDelegateController(TEST_PACKAGE_NAME_2,
+        SipDelegateControllerContainer c2 = injectMockDelegateController(TEST_PACKAGE_NAME_2,
                 secondDelegateRequest);
-        createDelegateAndVerify(controller, c2, secondDelegateRequest, Collections.emptySet(),
-                secondDeniedTags, TEST_PACKAGE_NAME_2, 1);
+        createDelegateAndVerify(controller, c2, Collections.emptySet(), secondDeniedTags, 1);
 
         // now swap the SMS role.
-        CompletableFuture<Boolean> pendingC1Change = setChangeSupportedFeatureTagsFuture(c1,
-                Collections.emptySet(), firstDeniedTags);
-        CompletableFuture<Boolean> pendingC2Change = setChangeSupportedFeatureTagsFuture(c2,
-                secondDelegateRequest.getFeatureTags(), Collections.emptySet());
+        CompletableFuture<Boolean> pendingC1Change = setChangeSupportedFeatureTagsFuture(
+                c1.delegateController, Collections.emptySet(), firstDeniedTags);
+        CompletableFuture<Boolean> pendingC2Change = setChangeSupportedFeatureTagsFuture(
+                c2.delegateController, secondDelegateRequest.getFeatureTags(),
+                Collections.emptySet());
         setSmsRoleAndEvaluate(controller, TEST_PACKAGE_NAME_2);
         // swapping roles should trigger a deregistration event on the ImsService side.
         verifyDelegateDeregistrationEvent();
@@ -405,17 +438,18 @@
         verifyDelegateRegistrationChangedEvent(1 /*times*/, THROTTLE_MS);
         // trigger completion stage to run
         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
-        verify(c1).changeSupportedFeatureTags(Collections.emptySet(), firstDeniedTags);
+        verify(c1.delegateController).changeSupportedFeatureTags(Collections.emptySet(),
+                firstDeniedTags);
         // we should not get a change for c2 until pendingC1Change completes.
-        verify(c2, never()).changeSupportedFeatureTags(secondDelegateRequest.getFeatureTags(),
-                Collections.emptySet());
+        verify(c2.delegateController, never()).changeSupportedFeatureTags(
+                secondDelegateRequest.getFeatureTags(), Collections.emptySet());
         // ensure we are not blocking executor here
         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
         completePendingChange(pendingC1Change, true);
         // trigger completion stage to run
         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
-        verify(c2).changeSupportedFeatureTags(secondDelegateRequest.getFeatureTags(),
-                Collections.emptySet());
+        verify(c2.delegateController).changeSupportedFeatureTags(
+                secondDelegateRequest.getFeatureTags(), Collections.emptySet());
         // ensure we are not blocking executor here
         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
         completePendingChange(pendingC2Change, true);
@@ -432,10 +466,9 @@
         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
         firstDelegate.remove(ImsSignallingUtils.GROUP_CHAT_TAG);
         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
-        SipDelegateController c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
                 firstDelegateRequest);
-        createDelegateAndVerify(controller, c1, firstDelegateRequest, firstDelegate,
-                Collections.emptySet(), TEST_PACKAGE_NAME);
+        createDelegateAndVerify(controller, c1, firstDelegate, Collections.emptySet());
         verifyNoDelegateRegistrationChangedEvent();
 
         // First delegate requests RCS message + Group RCS message. For this delegate, single RCS
@@ -446,21 +479,21 @@
         Pair<Set<String>, Set<FeatureTagState>> grantedAndDenied = getAllowedAndDeniedTagsForConfig(
                 secondDelegateRequest, SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE,
                 firstDelegate);
-        SipDelegateController c2 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c2 = injectMockDelegateController(TEST_PACKAGE_NAME,
                 secondDelegateRequest);
-        createDelegateAndVerify(controller, c2, secondDelegateRequest, grantedAndDenied.first,
-                grantedAndDenied.second, TEST_PACKAGE_NAME, 1);
+        createDelegateAndVerify(controller, c2, grantedAndDenied.first, grantedAndDenied.second, 1);
         verifyNoDelegateRegistrationChangedEvent();
 
         // Destroy the firstDelegate, which should now cause all previously denied tags to be
         // granted to the new delegate.
-        CompletableFuture<Boolean> pendingC2Change = setChangeSupportedFeatureTagsFuture(c2,
-                secondDelegate, Collections.emptySet());
+        CompletableFuture<Boolean> pendingC2Change = setChangeSupportedFeatureTagsFuture(
+                c2.delegateController, secondDelegate, Collections.emptySet());
         destroyDelegateAndVerify(controller, c1, false /*force*/,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
         // wait for create to be processed.
         assertTrue(waitForExecutorAction(mExecutorService, TIMEOUT_MS));
-        verify(c2).changeSupportedFeatureTags(secondDelegate, Collections.emptySet());
+        verify(c2.delegateController).changeSupportedFeatureTags(secondDelegate,
+                Collections.emptySet());
         completePendingChange(pendingC2Change, true);
 
         verifyDelegateRegistrationChangedEvent(1 /*times*/, THROTTLE_MS);
@@ -475,10 +508,10 @@
         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
         firstDelegate.remove(ImsSignallingUtils.GROUP_CHAT_TAG);
         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
-        SipDelegateController c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
                 firstDelegateRequest);
         CompletableFuture<Boolean> pendingC1Change = createDelegate(controller, c1,
-                firstDelegateRequest, firstDelegate, Collections.emptySet(), TEST_PACKAGE_NAME);
+                firstDelegate, Collections.emptySet());
 
         // Request RCS message + group RCS Message. For this delegate, single RCS message should be
         // denied.
@@ -488,11 +521,10 @@
         Pair<Set<String>, Set<FeatureTagState>> grantedAndDeniedC2 =
                 getAllowedAndDeniedTagsForConfig(secondDelegateRequest,
                         SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE, firstDelegate);
-        SipDelegateController c2 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c2 = injectMockDelegateController(TEST_PACKAGE_NAME,
                 secondDelegateRequest);
         CompletableFuture<Boolean> pendingC2Change = createDelegate(controller, c2,
-                secondDelegateRequest, grantedAndDeniedC2.first, grantedAndDeniedC2.second,
-                TEST_PACKAGE_NAME);
+                grantedAndDeniedC2.first, grantedAndDeniedC2.second);
 
         // Request group RCS message + file transfer. All should be denied at first
         ArraySet<String> thirdDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
@@ -502,42 +534,44 @@
                 getAllowedAndDeniedTagsForConfig(thirdDelegateRequest,
                         SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE, firstDelegate,
                         grantedAndDeniedC2.first);
-        SipDelegateController c3 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c3 = injectMockDelegateController(TEST_PACKAGE_NAME,
                 thirdDelegateRequest);
         CompletableFuture<Boolean> pendingC3Change = createDelegate(controller, c3,
-                thirdDelegateRequest, grantedAndDeniedC3.first, grantedAndDeniedC3.second,
-                TEST_PACKAGE_NAME);
+                grantedAndDeniedC3.first, grantedAndDeniedC3.second);
 
         verifyNoDelegateRegistrationChangedEvent();
         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
-        verifyDelegateChanged(c1, pendingC1Change, firstDelegate, Collections.emptySet(), 0);
-        verifyDelegateChanged(c2, pendingC2Change, grantedAndDeniedC2.first,
+        verifyDelegateChanged(c1.delegateController, pendingC1Change, firstDelegate,
+                Collections.emptySet(), 0);
+        verifyDelegateChanged(c2.delegateController, pendingC2Change, grantedAndDeniedC2.first,
                 grantedAndDeniedC2.second, 0);
-        verifyDelegateChanged(c3, pendingC3Change, grantedAndDeniedC3.first,
+        verifyDelegateChanged(c3.delegateController, pendingC3Change, grantedAndDeniedC3.first,
                 grantedAndDeniedC3.second, 0);
         verifyDelegateRegistrationChangedEvent(1, 2 * THROTTLE_MS);
 
         // Destroy the first and second controller in quick succession, this should only generate
         // one reevaluate for the third controller.
         CompletableFuture<Boolean> pendingChangeC3 = setChangeSupportedFeatureTagsFuture(
-                c3, thirdDelegate, Collections.emptySet());
-        CompletableFuture<Integer> pendingDestroyC1 = destroyDelegate(controller, c1,
-                false /*force*/,
+                c3.delegateController, thirdDelegate, Collections.emptySet());
+        CompletableFuture<Integer> pendingDestroyC1 = destroyDelegate(controller,
+                c1.delegateController, false /*force*/,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
-        CompletableFuture<Integer> pendingDestroyC2 = destroyDelegate(controller, c2,
-                false /*force*/,
+        CompletableFuture<Integer> pendingDestroyC2 = destroyDelegate(controller,
+                c2.delegateController, false /*force*/,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
-        verifyDestroyDelegate(controller, c1, pendingDestroyC1, false /*force*/,
+        verifyDestroyDelegate(c1.delegateController, pendingDestroyC1, false /*force*/,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
-        verifyDestroyDelegate(controller, c2, pendingDestroyC2, false /*force*/,
+        verifyDestroyDelegate(c2.delegateController, pendingDestroyC2, false /*force*/,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
 
         // All requested features should now be granted
         completePendingChange(pendingChangeC3, true);
-        verify(c3).changeSupportedFeatureTags(thirdDelegate, Collections.emptySet());
+        verify(c3.delegateController)
+                .changeSupportedFeatureTags(thirdDelegate, Collections.emptySet());
         // In total reeval should have only been called twice.
-        verify(c3, times(2)).changeSupportedFeatureTags(any(), any());
+        verify(c3.delegateController, times(2))
+                .changeSupportedFeatureTags(any(), any());
         verifyDelegateRegistrationChangedEvent(2 /*times*/, 2 * THROTTLE_MS);
     }
 
@@ -548,17 +582,16 @@
 
         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
-        SipDelegateController c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME,
                 firstDelegateRequest);
-        createDelegateAndVerify(controller, c1, firstDelegateRequest, firstDelegate,
-                Collections.emptySet(), TEST_PACKAGE_NAME);
+        createDelegateAndVerify(controller, c, firstDelegate, Collections.emptySet());
         verifyDelegateRegistrationChangedEvent(1 /*times*/, 0 /*waitMs*/);
 
-        CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c1, true,
+        CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c.delegateController, true,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
         controller.onAssociatedSubscriptionUpdated(TEST_SUB_ID + 1);
         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
-        verifyDestroyDelegate(controller, c1, pendingDestroy, true /*force*/,
+        verifyDestroyDelegate(c.delegateController, pendingDestroy, true /*force*/,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
         verifyDelegateRegistrationChangedEvent(2 /*times*/, 0 /*waitMs*/);
     }
@@ -570,16 +603,15 @@
 
         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
-        SipDelegateController c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME,
                 firstDelegateRequest);
-        createDelegateAndVerify(controller, c1, firstDelegateRequest, firstDelegate,
-                Collections.emptySet(), TEST_PACKAGE_NAME);
+        createDelegateAndVerify(controller, c, firstDelegate, Collections.emptySet());
 
-        CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c1, true,
+        CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c.delegateController, true,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
         controller.onRcsDisconnected();
         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
-        verifyDestroyDelegate(controller, c1, pendingDestroy, true /*force*/,
+        verifyDestroyDelegate(c.delegateController, pendingDestroy, true /*force*/,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
         verifyDelegateRegistrationChangedEvent(1, 0 /*waitMs*/);
     }
@@ -591,18 +623,17 @@
 
         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
-        SipDelegateController c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME,
                 firstDelegateRequest);
-        createDelegateAndVerify(controller, c1, firstDelegateRequest, firstDelegate,
-                Collections.emptySet(), TEST_PACKAGE_NAME);
+        createDelegateAndVerify(controller, c, firstDelegate, Collections.emptySet());
 
-        CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c1, true,
-                SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
+        CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c.delegateController,
+                true, SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
         controller.onDestroy();
         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
         verifyDelegateDeregistrationEvent();
         // verify change was called.
-        verify(c1).destroy(true /*force*/,
+        verify(c.delegateController).destroy(true /*force*/,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
         // ensure thread is not blocked while waiting for pending complete.
         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
@@ -620,16 +651,17 @@
 
         ArraySet<String> firstDelegate = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
         DelegateRequest firstDelegateRequest = new DelegateRequest(firstDelegate);
-        SipDelegateController c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c1 = injectMockDelegateController(TEST_PACKAGE_NAME,
                 firstDelegateRequest);
         CompletableFuture<Boolean> pendingC1Change = createDelegate(controller, c1,
-                firstDelegateRequest, firstDelegate, Collections.emptySet(), TEST_PACKAGE_NAME);
+                firstDelegate, Collections.emptySet());
         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
-        verifyDelegateChanged(c1, pendingC1Change, firstDelegate, Collections.emptySet(), 0);
+        verifyDelegateChanged(c1.delegateController, pendingC1Change, firstDelegate,
+                Collections.emptySet(), 0);
 
 
-        CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c1, true,
-                SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
+        CompletableFuture<Integer> pendingDestroy =  setDestroyFuture(c1.delegateController,
+                true, SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
         // triggers reeval now.
         controller.onAssociatedSubscriptionUpdated(TEST_SUB_ID + 1);
         waitForExecutorAction(mExecutorService, TIMEOUT_MS);
@@ -639,18 +671,18 @@
         secondDelegate.add(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG);
         secondDelegate.add(ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG);
         DelegateRequest secondDelegateRequest = new DelegateRequest(secondDelegate);
-        SipDelegateController c2 = injectMockDelegateController(TEST_SUB_ID + 1,
+        SipDelegateControllerContainer c2 = injectMockDelegateController(TEST_SUB_ID + 1,
                 TEST_PACKAGE_NAME, secondDelegateRequest);
-        CompletableFuture<Boolean> pendingC2Change = createDelegate(controller, c2,
-                TEST_SUB_ID + 1, secondDelegateRequest, secondDelegate,
-                Collections.emptySet(), TEST_PACKAGE_NAME);
+        CompletableFuture<Boolean> pendingC2Change = createDelegate(controller, c2, secondDelegate,
+                Collections.emptySet());
         assertTrue(scheduleDelayedWait(THROTTLE_MS));
 
         //trigger destroyed event
-        verifyDestroyDelegate(controller, c1, pendingDestroy, true /*force*/,
+        verifyDestroyDelegate(c1.delegateController, pendingDestroy, true /*force*/,
                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN);
         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
-        verifyDelegateChanged(c2, pendingC2Change, secondDelegate, Collections.emptySet(), 0);
+        verifyDelegateChanged(c2.delegateController, pendingC2Change, secondDelegate,
+                Collections.emptySet(), 0);
     }
 
     @SmallTest
@@ -664,16 +696,17 @@
         ArraySet<String> allowedTags = new ArraySet<>(requestTags);
         ArraySet<String> deniedTags = new ArraySet<>();
         DelegateRequest delegateRequest = new DelegateRequest(requestTags);
-        SipDelegateController sc = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME,
                 delegateRequest);
-        CompletableFuture<Boolean> pendingScChange = createDelegate(controller, sc,
-                delegateRequest, requestTags, Collections.emptySet(), TEST_PACKAGE_NAME);
+        CompletableFuture<Boolean> pendingScChange = createDelegate(controller, c, requestTags,
+                Collections.emptySet());
         allowedTags.remove(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG);
         deniedTags.add(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG);
 
         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
-        verifyDelegateChanged(sc, pendingScChange, allowedTags, getDeniedTagsForReason(
-                deniedTags, SipDelegateManager.DENIED_REASON_NOT_ALLOWED), 0);
+        verifyDelegateChanged(c.delegateController, pendingScChange, allowedTags,
+                getDeniedTagsForReason(deniedTags,
+                        SipDelegateManager.DENIED_REASON_NOT_ALLOWED), 0);
     }
 
     @SmallTest
@@ -685,14 +718,15 @@
         ArraySet<String> requestTags = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
         ArraySet<String> deniedTags = new ArraySet<>(requestTags);
         DelegateRequest delegateRequest = new DelegateRequest(requestTags);
-        SipDelegateController sc = injectMockDelegateController(TEST_PACKAGE_NAME,
+        SipDelegateControllerContainer c = injectMockDelegateController(TEST_PACKAGE_NAME,
                 delegateRequest);
-        CompletableFuture<Boolean> pendingScChange = createDelegate(controller, sc,
-                delegateRequest, requestTags, Collections.emptySet(), TEST_PACKAGE_NAME);
+        CompletableFuture<Boolean> pendingScChange = createDelegate(controller, c, requestTags,
+                Collections.emptySet());
 
         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
-        verifyDelegateChanged(sc, pendingScChange, Collections.emptySet(), getDeniedTagsForReason(
-                deniedTags, SipDelegateManager.DENIED_REASON_NOT_ALLOWED), 0);
+        verifyDelegateChanged(c.delegateController, pendingScChange, Collections.emptySet(),
+                getDeniedTagsForReason(deniedTags,
+                        SipDelegateManager.DENIED_REASON_NOT_ALLOWED), 0);
     }
 
     @SmallTest
@@ -705,13 +739,14 @@
         ArraySet<String> requestTags = new ArraySet<>(getBaseDelegateRequest().getFeatureTags());
         ArraySet<String> allowedTags = new ArraySet<>(requestTags);
         DelegateRequest delegateRequest = new DelegateRequest(requestTags);
-        SipDelegateController sc = injectMockDelegateController(TEST_PACKAGE_NAME,
-                delegateRequest);
-        CompletableFuture<Boolean> pendingScChange = createDelegate(controller, sc,
-                delegateRequest, requestTags, Collections.emptySet(), TEST_PACKAGE_NAME);
+        SipDelegateControllerContainer controllerContainer =
+                injectMockDelegateController(TEST_PACKAGE_NAME, delegateRequest);
+        CompletableFuture<Boolean> pendingScChange = createDelegate(controller, controllerContainer,
+                requestTags, Collections.emptySet());
 
         assertTrue(scheduleDelayedWait(2 * THROTTLE_MS));
-        verifyDelegateChanged(sc, pendingScChange, allowedTags, Collections.emptySet(), 0);
+        verifyDelegateChanged(controllerContainer.delegateController, pendingScChange, allowedTags,
+                Collections.emptySet(), 0);
     }
 
     @SafeVarargs
@@ -756,31 +791,32 @@
     }
 
     private void createDelegateAndVerify(SipTransportController controller,
-            SipDelegateController delegateController, DelegateRequest r, Set<String> allowedTags,
-            Set<FeatureTagState> deniedTags, String packageName,
-            int numPreviousChanges) throws ImsException {
+            SipDelegateControllerContainer controllerContainer, Set<String> allowedTags,
+            Set<FeatureTagState> deniedTags, int numPreviousChanges) {
 
-        CompletableFuture<Boolean> pendingChange = createDelegate(controller, delegateController, r,
-                allowedTags, deniedTags, packageName);
-        verifyDelegateChanged(delegateController, pendingChange, allowedTags, deniedTags,
-                numPreviousChanges);
+        CompletableFuture<Boolean> pendingChange = createDelegate(controller, controllerContainer,
+                allowedTags, deniedTags);
+        verifyDelegateChanged(controllerContainer.delegateController, pendingChange, allowedTags,
+                deniedTags, numPreviousChanges);
     }
 
     private void createDelegateAndVerify(SipTransportController controller,
-            SipDelegateController delegateController, DelegateRequest r, Set<String> allowedTags,
-            Set<FeatureTagState> deniedTags, String packageName) throws ImsException {
-        createDelegateAndVerify(controller, delegateController, r, allowedTags, deniedTags,
-                packageName, 0);
+            SipDelegateControllerContainer controllerContainer, Set<String> allowedTags,
+            Set<FeatureTagState> deniedTags) {
+        createDelegateAndVerify(controller, controllerContainer, allowedTags, deniedTags, 0);
     }
 
     private CompletableFuture<Boolean> createDelegate(SipTransportController controller,
-            SipDelegateController delegateController, int subId, DelegateRequest r,
-            Set<String> allowedTags, Set<FeatureTagState> deniedTags, String packageName) {
+            SipDelegateControllerContainer delegateControllerContainer, Set<String> allowedTags,
+            Set<FeatureTagState> deniedTags) {
         CompletableFuture<Boolean> pendingChange = setChangeSupportedFeatureTagsFuture(
-                delegateController, allowedTags, deniedTags);
+                delegateControllerContainer.delegateController, allowedTags, deniedTags);
         try {
-            controller.createSipDelegate(subId, r, packageName, mMockStateCallback,
-                    mMockMessageCallback);
+            controller.createSipDelegate(delegateControllerContainer.subId,
+                    delegateControllerContainer.delegateRequest,
+                    delegateControllerContainer.packageName,
+                    delegateControllerContainer.mockDelegateConnectionCallback,
+                    delegateControllerContainer.mockMessageCallback);
         } catch (ImsException e) {
             fail("ImsException thrown:" + e);
         }
@@ -791,13 +827,6 @@
         return pendingChange;
     }
 
-    private CompletableFuture<Boolean> createDelegate(SipTransportController controller,
-            SipDelegateController delegateController, DelegateRequest r, Set<String> allowedTags,
-            Set<FeatureTagState> deniedTags, String packageName) throws ImsException {
-        return createDelegate(controller, delegateController, TEST_SUB_ID, r, allowedTags,
-                deniedTags, packageName);
-    }
-
     private void verifyDelegateChanged(SipDelegateController delegateController,
             CompletableFuture<Boolean> pendingChange, Set<String> allowedTags,
             Set<FeatureTagState> deniedTags, int numPreviousChangeStages) {
@@ -817,10 +846,11 @@
     }
 
     private void destroyDelegateAndVerify(SipTransportController controller,
-            SipDelegateController delegateController, boolean force, int reason) {
+            SipDelegateControllerContainer controllerContainer, boolean force, int reason) {
+        SipDelegateController delegateController = controllerContainer.delegateController;
         CompletableFuture<Integer> pendingDestroy =  destroyDelegate(controller, delegateController,
                 force, reason);
-        verifyDestroyDelegate(controller, delegateController, pendingDestroy, force, reason);
+        verifyDestroyDelegate(delegateController, pendingDestroy, force, reason);
     }
 
     private CompletableFuture<Integer> destroyDelegate(SipTransportController controller,
@@ -836,9 +866,8 @@
         return pendingDestroy;
     }
 
-    private void verifyDestroyDelegate(SipTransportController controller,
-            SipDelegateController delegateController, CompletableFuture<Integer> pendingDestroy,
-            boolean force, int reason) {
+    private void verifyDestroyDelegate(SipDelegateController delegateController,
+            CompletableFuture<Integer> pendingDestroy, boolean force, int reason) {
         // verify destroy was called.
         verify(delegateController).destroy(force, reason);
         // ensure thread is not blocked while waiting for pending complete.
@@ -847,7 +876,8 @@
     }
 
     private void triggerFullNetworkRegistrationAndVerify(SipTransportController controller,
-            SipDelegateController delegateController) {
+            SipDelegateControllerContainer controllerContainer) {
+        SipDelegateController delegateController = controllerContainer.delegateController;
         controller.triggerFullNetworkRegistration(TEST_SUB_ID,
                 delegateController.getSipDelegateInterface(), 403, "forbidden");
         // move to internal & trigger event
@@ -856,7 +886,8 @@
     }
 
     private void triggerFullNetworkRegistrationAndVerifyNever(SipTransportController controller,
-            SipDelegateController delegateController) {
+            SipDelegateControllerContainer controllerContainer) {
+        SipDelegateController delegateController = controllerContainer.delegateController;
         controller.triggerFullNetworkRegistration(TEST_SUB_ID,
                 delegateController.getSipDelegateInterface(), 403, "forbidden");
         // move to internal & potentially trigger event
@@ -872,29 +903,22 @@
         return new DelegateRequest(featureTags);
     }
 
-    private Set<FeatureTagState> getBaseDeniedSet() {
-        Set<FeatureTagState> deniedTags = new ArraySet<>();
-        deniedTags.add(new FeatureTagState(ImsSignallingUtils.MMTEL_TAG,
-                SipDelegateManager.DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE));
-        return deniedTags;
-    }
-
     private Set<FeatureTagState> getDeniedTagsForReason(Set<String> deniedTags, int reason) {
         return deniedTags.stream().map(t -> new FeatureTagState(t, reason))
                 .collect(Collectors.toSet());
     }
 
-    private SipDelegateController injectMockDelegateController(String packageName,
+    private SipDelegateControllerContainer injectMockDelegateController(String packageName,
             DelegateRequest r) {
         return injectMockDelegateController(TEST_SUB_ID, packageName, r);
     }
 
-    private SipDelegateController injectMockDelegateController(int subId, String packageName,
-            DelegateRequest r) {
+    private SipDelegateControllerContainer injectMockDelegateController(int subId,
+            String packageName, DelegateRequest r) {
         SipDelegateControllerContainer c = new SipDelegateControllerContainer(subId,
                 packageName, r);
         mMockControllers.add(c);
-        return c.delegateController;
+        return c;
     }
 
     private SipDelegateController getMockDelegateController(int subId, String packageName,
diff --git a/tests/src/com/android/services/telephony/rcs/TransportSipMessageValidatorTest.java b/tests/src/com/android/services/telephony/rcs/TransportSipMessageValidatorTest.java
new file mode 100644
index 0000000..4d222e3
--- /dev/null
+++ b/tests/src/com/android/services/telephony/rcs/TransportSipMessageValidatorTest.java
@@ -0,0 +1,487 @@
+/*
+ * Copyright (C) 2021 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.rcs;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.net.InetAddresses;
+import android.telephony.ims.DelegateRegistrationState;
+import android.telephony.ims.SipDelegateConfiguration;
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+import android.util.ArraySet;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.TelephonyTestBase;
+import com.android.TestExecutorService;
+import com.android.services.telephony.rcs.validator.IncomingTransportStateValidator;
+import com.android.services.telephony.rcs.validator.OutgoingTransportStateValidator;
+import com.android.services.telephony.rcs.validator.ValidationResult;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+import java.net.InetSocketAddress;
+import java.util.Collections;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ScheduledExecutorService;
+
+@RunWith(AndroidJUnit4.class)
+public class TransportSipMessageValidatorTest extends TelephonyTestBase {
+    private static final int TEST_SUB_ID = 1;
+    private static final int TEST_CONFIG_VERSION = 1;
+    private static final SipMessage TEST_MESSAGE = new SipMessage(
+            "INVITE sip:bob@biloxi.com SIP/2.0",
+            // Typical Via
+            "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds\n"
+                    + "Max-Forwards: 70\n"
+                    + "To: Bob <sip:bob@biloxi.com>\n"
+                    + "From: Alice <sip:alice@atlanta.com>;tag=1928301774\n"
+                    + "Call-ID: testid\n"
+                    + "CSeq: 314159 INVITE\n"
+                    + "Contact: <sip:alice@pc33.atlanta.com>\n"
+                    + "Content-Type: application/sdp\n"
+                    + "Content-Length: 142",
+            new byte[0]);
+
+    @Mock
+    private SipSessionTracker mSipSessionTracker;
+    @Mock
+    private IncomingTransportStateValidator mIncomingStateValidator;
+    @Mock
+    private OutgoingTransportStateValidator mOutgoingStateValidator;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    @Test
+    public void testTransportOpening() {
+        TestExecutorService executor = new TestExecutorService();
+        TransportSipMessageValidator tracker = getTestTracker(executor);
+        tracker.onTransportOpened(Collections.emptySet(), Collections.emptySet());
+        verify(mOutgoingStateValidator).open(Collections.emptySet(), Collections.emptySet());
+        verify(mIncomingStateValidator).open();
+        // Incoming messages are already verified
+        assertTrue(isIncomingTransportOpen(tracker));
+        // IMS config needs to be sent before outgoing messages can be verified.
+        assertFalse(isOutgoingTransportOpen(tracker));
+        tracker.onConfigurationChanged(getConfigBuilder(TEST_CONFIG_VERSION).build());
+        // Incoming messages are already verified
+        // Config set, transport is now open.
+        assertTrue(isIncomingTransportOpen(tracker));
+        assertTrue(isOutgoingTransportOpen(tracker));
+    }
+
+    @Test
+    public void testTransportOpenConfigChange() {
+        TestExecutorService executor = new TestExecutorService();
+        TransportSipMessageValidator tracker = openTransport(executor);
+
+        // Update IMS config version and send a message with an outdated version.
+        tracker.onConfigurationChanged(getConfigBuilder(TEST_CONFIG_VERSION + 1).build());
+        assertEquals(SipDelegateManager.MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION,
+                verifyOutgoingTransportClosed(tracker));
+    }
+
+    @Test
+    public void testSessionTrackerFiltering() {
+        TestExecutorService executor = new TestExecutorService();
+        TransportSipMessageValidator tracker = openTransport(executor);
+        // Since the incoming/outgoing messages were verified, there should have been two calls
+        // to filter the message.
+        verify(mSipSessionTracker, times(2)).filterSipMessage(TEST_MESSAGE);
+        // ensure pass through methods are working
+        tracker.acknowledgePendingMessage("abc");
+        verify(mSipSessionTracker).acknowledgePendingMessage("abc");
+        tracker.notifyPendingMessageFailed("abc");
+        verify(mSipSessionTracker).pendingMessageFailed("abc");
+        tracker.onSipSessionCleanup("abc");
+        verify(mSipSessionTracker).cleanupSession("abc");
+        // Now have validators return a non-successful result for validation and the tracker should
+        // not get the indication to filter the message.
+        doReturn(new ValidationResult(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED,
+                "")).when(mOutgoingStateValidator).validate(any());
+        doReturn(new ValidationResult(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED,
+                "")).when(mIncomingStateValidator).validate(any());
+        assertFalse(tracker.verifyIncomingMessage(TEST_MESSAGE).isValidated);
+        assertFalse(tracker.verifyOutgoingMessage(TEST_MESSAGE, TEST_CONFIG_VERSION).isValidated);
+        // The number of times the filter method was called should still only be two after these
+        // messages were not validated.
+        verify(mSipSessionTracker, times(2)).filterSipMessage(TEST_MESSAGE);
+    }
+
+
+    @Test
+    public void testTransportClosingGracefullyNoPendingSessions() {
+        TestExecutorService executor = new TestExecutorService(true /*wait*/);
+        TransportSipMessageValidator tracker = openTransport(executor);
+
+        doReturn(Collections.emptySet()).when(mSipSessionTracker).getTrackedDialogs();
+        ArraySet<String> pendingCallIds = new ArraySet<>();
+        CountDownLatch l = new CountDownLatch(1);
+        tracker.closeSessionsGracefully((ids) -> {
+            pendingCallIds.addAll(ids);
+            l.countDown();
+        }, SipDelegateManager.MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION,
+                SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED);
+        // Since there are no pending call ids, this should be completed with no call ids pending.
+        assertEquals(0, l.getCount());
+        assertTrue(pendingCallIds.isEmpty());
+        verify(mOutgoingStateValidator).close(anyInt());
+        verify(mIncomingStateValidator).close(anyInt());
+    }
+
+    @Test
+    public void testTransportClosingGracefullyCloseCallIds() {
+        TestExecutorService executor = new TestExecutorService(true /*wait*/);
+        TransportSipMessageValidator tracker = openTransport(executor);
+
+        ArraySet<SipDialog> dialogs = new ArraySet<>();
+        dialogs.add(SipDialog.fromSipMessage(TEST_MESSAGE));
+        doReturn(dialogs).when(mSipSessionTracker).getTrackedDialogs();
+        ArraySet<String> pendingCallIds = new ArraySet<>();
+        CountDownLatch l = new CountDownLatch(1);
+        tracker.closeSessionsGracefully((ids) -> {
+            pendingCallIds.addAll(ids);
+            l.countDown();
+        }, SipDelegateManager.MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION,
+                SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED);
+        // Before executor executes, outgoing messages will be restricted due to pending call ids.
+        assertTrue(l.getCount() >= 1);
+        assertTrue(pendingCallIds.isEmpty());
+        assertTrue(isIncomingTransportOpen(tracker));
+        verify(mOutgoingStateValidator).restrict(anyInt());
+        // pretend a sip message has been acknowledged, which closed pending call id. Since there
+        // are no more pending call ids, the transport should move to closed.
+        dialogs.clear();
+        tracker.acknowledgePendingMessage("blah");
+        assertEquals(0, l.getCount());
+        assertTrue(pendingCallIds.isEmpty());
+        verify(mOutgoingStateValidator).close(anyInt());
+        verify(mIncomingStateValidator).close(anyInt());
+    }
+
+    @Test
+    public void testTransportClosingGracefullyThenForceClose() {
+        TestExecutorService executor = new TestExecutorService(true /*wait*/);
+        TransportSipMessageValidator tracker = openTransport(executor);
+
+        ArraySet<SipDialog> dialogs = new ArraySet<>();
+        dialogs.add(SipDialog.fromSipMessage(TEST_MESSAGE));
+        doReturn(dialogs).when(mSipSessionTracker).getTrackedDialogs();
+        ArraySet<String> pendingCallIds = new ArraySet<>();
+        CountDownLatch l = new CountDownLatch(1);
+        tracker.closeSessionsGracefully((ids) -> {
+            pendingCallIds.addAll(ids);
+            l.countDown();
+        }, SipDelegateManager.MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION,
+                SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED);
+        // Before executor executes, outgoing messages will be restricted due to pending call ids.
+        assertTrue(l.getCount() >= 1);
+        assertTrue(pendingCallIds.isEmpty());
+        assertTrue(isIncomingTransportOpen(tracker));
+        verify(mOutgoingStateValidator).restrict(anyInt());
+        // force close amd ensure pending close is
+        assertTrue(tracker.closeSessions(
+                SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED).isEmpty());
+        assertEquals(0, l.getCount());
+        assertEquals(pendingCallIds, pendingCallIds);
+        verify(mOutgoingStateValidator).close(anyInt());
+        verify(mIncomingStateValidator).close(anyInt());
+    }
+
+    @Test
+    public void testTransportClosingGracefullyTimeout() {
+        TestExecutorService executor = new TestExecutorService(true /*wait*/);
+        TransportSipMessageValidator tracker = openTransport(executor);
+
+        ArraySet<SipDialog> dialogs = new ArraySet<>();
+        dialogs.add(SipDialog.fromSipMessage(TEST_MESSAGE));
+        doReturn(dialogs).when(mSipSessionTracker).getTrackedDialogs();
+        ArraySet<String> pendingCallIds = new ArraySet<>();
+        CountDownLatch l = new CountDownLatch(1);
+        tracker.closeSessionsGracefully((ids) -> {
+            pendingCallIds.addAll(ids);
+            l.countDown();
+        }, SipDelegateManager.MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION,
+                SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED);
+        // Before executor executes, outgoing messages will be restricted due to pending call ids.
+        assertTrue(l.getCount() >= 1);
+        assertTrue(pendingCallIds.isEmpty());
+        assertTrue(isIncomingTransportOpen(tracker));
+        verify(mOutgoingStateValidator).restrict(anyInt());
+        // Process timeout event - pending call id should be passed to transport.
+        executor.executePending();
+        assertEquals(0, l.getCount());
+        assertTrue(pendingCallIds.contains("testid"));
+        verify(mOutgoingStateValidator).close(anyInt());
+        verify(mIncomingStateValidator).close(anyInt());
+    }
+
+    @Test
+    public void testTransportClosingGracefullyCleanup() {
+        TestExecutorService executor = new TestExecutorService(true /*wait*/);
+        TransportSipMessageValidator tracker = openTransport(executor);
+
+        ArraySet<SipDialog> dialogs = new ArraySet<>();
+        dialogs.add(SipDialog.fromSipMessage(TEST_MESSAGE));
+        doReturn(dialogs).when(mSipSessionTracker).getTrackedDialogs();
+        ArraySet<String> pendingCallIds = new ArraySet<>();
+        CountDownLatch l = new CountDownLatch(1);
+        tracker.closeSessionsGracefully((ids) -> {
+            pendingCallIds.addAll(ids);
+            l.countDown();
+        }, SipDelegateManager.MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION,
+                SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED);
+        // Before executor executes, outgoing messages will be restricted due to pending call ids.
+        assertTrue(l.getCount() >= 1);
+        assertTrue(pendingCallIds.isEmpty());
+        assertTrue(isIncomingTransportOpen(tracker));
+        verify(mOutgoingStateValidator).restrict(anyInt());
+        // Mock cleanupSession event was called for pending callId
+        dialogs.clear();
+        tracker.onSipSessionCleanup("abc");
+        assertEquals(0, l.getCount());
+        assertTrue(pendingCallIds.isEmpty());
+        verify(mOutgoingStateValidator).close(anyInt());
+        verify(mIncomingStateValidator).close(anyInt());
+    }
+
+    @Test
+    public void testTransportClosingForcefully() {
+        TestExecutorService executor = new TestExecutorService();
+        TransportSipMessageValidator tracker = openTransport(executor);
+
+        tracker.closeSessions(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED);
+
+        // All messages will be rejected.
+        verify(mOutgoingStateValidator).close(anyInt());
+        verify(mIncomingStateValidator).close(anyInt());
+    }
+
+    @Test
+    public void setRegStateChangedNoPendingCallIds() {
+        TestExecutorService executor = new TestExecutorService(true /*wait*/);
+        TransportSipMessageValidator tracker = openTransport(executor);
+
+        doReturn(Collections.emptySet()).when(mSipSessionTracker)
+                .getCallIdsAssociatedWithFeatureTag(any());
+        ArraySet<String> pendingCallIds = new ArraySet<>();
+        CountDownLatch l = new CountDownLatch(1);
+        // no feature tags are deregistering/deregistered, should return immediately
+        tracker.onRegistrationStateChanged((ids) -> {
+            pendingCallIds.addAll(ids);
+            l.countDown();
+        }, getTestRegistrationState());
+        verify(mOutgoingStateValidator, times(2)).restrictFeatureTags(Collections.emptySet());
+        assertTrue(pendingCallIds.isEmpty());
+        assertEquals(0, l.getCount());
+    }
+
+    @Test
+    public void setRegStateChangedPendingCallIdsMultipleCalls() {
+        TestExecutorService executor = new TestExecutorService(true /*wait*/);
+        TransportSipMessageValidator tracker = openTransport(executor);
+
+        ArraySet<String> callIds = new ArraySet<>(1);
+        callIds.add("abc");
+        doReturn(callIds).when(mSipSessionTracker)
+                .getCallIdsAssociatedWithFeatureTag(any());
+        ArraySet<String> pendingCallIds = new ArraySet<>();
+        CountDownLatch l = new CountDownLatch(2);
+        tracker.onRegistrationStateChanged((ids) -> {
+            pendingCallIds.addAll(ids);
+            l.countDown();
+        }, getTestRegistrationState());
+        assertEquals(2, l.getCount());
+        // If called again, the previous request will complete with no call ids
+        tracker.onRegistrationStateChanged((ids) -> {
+            pendingCallIds.addAll(ids);
+            l.countDown();
+        }, getTestRegistrationState());
+        assertEquals(1, l.getCount());
+        assertTrue(pendingCallIds.isEmpty());
+        // Simulate timeout - we should get callback with the pending call ids.
+        executor.executePending();
+        assertEquals(0, l.getCount());
+        assertEquals(callIds, pendingCallIds);
+    }
+
+    @Test
+    public void setRegStateChangedPendingCallIdsTimeout() {
+        TestExecutorService executor = new TestExecutorService(true /*wait*/);
+        TransportSipMessageValidator tracker = openTransport(executor);
+
+        ArraySet<String> callIds = new ArraySet<>(1);
+        callIds.add("abc");
+        doReturn(callIds).when(mSipSessionTracker)
+                .getCallIdsAssociatedWithFeatureTag(any());
+        ArraySet<String> pendingCallIds = new ArraySet<>();
+        CountDownLatch l = new CountDownLatch(1);
+        tracker.onRegistrationStateChanged((ids) -> {
+            pendingCallIds.addAll(ids);
+            l.countDown();
+        }, getTestRegistrationState());
+        assertEquals(1, l.getCount());
+        assertTrue(pendingCallIds.isEmpty());
+        // Simulate timeout - we should get callback with the pending call ids.
+        executor.executePending();
+        assertEquals(0, l.getCount());
+        assertEquals(callIds, pendingCallIds);
+    }
+
+    @Test
+    public void setRegStateChangedPendingCallIdsResolved() {
+        TestExecutorService executor = new TestExecutorService(true /*wait*/);
+        TransportSipMessageValidator tracker = openTransport(executor);
+
+        ArraySet<String> callIds = new ArraySet<>(1);
+        callIds.add("abc");
+        doReturn(callIds).when(mSipSessionTracker)
+                .getCallIdsAssociatedWithFeatureTag(any());
+        ArraySet<String> pendingCallIds = new ArraySet<>();
+        CountDownLatch l = new CountDownLatch(1);
+        tracker.onRegistrationStateChanged((ids) -> {
+            pendingCallIds.addAll(ids);
+            l.countDown();
+        }, getTestRegistrationState());
+        assertEquals(1, l.getCount());
+        assertTrue(pendingCallIds.isEmpty());
+        // Simulate ack pending SIP session, which has cleared pending call id
+        doReturn(Collections.emptySet()).when(mSipSessionTracker)
+                .getCallIdsAssociatedWithFeatureTag(any());
+        tracker.acknowledgePendingMessage("blah");
+        assertEquals(0, l.getCount());
+        assertEquals(callIds, pendingCallIds);
+    }
+
+    @Test
+    public void setRegStateChangedPendingCallIdsChanged() {
+        TestExecutorService executor = new TestExecutorService(true /*wait*/);
+        TransportSipMessageValidator tracker = openTransport(executor);
+
+        ArraySet<String> callIds = new ArraySet<>(1);
+        callIds.add("abc");
+        doReturn(callIds).when(mSipSessionTracker)
+                .getCallIdsAssociatedWithFeatureTag(any());
+        ArraySet<String> pendingCallIds = new ArraySet<>();
+        CountDownLatch l = new CountDownLatch(1);
+        tracker.onRegistrationStateChanged((ids) -> {
+            pendingCallIds.addAll(ids);
+            l.countDown();
+        }, getTestRegistrationState());
+        assertEquals(1, l.getCount());
+        assertTrue(pendingCallIds.isEmpty());
+        // Simulate pending callIds changed to add another session.
+        callIds.add("def");
+        executor.executePending();
+        assertEquals(0, l.getCount());
+        assertEquals(callIds, pendingCallIds);
+    }
+
+    @Test
+    public void setRegStateRegThenClose() {
+        TestExecutorService executor = new TestExecutorService(true /*wait*/);
+        TransportSipMessageValidator tracker = openTransport(executor);
+
+        ArraySet<String> callIds = new ArraySet<>(1);
+        callIds.add("abc");
+        doReturn(callIds).when(mSipSessionTracker)
+                .getCallIdsAssociatedWithFeatureTag(any());
+        ArraySet<String> pendingCallIds = new ArraySet<>();
+        CountDownLatch l = new CountDownLatch(1);
+        tracker.onRegistrationStateChanged((ids) -> {
+            pendingCallIds.addAll(ids);
+            l.countDown();
+        }, getTestRegistrationState());
+        assertEquals(1, l.getCount());
+        assertTrue(pendingCallIds.isEmpty());
+        // If close is called during pending reg state change, it should be completed with no
+        // pending call IDs (close will take care of closing everything).
+        ArraySet<SipDialog> dialogs = new ArraySet<>();
+        dialogs.add(SipDialog.fromSipMessage(TEST_MESSAGE));
+        doReturn(dialogs).when(mSipSessionTracker).getTrackedDialogs();
+        tracker.closeSessions(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD);
+        assertEquals(0, l.getCount());
+        assertEquals(Collections.emptySet(), pendingCallIds);
+    }
+
+    private SipDelegateConfiguration.Builder getConfigBuilder(int version) {
+        InetSocketAddress localAddr = new InetSocketAddress(
+                InetAddresses.parseNumericAddress("1.1.1.1"), 80);
+        InetSocketAddress serverAddr = new InetSocketAddress(
+                InetAddresses.parseNumericAddress("2.2.2.2"), 81);
+        return new SipDelegateConfiguration.Builder(version,
+                SipDelegateConfiguration.SIP_TRANSPORT_TCP, localAddr, serverAddr);
+    }
+
+    private boolean isIncomingTransportOpen(TransportSipMessageValidator tracker) {
+        return tracker.verifyIncomingMessage(TEST_MESSAGE).isValidated;
+    }
+
+    private boolean isOutgoingTransportOpen(TransportSipMessageValidator tracker) {
+        return tracker.verifyOutgoingMessage(TEST_MESSAGE, TEST_CONFIG_VERSION).isValidated;
+    }
+
+    private int verifyOutgoingTransportClosed(TransportSipMessageValidator tracker) {
+        ValidationResult result = tracker.verifyOutgoingMessage(TEST_MESSAGE, TEST_CONFIG_VERSION);
+        assertFalse(result.isValidated);
+        return result.restrictedReason;
+    }
+
+    private DelegateRegistrationState getTestRegistrationState() {
+        return new DelegateRegistrationState.Builder().build();
+    }
+
+    private TransportSipMessageValidator openTransport(ScheduledExecutorService executor) {
+        TransportSipMessageValidator tracker = getTestTracker(executor);
+        tracker.onTransportOpened(Collections.emptySet(), Collections.emptySet());
+        tracker.onConfigurationChanged(getConfigBuilder(TEST_CONFIG_VERSION).build());
+        tracker.onRegistrationStateChanged((ignore) -> {}, getTestRegistrationState());
+        // Config set + IMS reg state sent, transport is now open.
+        assertTrue(isIncomingTransportOpen(tracker));
+        assertTrue(isOutgoingTransportOpen(tracker));
+        return tracker;
+    }
+
+    private TransportSipMessageValidator getTestTracker(ScheduledExecutorService executor) {
+        doReturn(ValidationResult.SUCCESS).when(mOutgoingStateValidator).validate(any());
+        doReturn(ValidationResult.SUCCESS).when(mIncomingStateValidator).validate(any());
+        doReturn(mIncomingStateValidator).when(mIncomingStateValidator).andThen(any());
+        return new TransportSipMessageValidator(TEST_SUB_ID, executor, mSipSessionTracker,
+                mOutgoingStateValidator, mIncomingStateValidator);
+    }
+}
diff --git a/tests/src/com/android/services/telephony/rcs/UceControllerManagerTest.java b/tests/src/com/android/services/telephony/rcs/UceControllerManagerTest.java
index 82687f8..8d719fd 100644
--- a/tests/src/com/android/services/telephony/rcs/UceControllerManagerTest.java
+++ b/tests/src/com/android/services/telephony/rcs/UceControllerManagerTest.java
@@ -17,6 +17,7 @@
 package com.android.services.telephony.rcs;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.fail;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
@@ -108,6 +109,21 @@
     }
 
     @Test
+    public void testSubIdAndCarrierConfigUpdateWithInvalidSubId() throws Exception {
+        UceControllerManager uceCtrlManager = getUceControllerManager();
+
+        // Updates with the same subId should not destroy the UceController
+        uceCtrlManager.onCarrierConfigChanged();
+        verify(mUceController, never()).onDestroy();
+
+        // Updates with invalid subscription ID
+        uceCtrlManager.onAssociatedSubscriptionUpdated(-1);
+
+        verify(mUceController).onDestroy();
+        assertNull(uceCtrlManager.getUceController());
+    }
+
+    @Test
     public void testRequestCapabilitiesWithRcsUnavailable() throws Exception {
         UceControllerManager uceCtrlManager = getUceControllerManager();
         doReturn(true).when(mUceController).isUnavailable();
@@ -242,9 +258,8 @@
     }
 
     private UceControllerManager getUceControllerManager() {
-        UceControllerManager manager = new UceControllerManager(mContext, mSlotId, mSubId,
-                mExecutorService);
-        manager.setUceController(mUceController);
+        UceControllerManager manager = new UceControllerManager(mContext, mSlotId,
+                mExecutorService, mUceController);
         return manager;
     }
 }
diff --git a/tests/src/com/android/services/telephony/rcs/validator/IncomingTransportStateValidatorTest.java b/tests/src/com/android/services/telephony/rcs/validator/IncomingTransportStateValidatorTest.java
new file mode 100644
index 0000000..0e7e1be
--- /dev/null
+++ b/tests/src/com/android/services/telephony/rcs/validator/IncomingTransportStateValidatorTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2021 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.rcs.validator;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class IncomingTransportStateValidatorTest {
+    private static final SipMessage TEST_MESSAGE = new SipMessage(
+            "INVITE sip:bob@biloxi.com SIP/2.0",
+            "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds\n"
+                    + "Max-Forwards: 70\n"
+                    + "To: Bob <sip:bob@biloxi.com>\n"
+                    + "From: Alice <sip:alice@atlanta.com>;tag=1928301774\n"
+                    + "Call-ID: a84b4c76e66710@pc33.atlanta.com\n"
+                    + "CSeq: 314159 INVITE\n"
+                    + "Contact: <sip:alice@pc33.atlanta.com>\n"
+                    + "Content-Type: application/sdp\n"
+                    + "Content-Length: 142",
+            new byte[0]);
+
+    @Test
+    public void testVerifyMessageAndUpdateState() {
+        IncomingTransportStateValidator validator = new IncomingTransportStateValidator();
+        ValidationResult result = validator.validate(TEST_MESSAGE);
+        assertFalse(result.isValidated);
+        assertEquals(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED,
+                result.restrictedReason);
+
+        validator.open();
+        result = validator.validate(TEST_MESSAGE);
+        assertTrue(result.isValidated);
+
+        validator.close(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED);
+        result = validator.validate(TEST_MESSAGE);
+        assertFalse(result.isValidated);
+        assertEquals(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED,
+                result.restrictedReason);
+    }
+}
diff --git a/tests/src/com/android/services/telephony/rcs/validator/MalformedSipMessageValidatorTest.java b/tests/src/com/android/services/telephony/rcs/validator/MalformedSipMessageValidatorTest.java
new file mode 100644
index 0000000..18b37fc
--- /dev/null
+++ b/tests/src/com/android/services/telephony/rcs/validator/MalformedSipMessageValidatorTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2021 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.rcs.validator;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class MalformedSipMessageValidatorTest {
+
+    @Test
+    public void testValidRequest() {
+        SipMessage msg = new SipMessage(
+                "INVITE sip:bob@biloxi.com SIP/2.0",
+                // Typical Via
+                "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK.TeSt\n"
+                        + "Max-Forwards: 70\n"
+                        + "To: Bob <sip:bob@biloxi.com>\n"
+                        + "From: Alice <sip:alice@atlanta.com>;tag=1928301774\n"
+                        + "Call-ID: a84b4c76e66710@pc33.atlanta.com\n"
+                        + "CSeq: 314159 INVITE\n"
+                        + "Contact: <sip:alice@pc33.atlanta.com>\n"
+                        + "Content-Type: application/sdp\n"
+                        + "Content-Length: 142",
+                new byte[0]);
+        ValidationResult result = new MalformedSipMessageValidator().validate(msg);
+        assertTrue(result.isValidated);
+    }
+
+    @Test
+    public void testInvalidRequest() {
+        SipMessage msg = new SipMessage(
+                "INVITE sip:bob@biloxi.comSIP/2.0",
+                "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds\n"
+                        + "Max-Forwards: 70\n"
+                        + "To: Bob <sip:bob@biloxi.com>\n"
+                        + "From: Alice <sip:alice@atlanta.com>;tag=1928301774\n"
+                        + "Call-ID: a84b4c76e66710@pc33.atlanta.com\n"
+                        + "CSeq: 314159 INVITE\n"
+                        + "Contact: <sip:alice@pc33.atlanta.com>\n"
+                        + "Content-Type: application/sdp\n"
+                        + "Content-Length: 142",
+                new byte[0]);
+        ValidationResult result = new MalformedSipMessageValidator().validate(msg);
+        assertFalse(result.isValidated);
+        assertEquals(SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_START_LINE,
+                result.restrictedReason);
+    }
+
+    @Test
+    public void testInvalidResponse() {
+        SipMessage msg = new SipMessage(
+                "SIP/2.0 200OK",
+                "Via: SIP/2.0/TCP terminal.vancouver.example.com;"
+                        + "branch=z9hG4bKwYb6QREiCL\n"
+                        + "To: <sip:adam-buddies@pres.vancouver.example.com>;tag=zpNctbZq\n"
+                        + "From: <sip:adam@vancouver.example.com>;tag=ie4hbb8t\n"
+                        + "Call-ID: cdB34qLToC@terminal.vancouver.example.com\n"
+                        + "CSeq: 322723822 SUBSCRIBE\n"
+                        + "Contact: <sip:pres.vancouver.example.com>\n"
+                        + "Expires: 7200\n"
+                        + "Require: eventlist\n"
+                        + "Content-Length: 0",
+                new byte[0]);
+        ValidationResult result = new MalformedSipMessageValidator().validate(msg);
+        assertFalse(result.isValidated);
+        assertEquals(SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_START_LINE,
+                result.restrictedReason);
+    }
+}
diff --git a/tests/src/com/android/services/telephony/rcs/validator/OutgoingTransportStateValidatorTest.java b/tests/src/com/android/services/telephony/rcs/validator/OutgoingTransportStateValidatorTest.java
new file mode 100644
index 0000000..8dbeb9b
--- /dev/null
+++ b/tests/src/com/android/services/telephony/rcs/validator/OutgoingTransportStateValidatorTest.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2021 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.rcs.validator;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.doReturn;
+
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+import android.util.ArraySet;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.TelephonyTestBase;
+import com.android.services.telephony.rcs.SipDialog;
+import com.android.services.telephony.rcs.SipSessionTracker;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+import java.util.Collections;
+import java.util.Random;
+
+@RunWith(AndroidJUnit4.class)
+public class OutgoingTransportStateValidatorTest  extends TelephonyTestBase {
+
+    @Mock
+    private SipSessionTracker mMockSessionTracker;
+    private final Random mRandom = new Random();
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    @Test
+    public void testVerifyMessageInOpenCloseState() {
+        SipMessage testMessage = generateSipRequestForCallId("callId1");
+        OutgoingTransportStateValidator validator =
+                new OutgoingTransportStateValidator(mMockSessionTracker);
+        ValidationResult result = validator.validate(testMessage);
+        assertFalse(result.isValidated);
+        assertEquals(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED,
+                result.restrictedReason);
+
+        validator.open(Collections.singleton("+tag"), Collections.emptySet());
+        validator.restrictFeatureTags(Collections.emptySet());
+        result = validator.validate(testMessage);
+        assertTrue(result.isValidated);
+
+        validator.close(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED);
+        result = validator.validate(testMessage);
+        assertFalse(result.isValidated);
+        assertEquals(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED,
+                result.restrictedReason);
+    }
+
+    @Test
+    public void testVerifyMessageRestricted() {
+        String callId1 = "callId1";
+        String callId2 = "callId2";
+        String callId3 = "callId3";
+        SipMessage testInDialogEarlyMessage = generateSipRequestForCallId(callId1);
+        SipMessage testInDialogConfirmedMessage = generateSipRequestForCallId(callId2);
+        SipMessage testOutOfDialogInvite = generateSipRequestForCallId(callId3);
+        SipMessage testStatelessRequest = generateMessageRequest();
+        ArraySet<SipDialog> inDialogEarlyCallIds = new ArraySet<>(1);
+        inDialogEarlyCallIds.add(SipDialog.fromSipMessage(testInDialogEarlyMessage));
+        ArraySet<String> inDialogConfirmedCallIds = new ArraySet<>();
+        inDialogEarlyCallIds.add(SipDialog.fromSipMessage(testInDialogConfirmedMessage));
+        // For the sake of testing, add the same call id to early and confirmed dialogs, since we
+        // will accept requests for both right now.
+        doReturn(inDialogEarlyCallIds).when(mMockSessionTracker).getEarlyDialogs();
+        doReturn(inDialogConfirmedCallIds).when(mMockSessionTracker).getConfirmedDialogs();
+        OutgoingTransportStateValidator validator =
+                new OutgoingTransportStateValidator(mMockSessionTracker);
+        validator.restrict(
+                SipDelegateManager.MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION);
+
+        // ensure a response to a pending request is not restricted, even if it is not for a tracked
+        // call ID.
+        ValidationResult result = validator.validate(generate200OkResponse("callId4"));
+        assertTrue(result.isValidated);
+
+        // confirm in dialog messages are not restricted
+        result = validator.validate(testInDialogEarlyMessage);
+        assertTrue(result.isValidated);
+        result = validator.validate(testInDialogConfirmedMessage);
+        assertTrue(result.isValidated);
+
+        // confirm out-of-dialog requests are restricted.
+        result = validator.validate(testOutOfDialogInvite);
+        assertFalse(result.isValidated);
+        assertEquals(SipDelegateManager.MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION,
+                result.restrictedReason);
+        result = validator.validate(testStatelessRequest);
+        assertFalse(result.isValidated);
+        assertEquals(SipDelegateManager.MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION,
+                result.restrictedReason);
+    }
+
+    @Test
+    public void testDeniedFeatureTag() {
+        SipMessage testMessage = generateSipRequestForCallId("callId1");
+        OutgoingTransportStateValidator validator =
+                new OutgoingTransportStateValidator(mMockSessionTracker);
+        ValidationResult result = validator.validate(testMessage);
+        assertFalse(result.isValidated);
+        assertEquals(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED,
+                result.restrictedReason);
+
+        // Assert that invites associated with denied tags are denied.
+        validator.open(Collections.emptySet(), Collections.singleton("+tag"));
+        validator.restrictFeatureTags(Collections.emptySet());
+        result = validator.validate(testMessage);
+        assertFalse(result.isValidated);
+        assertEquals(SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG,
+                result.restrictedReason);
+    }
+
+    @Test
+    public void testRestrictedFeatureTag() {
+        SipMessage testMessage = generateSipRequestForCallId("callId1");
+        OutgoingTransportStateValidator validator =
+                new OutgoingTransportStateValidator(mMockSessionTracker);
+        ValidationResult result = validator.validate(testMessage);
+        assertFalse(result.isValidated);
+        assertEquals(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED,
+                result.restrictedReason);
+
+        validator.open(Collections.singleton("+tag"), Collections.emptySet());
+        // Ensure that when supported tags are restricted, the message is not validated.
+        validator.restrictFeatureTags(Collections.singleton("+tag"));
+        result = validator.validate(testMessage);
+        assertFalse(result.isValidated);
+        assertEquals(SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG,
+                result.restrictedReason);
+    }
+
+    @Test
+    public void testNoSupportedFeatureTag() {
+        SipMessage testMessage = generateSipRequestForCallId("callId1");
+        OutgoingTransportStateValidator validator =
+                new OutgoingTransportStateValidator(mMockSessionTracker);
+        ValidationResult result = validator.validate(testMessage);
+        assertFalse(result.isValidated);
+        assertEquals(SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED,
+                result.restrictedReason);
+
+        // Assert if a message doesn't have any related supported tags, it should be denied
+        validator.open(Collections.emptySet(), Collections.emptySet());
+        validator.restrictFeatureTags(Collections.emptySet());
+        result = validator.validate(testMessage);
+        assertFalse(result.isValidated);
+        assertEquals(SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG,
+                result.restrictedReason);
+
+        // responses and non-dialog starting messages do not matter
+        result = validator.validate(generate200OkResponse("callId2"));
+        assertTrue(result.isValidated);
+        result = validator.validate(generateMessageRequest());
+        assertTrue(result.isValidated);
+    }
+
+    /**
+     * @return A INVITE with the call ID specified. Note: this request is not technically valid, but
+     * only contains the relevant headers for testing.
+     */
+    private SipMessage generateSipRequestForCallId(String callId) {
+        return new SipMessage(
+                "INVITE sip:b@client.example.com SIP/2.0",
+                "Via: SIP/2.0/UDP client.example.com;branch=z9hG4bK776asdhds\n"
+                        + "To: B <sip:b@example.com>\n"
+                        + "From: A <sip:a@example.com>;tag=1928301774\n"
+                        + "Accept-Contact: *;+tag\n"
+                        + "Call-ID: " + callId,
+                new byte[0]);
+    }
+
+    /**
+     * @return A MESSAGE request. Note: this request is not technically valid, but only contains the
+     * relevant headers for testing.
+     */
+    private SipMessage generateMessageRequest() {
+        return new SipMessage(
+                "MESSAGE sip:b@client.example.com SIP/2.0",
+                "Via: SIP/2.0/UDP client.example.com;branch=z9hG4bK776asdhds\n"
+                        + "To: B <sip:b@example.com>\n"
+                        + "From: A <sip:a@example.com>;tag=1928301774\n",
+                new byte[0]);
+    }
+
+    /**
+     * @return A 200 OK associated with the supplied call ID.
+     */
+    private SipMessage generate200OkResponse(String callId) {
+        return new SipMessage(
+                "SIP/2.0 200 OK",
+                "Via: SIP/2.0/UDP client.example.com;branch=z9hG4bK776asdhds\n"
+                        + "To: B <sip:b@example.com>\n"
+                        + "From: A <sip:a@example.com>;tag=1928301774\n"
+                        + "Call-ID: " + callId,
+                new byte[0]);
+    }
+}
diff --git a/tests/src/com/android/services/telephony/rcs/validator/RestrictedOutgoingSipRequestValidatorTest.java b/tests/src/com/android/services/telephony/rcs/validator/RestrictedOutgoingSipRequestValidatorTest.java
new file mode 100644
index 0000000..a90aaeb
--- /dev/null
+++ b/tests/src/com/android/services/telephony/rcs/validator/RestrictedOutgoingSipRequestValidatorTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2021 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.rcs.validator;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class RestrictedOutgoingSipRequestValidatorTest {
+
+    @Test
+    public void testRegisterNotAllowed() {
+        SipMessage msg = new SipMessage(
+                "REGISTER sip:bob@biloxi.com SIP/2.0",
+                // Not representative of real REGISTER message, but close enough for validation.
+                "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds\n"
+                        + "Max-Forwards: 70\n"
+                        + "To: Bob <sip:bob@biloxi.com>\n"
+                        + "From: Alice <sip:alice@atlanta.com>;tag=1928301774\n"
+                        + "CSeq: 314159 REGISTER\n"
+                        + "Contact: <sip:alice@pc33.atlanta.com>\n",
+                new byte[0]);
+        ValidationResult result = new RestrictedOutgoingSipRequestValidator().validate(msg);
+        assertFalse(result.isValidated);
+        assertEquals(SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_START_LINE,
+                result.restrictedReason);
+    }
+
+    @Test
+    public void testPublishNotAllowed() {
+        SipMessage msg = new SipMessage(
+                "PUBLISH sip:bob@biloxi.com SIP/2.0",
+                // Not representative of real REGISTER message, but close enough for validation.
+                "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds\n"
+                        + "Max-Forwards: 70\n"
+                        + "To: Bob <sip:bob@biloxi.com>\n"
+                        + "From: Alice <sip:alice@atlanta.com>;tag=1928301774\n"
+                        + "CSeq: 314159 PUBLISH\n"
+                        + "Contact: <sip:alice@pc33.atlanta.com>\n",
+                new byte[0]);
+        ValidationResult result = new RestrictedOutgoingSipRequestValidator().validate(msg);
+        assertFalse(result.isValidated);
+        assertEquals(SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_START_LINE,
+                result.restrictedReason);
+
+    }
+
+    @Test
+    public void testOptionsNotAllowed() {
+        SipMessage msg = new SipMessage(
+                "OPTIONS sip:bob@biloxi.com SIP/2.0",
+                // Not representative of real REGISTER message, but close enough for validation.
+                "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds\n"
+                        + "Max-Forwards: 70\n"
+                        + "To: Bob <sip:bob@biloxi.com>\n"
+                        + "From: Alice <sip:alice@atlanta.com>;tag=1928301774\n"
+                        + "CSeq: 314159 OPTIONS\n"
+                        + "Contact: <sip:alice@pc33.atlanta.com>\n",
+                new byte[0]);
+        ValidationResult result = new RestrictedOutgoingSipRequestValidator().validate(msg);
+        assertFalse(result.isValidated);
+        assertEquals(SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_START_LINE,
+                result.restrictedReason);
+
+    }
+
+    @Test
+    public void testInviteAllowed() {
+        SipMessage msg = new SipMessage(
+                "INVITE sip:bob@biloxi.com SIP/2.0",
+                "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds\n"
+                        + "Max-Forwards: 70\n"
+                        + "To: Bob <sip:bob@biloxi.com>\n"
+                        + "From: Alice <sip:alice@atlanta.com>;tag=1928301774\n"
+                        + "Call-ID: a84b4c76e66710@pc33.atlanta.com\n"
+                        + "CSeq: 314159 INVITE\n"
+                        + "Contact: <sip:alice@pc33.atlanta.com>\n"
+                        + "Content-Type: application/sdp\n"
+                        + "Content-Length: 142",
+                new byte[0]);
+        ValidationResult result = new RestrictedOutgoingSipRequestValidator().validate(msg);
+        assertTrue(result.isValidated);
+    }
+
+    @Test
+    public void testResponseAllowed() {
+        SipMessage msg = new SipMessage(
+                "SIP/2.0 200 OK",
+                "Via: SIP/2.0/TCP terminal.vancouver.example.com;"
+                        + "branch=z9hG4bKwYb6QREiCL\n"
+                        + "To: <sip:adam-buddies@pres.vancouver.example.com>;tag=zpNctbZq\n"
+                        + "From: <sip:adam@vancouver.example.com>;tag=ie4hbb8t\n"
+                        + "Call-ID: cdB34qLToC@terminal.vancouver.example.com\n"
+                        + "CSeq: 322723822 SUBSCRIBE\n"
+                        + "Contact: <sip:pres.vancouver.example.com>\n"
+                        + "Expires: 7200\n"
+                        + "Require: eventlist\n"
+                        + "Content-Length: 0",
+                new byte[0]);
+        ValidationResult result = new RestrictedOutgoingSipRequestValidator().validate(msg);
+        assertTrue(result.isValidated);
+    }
+}
diff --git a/tests/src/com/android/services/telephony/rcs/validator/RestrictedOutgoingSubscribeValidatorTest.java b/tests/src/com/android/services/telephony/rcs/validator/RestrictedOutgoingSubscribeValidatorTest.java
new file mode 100644
index 0000000..9864872
--- /dev/null
+++ b/tests/src/com/android/services/telephony/rcs/validator/RestrictedOutgoingSubscribeValidatorTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2021 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.rcs.validator;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class RestrictedOutgoingSubscribeValidatorTest {
+
+    @Test
+    public void testValidUnrelatedRequest() {
+        SipMessage msg = new SipMessage(
+                "INVITE sip:bob@biloxi.com SIP/2.0",
+                // Typical Via
+                "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK.TeSt\n"
+                        + "Max-Forwards: 70\n"
+                        + "To: Bob <sip:bob@biloxi.com>\n"
+                        + "From: Alice <sip:alice@atlanta.com>;tag=1928301774\n"
+                        + "Call-ID: a84b4c76e66710@pc33.atlanta.com\n"
+                        + "CSeq: 314159 INVITE\n"
+                        + "Contact: <sip:alice@pc33.atlanta.com>\n"
+                        + "Content-Type: application/sdp\n"
+                        + "Content-Length: 142",
+                new byte[0]);
+        ValidationResult result = new MalformedSipMessageValidator().validate(msg);
+        assertTrue(result.isValidated);
+    }
+
+    @Test
+    public void testValidUnrelatedResponse() {
+        SipMessage msg = new SipMessage(
+                "SIP/2.0 200 OK",
+                "Via: SIP/2.0/TCP terminal.vancouver.example.com;"
+                        + "branch=z9hG4bKwYb6QREiCL\n"
+                        + "To: <sip:adam-buddies@pres.vancouver.example.com>;tag=zpNctbZq\n"
+                        + "From: <sip:adam@vancouver.example.com>;tag=ie4hbb8t\n"
+                        + "Call-ID: cdB34qLToC@terminal.vancouver.example.com\n"
+                        + "CSeq: 322723822 SUBSCRIBE\n"
+                        + "Contact: <sip:pres.vancouver.example.com>\n"
+                        + "Expires: 7200\n"
+                        + "Require: eventlist\n"
+                        + "Content-Length: 0",
+                new byte[0]);
+        ValidationResult result = new MalformedSipMessageValidator().validate(msg);
+        assertTrue(result.isValidated);
+    }
+
+    @Test
+    public void testValidSubscribeRequest() {
+        SipMessage msg = new SipMessage(
+                "SUBSCRIBE sip:joe@example.com SIP/2.0",
+                "Via: SIP/2.0/UDP app.example.com;branch=z9hG4bKnashds7\n"
+                        + "From: sip:app.example.com;tag=123aa9\n"
+                        + "To: sip:joe@example.com\n"
+                        + "Call-ID: 9987@app.example.com\n"
+                        + "CSeq: 9887 SUBSCRIBE\n"
+                        + "Contact: sip:app.example.com\n"
+                        + "Event:    conference \n"
+                        + "Max-Forwards: 70\n",
+                new byte[0]);
+        ValidationResult result = new RestrictedOutgoingSubscribeValidator().validate(msg);
+        assertTrue(result.isValidated);
+    }
+
+    @Test
+    public void testInvalidSubscribeRequest() {
+        SipMessage msg = new SipMessage(
+                "SUBSCRIBE sip:joe@example.com SIP/2.0",
+                "Via: SIP/2.0/UDP app.example.com;branch=z9hG4bKnashds7\n"
+                        + "From: sip:app.example.com;tag=123aa9\n"
+                        + "To: sip:joe@example.com\n"
+                        + "Call-ID: 9987@app.example.com\n"
+                        + "CSeq: 9887 SUBSCRIBE\n"
+                        + "Contact: sip:app.example.com\n"
+                        + "Event:  presence  \n"
+                        + "Max-Forwards: 70\n",
+                new byte[0]);
+        ValidationResult result = new RestrictedOutgoingSubscribeValidator().validate(msg);
+        assertFalse(result.isValidated);
+        assertEquals(SipDelegateManager.MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS,
+                result.restrictedReason);
+
+    }
+}