Merge "Add log when turn off radio"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 32733cc..22d007e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -573,6 +573,14 @@
             android:configChanges="orientation|screenSize|keyboardHidden"
             android:theme="@style/Theme.Transparent"/>
 
+        <activity
+            android:name="com.android.phone.ErrorDialogActivity"
+            android:exported="false"
+            android:excludeFromRecents="true"
+            android:launchMode="singleTop"
+            android:configChanges="orientation|screenSize|keyboardHidden"
+            android:theme="@style/Theme.Telephony.Transparent"/>
+
         <service
             android:name="com.android.phone.vvm.RemoteVvmTaskManager"
             android:exported="false"/>
diff --git a/assets/CarrierRestrictionOperatorDetails.json b/assets/CarrierRestrictionOperatorDetails.json
new file mode 100644
index 0000000..166cc39
--- /dev/null
+++ b/assets/CarrierRestrictionOperatorDetails.json
@@ -0,0 +1,4 @@
+{
+  "_comment": "Operator should register with its application package name, carrierId and all the corresponding  SHAIDs",
+  "_comment": "Example format :: << \"packageName\" : {\"carrierId\":<int>, \"callerSHA1Id\":[<SHAID1>, <SHAID2>]} >>"
+}
\ No newline at end of file
diff --git a/ecc/input/eccdata.txt b/ecc/input/eccdata.txt
index e1c7306..6988f14 100644
--- a/ecc/input/eccdata.txt
+++ b/ecc/input/eccdata.txt
@@ -129,10 +129,35 @@
 countries {
   iso_code: "AT"
   eccs {
-    phone_number: "112"
-    types: POLICE
-    types: AMBULANCE
-    types: FIRE
+      phone_number: "112"
+      types: POLICE
+      types: AMBULANCE
+      types: FIRE
+  }
+  eccs {
+      phone_number: "122"
+      types: FIRE
+      routing: NORMAL
+  }
+  eccs {
+      phone_number: "133"
+      types: POLICE
+      routing: NORMAL
+  }
+  eccs {
+      phone_number: "144"
+      types: AMBULANCE
+      routing: NORMAL
+  }
+  eccs {
+      phone_number: "128"
+      types: MOUNTAIN_RESCUE
+      routing: NORMAL
+  }
+  eccs {
+      phone_number: "140"
+      types: TYPE_UNSPECIFIED
+      routing: NORMAL
   }
   ecc_fallback: "112"
 }
@@ -333,14 +358,22 @@
   eccs {
     phone_number: "190"
     types: POLICE
+    routing: EMERGENCY
   }
   eccs {
     phone_number: "192"
     types: AMBULANCE
+    routing: NORMAL
   }
   eccs {
     phone_number: "193"
     types: FIRE
+    routing: NORMAL
+  }
+  eccs {
+    phone_number: "185"
+    types: MARINE_GUARD
+    routing: NORMAL
   }
   ecc_fallback: "911"
 }
@@ -420,6 +453,12 @@
     types: AMBULANCE
     types: FIRE
   }
+  eccs {
+      phone_number: "112"
+      types: POLICE
+      types: AMBULANCE
+      types: FIRE
+   }
   ecc_fallback: "911"
 }
 countries {
@@ -451,16 +490,57 @@
 countries {
   iso_code: "CH"
   eccs {
+      phone_number: "112"
+      types: POLICE
+      types: AMBULANCE
+      types: FIRE
+      routing: EMERGENCY
+  }
+  eccs {
+        phone_number: "911"
+        types: POLICE
+        types: AMBULANCE
+        types: FIRE
+        routing: EMERGENCY
+    }
+  eccs {
     phone_number: "117"
     types: POLICE
+    routing: EMERGENCY
   }
   eccs {
     phone_number: "144"
     types: AMBULANCE
+    routing: EMERGENCY
   }
   eccs {
     phone_number: "118"
     types: FIRE
+    routing: EMERGENCY
+  }
+  eccs {
+      phone_number: "143"
+      types: TYPE_UNSPECIFIED
+      routing: NORMAL
+  }
+  eccs {
+      phone_number: "145"
+      types: TYPE_UNSPECIFIED
+      routing: NORMAL
+  }
+   eccs {
+      phone_number: "147"
+      types: TYPE_UNSPECIFIED
+      routing: NORMAL
+  }
+   eccs {
+      phone_number: "1414"
+      types: TYPE_UNSPECIFIED
+  }
+   eccs {
+      phone_number: "0800117117"
+      types: TYPE_UNSPECIFIED
+      routing: NORMAL
   }
   ecc_fallback: "112"
 }
@@ -735,6 +815,47 @@
     types: POLICE
     types: AMBULANCE
     types: FIRE
+    routing: EMERGENCY
+  }
+  eccs {
+      phone_number: "088"
+      types: POLICE
+      routing: EMERGENCY
+  }
+  eccs {
+      phone_number: "085"
+      types: FIRE
+      routing: EMERGENCY
+  }
+  eccs {
+      phone_number: "1006"
+      types: TYPE_UNSPECIFIED
+      routing: EMERGENCY
+  }
+  eccs {
+      phone_number: "061"
+      types: TYPE_UNSPECIFIED
+      routing: EMERGENCY
+  }
+  eccs {
+      phone_number: "062"
+      types: TYPE_UNSPECIFIED
+      routing: EMERGENCY
+  }
+  eccs {
+      phone_number: "080"
+      types: FIRE
+      routing: EMERGENCY
+  }
+  eccs {
+       phone_number: "091"
+       types: POLICE
+       routing: EMERGENCY
+  }
+  eccs {
+       phone_number: "092"
+       types: POLICE
+       routing: EMERGENCY
   }
   ecc_fallback: "112"
 }
@@ -889,6 +1010,7 @@
     types: POLICE
     types: AMBULANCE
     types: FIRE
+    routing: EMERGENCY
   }
   ecc_fallback: "112"
 }
@@ -2298,7 +2420,38 @@
     types: POLICE
     types: AMBULANCE
     types: FIRE
+    routing: EMERGENCY
   }
+  eccs {
+    phone_number: "101"
+    types: FIRE
+    routing: EMERGENCY
+  }
+  eccs {
+    phone_number: "102"
+    types: POLICE
+    routing: EMERGENCY
+  }
+  eccs {
+    phone_number: "103"
+    types: AMBULANCE
+    routing: EMERGENCY
+  }
+  eccs {
+    phone_number: "104"
+    types: TYPE_UNSPECIFIED
+    routing: EMERGENCY
+  }
+  eccs {
+    phone_number: "121"
+    types: TYPE_UNSPECIFIED
+    routing: EMERGENCY
+  }
+  eccs {
+    phone_number: "123"
+    types: TYPE_UNSPECIFIED
+    routing: EMERGENCY
+    }
   ecc_fallback: "112"
 }
 countries {
diff --git a/ecc/output/eccdata b/ecc/output/eccdata
index 8ab89d6..8b4f49b 100644
--- a/ecc/output/eccdata
+++ b/ecc/output/eccdata
Binary files differ
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index db93b63..a755490 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -575,7 +575,7 @@
     <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="onscreenHoldText" msgid="4025348842151665191">"انتظار"</string>
     <string name="onscreenEndCallText" msgid="6138725377654842757">"الانتهاء"</string>
     <string name="onscreenShowDialpadText" msgid="658465753816164079">"لوحة الاتصال"</string>
     <string name="onscreenMuteText" msgid="5470306116733843621">"كتم الصوت"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index b5e18fb..af2c4d8 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -575,7 +575,7 @@
     <string name="fire_type_description" msgid="6565200468934914930">"Bomberos"</string>
     <string name="description_concat_format" msgid="2014471565101724088">"%1$s, %2$s"</string>
     <string name="dialerKeyboardHintText" msgid="1115266533703764049">"Utilizar teclado para marcar"</string>
-    <string name="onscreenHoldText" msgid="4025348842151665191">"Retener"</string>
+    <string name="onscreenHoldText" msgid="4025348842151665191">"Pausar"</string>
     <string name="onscreenEndCallText" msgid="6138725377654842757">"Finalizar"</string>
     <string name="onscreenShowDialpadText" msgid="658465753816164079">"Teclado"</string>
     <string name="onscreenMuteText" msgid="5470306116733843621">"Silenciar"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index cbe88e0..b205fc8 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -615,7 +615,7 @@
     <string name="ota_title_activate" msgid="4049645324841263423">"Aktibatu telefonoa"</string>
     <string name="ota_touch_activate" msgid="838764494319694754">"Telefono-zerbitzua aktibatzeko, dei berezi bat egin behar da.\n\n\"Aktibatu\" sakatu ondoren, telefonoa aktibatzeko, entzun ematen zaizkizun argibideak."</string>
     <string name="ota_hfa_activation_title" msgid="3300556778212729671">"Aktibatzen…"</string>
-    <string name="ota_hfa_activation_dialog_message" msgid="7921718445773342996">"Telefonoa datu-konexioaren zerbitzua aktibatzen ari da.\n\nEragiketa 5 minutura arte luza daiteke."</string>
+    <string name="ota_hfa_activation_dialog_message" msgid="7921718445773342996">"Telefonoa mugikorretarako datu-zerbitzua aktibatzen ari da.\n\nEragiketa gehienez 5 minutu luza daiteke."</string>
     <string name="ota_skip_activation_dialog_title" msgid="7666611236789203797">"Aktibazioa saltatu nahi duzu?"</string>
     <string name="ota_skip_activation_dialog_message" msgid="6691722887019708713">"Aktibazioa saltatzen baduzu, ezingo duzu deirik egin, ez eta datu-konexioaren sareetara konektatu ere, baina Wi-Fi sareetara konektatu ahal izango duzu. Telefonoa aktibatzen duzun arte, pizten duzun bakoitzean eskatuko zaizu aktibatzeko."</string>
     <string name="ota_skip_activation_dialog_skip_label" msgid="5908029466817825633">"Saltatu"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 9443c12..f3f9884 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -47,7 +47,7 @@
     <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="voice_number_setting_primary_user_only" msgid="3394706575741912843">"Үн почта жөндөөлөрүн алгачкы колдонуучу гана өзгөртө алат."</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_phoneid" msgid="8775611434123577808">"SIM-карта оператор үчүн кулпуланган"</string>
@@ -56,23 +56,23 @@
     <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>
-    <string name="labelGSMMore" msgid="7354182269461281543">"GSM чалуунун жөндөөлөрү"</string>
-    <string name="labelGsmMore_with_label" msgid="3206015314393246224">"GSM чалуунун жөндөөлөрү (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
-    <string name="labelCDMAMore" msgid="7937441382611224632">"CDMA чалуунун жөндөөлөрү"</string>
-    <string name="labelCdmaMore_with_label" msgid="7759692829160238152">"CDMA чалуунун жөндөөлөрү (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+    <string name="mobile_network_settings_not_available" msgid="8678168497517090039">"Бул колдонуучу мобилдик тармак параметрлерин колдоно албайт"</string>
+    <string name="labelGSMMore" msgid="7354182269461281543">"GSM чалуунун параметрлери"</string>
+    <string name="labelGsmMore_with_label" msgid="3206015314393246224">"GSM чалуунун параметрлери (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+    <string name="labelCDMAMore" msgid="7937441382611224632">"CDMA чалуунун параметрлери"</string>
+    <string name="labelCdmaMore_with_label" msgid="7759692829160238152">"CDMA чалуунун параметрлери (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
     <string name="apn_settings" msgid="1978652203074756623">"Туташуу түйүндөрү (APN)"</string>
-    <string name="settings_label" msgid="9101778088412567956">"Тармак жөндөөлөрү"</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_default_account_label" msgid="5107598881335931101">"Тармак жок"</string>
-    <string name="phone_accounts_settings_header" msgid="6296501692964706536">"Жөндөөлөр"</string>
+    <string name="phone_accounts_settings_header" msgid="6296501692964706536">"Параметрлер"</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_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="wifi_calling" msgid="3650509202851355742">"Wi-Fi чалуу"</string>
@@ -85,18 +85,18 @@
     <string name="smart_forwarding_settings_menu_summary" msgid="5096947726032885325">"Бир номер жеткиликсиз болсо, чалууларды ар дайым башка номериңизге багыттоо"</string>
     <string name="voicemail_notifications_preference_title" msgid="7829238858063382977">"Билдирмелер"</string>
     <string name="cell_broadcast_settings" msgid="8135324242541809924">"Өзгөчө кырдаал тууралуу кулактандыруу"</string>
-    <string name="call_settings" msgid="3677282690157603818">"Чалуу жөндөөлөрү"</string>
+    <string name="call_settings" msgid="3677282690157603818">"Чалуу параметрлери"</string>
     <string name="additional_gsm_call_settings" msgid="1561980168685658846">"Кошумча жөндөөлөр"</string>
     <string name="additional_gsm_call_settings_with_label" msgid="7973920539979524908">"Кошумча жөндөөлөр (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
-    <string name="sum_gsm_call_settings" msgid="7964692601608878138">"GSM менен гана чалуунун кошумча жөндөөлөрү"</string>
-    <string name="additional_cdma_call_settings" msgid="2178016561980611304">"Кошумча CDMA чалуунун жөндөөлөрү"</string>
-    <string name="sum_cdma_call_settings" msgid="3185825305136993636">"CDMA менен гана чалуунун кошумча жөндөөлөрү"</string>
-    <string name="labelNwService" msgid="6015891883487125120">"Тармак кызматынын жөндөөлөрү"</string>
+    <string name="sum_gsm_call_settings" msgid="7964692601608878138">"GSM менен гана чалуунун кошумча параметрлери"</string>
+    <string name="additional_cdma_call_settings" msgid="2178016561980611304">"Кошумча CDMA чалуунун параметрлери"</string>
+    <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>
+    <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>
@@ -131,13 +131,13 @@
     <string name="disable_cdma_cw" msgid="7119290446496301734">"Баш тартуу"</string>
     <string name="cdma_call_waiting_in_ims_on" msgid="6390979414188659218">"IMS платформасында CDMA чалуу күтүүcү күйгүзүлгөн"</string>
     <string name="cdma_call_waiting_in_ims_off" msgid="1099246114368636334">"IMS платформасында CDMA чалуу күтүүcү өчүрүлгөн"</string>
-    <string name="updating_title" msgid="6130548922615719689">"Чалуу жөндөөлөрү"</string>
-    <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="updating_title" msgid="6130548922615719689">"Чалуу параметрлери"</string>
+    <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>
@@ -328,7 +328,7 @@
     <string name="enable_disable_cell_bc_sms" msgid="4759958924031721350">"Уюлдук жөнөтүү SMS\'и"</string>
     <string name="cell_bc_sms_enable" msgid="2019708772024632073">"Уюлдук жөнөтүү SMS\'и иштетилген"</string>
     <string name="cell_bc_sms_disable" msgid="1214238639910875347">"Уюлдук жөнөтүү SMS\'и өчүрүлгөн"</string>
-    <string name="cb_sms_settings" msgid="6858093721831312036">"Уюлдук жөнөтүүлөрдүн SMS жөндөөлөрү"</string>
+    <string name="cb_sms_settings" msgid="6858093721831312036">"Уюлдук жөнөтүүлөрдүн SMS параметрлери"</string>
     <string name="enable_disable_emergency_broadcast" msgid="6325655044472196496">"Өзгөчө кырдаалдагы жөнөтүүлөр"</string>
     <string name="emergency_broadcast_enable" msgid="5759610647771102442">"Өзгөчө кырдаалдагы жөнөтүүлөр иштетилген"</string>
     <string name="emergency_broadcast_disable" msgid="2844904734469323266">"Өзгөчө кырдаалдагы жөнөтүүлөр өчүрүлгөн"</string>
@@ -650,7 +650,7 @@
     <string name="voicemail_provider" msgid="4158806657253745294">"Кызмат"</string>
     <string name="voicemail_settings" msgid="4451045613238972776">"Жөндөө"</string>
     <string name="voicemail_number_not_set" msgid="8831561283386938155">"&lt;Коюлган эмес&gt;"</string>
-    <string name="other_settings" msgid="8895088007393598447">"Башка чалуу жөндөөлөрү"</string>
+    <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>
@@ -665,8 +665,8 @@
     <string name="preference_category_ringtone" msgid="8787281191375434976">"Рингтон жана Титирөө"</string>
     <string name="pstn_connection_service_label" msgid="9200102709997537069">"Кыналган SIM карталар"</string>
     <string name="enable_video_calling_title" msgid="7246600931634161830">"Видео чалууну күйгүзүү"</string>
-    <string name="enable_video_calling_dialog_msg" msgid="7141478720386203540">"Видео чалууну күйгүзүү үчүн тармак жөндөөлөрүнөн Жакшыртылган 4G LTE режимин иштетишиңиз керек."</string>
-    <string name="enable_video_calling_dialog_settings" msgid="8697890611305307110">"Тармак жөндөөлөрү"</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="sim_label_emergency_calls" msgid="9078241989421522310">"Шашылыш чалуулар"</string>
     <string name="sim_description_emergency_calls" msgid="5146872803938897296">"Шашылыш чалуу гана"</string>
@@ -781,7 +781,7 @@
     <string name="call_barring_baicr_enabled" msgid="64774270234828175">"Роумингдеги эл аралык кирүүчү чалууларды бөгөттөө функциясы өчүрүлсүнбү?"</string>
     <string name="call_barring_baicr_disabled" msgid="3488129262744027262">"Роумингдеги эл аралык кирүүчү чалуу бөгөттөлсүнбү?"</string>
     <string name="call_barring_deactivate_all" msgid="7837931580047157328">"Баары өчүрүлсүн"</string>
-    <string name="call_barring_deactivate_all_description" msgid="4474119585042121604">"Чалууларга тыюу салуу функциясынын жөндөөлөрүн өчүрүү"</string>
+    <string name="call_barring_deactivate_all_description" msgid="4474119585042121604">"Чалууларга тыюу салуу функциясынын параметрлерин өчүрүү"</string>
     <string name="call_barring_deactivate_success" msgid="3545644320298275337">"Чалууларга тыюу салуу функциясы өчүрүлдү"</string>
     <string name="call_barring_change_pwd" msgid="1730691950940338387">"Сызсөздү өзгөртүү"</string>
     <string name="call_barring_change_pwd_description" msgid="1274245130382054227">"Чалууларга тыюу салуу функциясынын сырсөзүн өзгөртүү"</string>
@@ -793,7 +793,7 @@
     <string name="call_barring_new_pwd" msgid="2515524903813227732">"Жаңы сырсөз"</string>
     <string name="call_barring_confirm_pwd" msgid="7552526161616461858">"Сырсөздү ырастоо"</string>
     <string name="messageCallBarring" msgid="5537730400652466912">"Сырсөздү киргизиңиз"</string>
-    <string name="call_barring_settings" msgid="4616607285790258919">"Чалууларга тыюу салуу функциясынын жөндөөлөрү"</string>
+    <string name="call_barring_settings" msgid="4616607285790258919">"Чалууларга тыюу салуу функциясынын параметрлери"</string>
     <string name="callFailed_NetworkBusy" msgid="5437103975842913681">"Тармак бош эмес. Кийинчерээк кайра чалыңыз."</string>
     <string name="callFailed_NetworkCongested" msgid="6801283142342775380">"Тармак ашыкча жүктөлгөн. Жардам алуу үчүн мобилдик операторуңуз менен байланышыңыз."</string>
     <string name="supp_service_notification_call_deflected" msgid="4980942818105909813">"Чалуу кабыл алынган жок."</string>
@@ -818,10 +818,10 @@
     <string name="callFailed_already_ringing" msgid="2376603543544289303">"Чалуу аткарылбайт, анткени кирүүчү чалууга жооп берилген жок. Жаңы чалуу аткаруудан мурун кирүүчү чалууга жооп берип же четке кагыңыз."</string>
     <string name="callFailed_calling_disabled" msgid="5010992739401206283">"Чалуу аткарылбайт, анткени чалуу ro.telephony.disable-call тутуму аркылуу өчүрүлгөн."</string>
     <string name="callFailed_too_many_calls" msgid="2761754044990799580">"Чалуу аткарылбайт, анткени эки чалуу аткарылууда. Бир чалууну өчүрүңүз же аларды конференцияга бириктириңиз."</string>
-    <string name="supp_service_over_ut_precautions" msgid="2145018231396701311">"<xliff:g id="SUPP_SERVICE">%s</xliff:g> колдонуу үчүн мобилдик Интернет күйгүзүлгөнүн текшериңиз. Муну мобилдик тармак жөндөөлөрүнөн өзгөртсөңүз болот."</string>
-    <string name="supp_service_over_ut_precautions_roaming" msgid="670342104569972327">"<xliff:g id="SUPP_SERVICE">%s</xliff:g> колдонуу үчүн мобилдик Интернет жана Интернет-роуминг күйгүзүлгөнүн текшериңиз. Муну мобилдик тармак жөндөөлөрүнөн өзгөртсөңүз болот."</string>
-    <string name="supp_service_over_ut_precautions_dual_sim" msgid="5166866975550910474">"<xliff:g id="SUPP_SERVICE">%1$s</xliff:g> колдонуу үчүн <xliff:g id="SIM_NUMBER">%2$d</xliff:g> SIM-картасында мобилдик Интернет күйгүзүлгөнүн текшериңиз. Муну мобилдик тармак жөндөөлөрүнөн өзгөртсөңүз болот."</string>
-    <string name="supp_service_over_ut_precautions_roaming_dual_sim" msgid="6627654855191817965">"<xliff:g id="SUPP_SERVICE">%1$s</xliff:g> колдонуу үчүн <xliff:g id="SIM_NUMBER">%2$d</xliff:g> SIM-картасында мобилдик Интернет жана Интернет-роуминг күйгүзүлгөнүн текшериңиз. Муну мобилдик тармак жөндөөлөрүнөн өзгөртсөңүз болот."</string>
+    <string name="supp_service_over_ut_precautions" msgid="2145018231396701311">"<xliff:g id="SUPP_SERVICE">%s</xliff:g> колдонуу үчүн мобилдик Интернет күйгүзүлгөнүн текшериңиз. Муну мобилдик тармак параметрлеринен өзгөртсөңүз болот."</string>
+    <string name="supp_service_over_ut_precautions_roaming" msgid="670342104569972327">"<xliff:g id="SUPP_SERVICE">%s</xliff:g> колдонуу үчүн мобилдик Интернет жана Интернет-роуминг күйгүзүлгөнүн текшериңиз. Муну мобилдик тармак параметрлеринен өзгөртсөңүз болот."</string>
+    <string name="supp_service_over_ut_precautions_dual_sim" msgid="5166866975550910474">"<xliff:g id="SUPP_SERVICE">%1$s</xliff:g> колдонуу үчүн <xliff:g id="SIM_NUMBER">%2$d</xliff:g> SIM-картасында мобилдик Интернет күйгүзүлгөнүн текшериңиз. Муну мобилдик тармак параметрлеринен өзгөртсөңүз болот."</string>
+    <string name="supp_service_over_ut_precautions_roaming_dual_sim" msgid="6627654855191817965">"<xliff:g id="SUPP_SERVICE">%1$s</xliff:g> колдонуу үчүн <xliff:g id="SIM_NUMBER">%2$d</xliff:g> SIM-картасында мобилдик Интернет жана Интернет-роуминг күйгүзүлгөнүн текшериңиз. Муну мобилдик тармак параметрлеринен өзгөртсөңүз болот."</string>
     <string name="supp_service_over_ut_precautions_dialog_dismiss" msgid="5934541487903081652">"Жабуу"</string>
     <string name="radio_info_data_connection_enable" msgid="6183729739783252840">"Мобилдик туташууну иштетүү"</string>
     <string name="radio_info_data_connection_disable" msgid="6404751291511368706">"Мобилдик туташууну өчүрүү"</string>
@@ -903,7 +903,7 @@
     <string name="radio_info_smsc_update_label" msgid="5141996256097115753">"Жаңыртуу"</string>
     <string name="radio_info_smsc_refresh_label" msgid="8409923721451604560">"Жаңылоо"</string>
     <string name="radio_info_toggle_dns_check_label" msgid="1394078554927787350">"DNS текшерүүнү которуштуруу"</string>
-    <string name="oem_radio_info_label" msgid="2914167475119997456">"OEM\'ге тиешелүү Маалымат/Жөндөөлөр"</string>
+    <string name="oem_radio_info_label" msgid="2914167475119997456">"OEM\'ге тиешелүү Маалымат/Параметрлер"</string>
     <string name="radio_info_endc_available" msgid="2983767110681230019">"EN-DC жеткиликтүү (NSA):"</string>
     <string name="radio_info_dcnr_restricted" msgid="7147511536420148173">"DCNR чектелген (NSA):"</string>
     <string name="radio_info_nr_available" msgid="3383388088451237182">"NR жеткиликтүү (NSA):"</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 79119a3..e21f761 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2203,4 +2203,10 @@
     <!-- Telephony notification channel name for a channel containing SIP accounts removed
      notificatios -->
     <string name="notification_channel_sip_account">Deprecated SIP accounts</string>
+
+    <string name="send_from_work_profile_title">Can\'t send message from this profile</string>
+    <string name="send_from_work_profile_description">Your work policy allows you to send message only from the work profile</string>
+    <string name="send_from_work_profile_cancel">Cancel</string>
+    <string name="send_from_work_profile_action_str">Switch to work profile</string>
+
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index d0f427c..19798f0 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -309,6 +309,17 @@
         <item name="android:backgroundDimEnabled">false</item>
     </style>
 
+    <style name="Theme.Telephony.Transparent" parent="@android:style/Theme.DeviceDefault.Light">
+        <item name="android:forceDarkAllowed">true</item>
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:windowContentOverlay">@null</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowIsFloating">true</item>
+        <item name="android:backgroundDimEnabled">true</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
+    </style>
+
     <style name="CallSettingsWithoutDividerTheme" parent="DialerSettingsLight">
         <item name="android:listDivider">@null</item>
     </style>
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index ede0015..5ba148d 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -65,6 +65,7 @@
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.SubscriptionInfoUpdater;
 import com.android.internal.telephony.TelephonyPermissions;
+import com.android.internal.telephony.subscription.SubscriptionManagerService;
 import com.android.internal.telephony.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.telephony.Rlog;
@@ -309,7 +310,7 @@
                             // smoothly.
                             mConfigFromDefaultApp[phoneId] = new PersistableBundle();
                             // Send broadcast if bind fails.
-                            notifySubscriptionInfoUpdater(phoneId);
+                            updateSubscriptionDatabase(phoneId);
                             // TODO: We *must* call unbindService even if bindService returns false.
                             // (And possibly if SecurityException was thrown.)
                             loge("binding to default app: "
@@ -344,7 +345,7 @@
                                     if (resultCode == RESULT_ERROR || resultData == null) {
                                         // On error, abort config fetching.
                                         loge("Failed to get carrier config");
-                                        notifySubscriptionInfoUpdater(phoneId);
+                                        updateSubscriptionDatabase(phoneId);
                                         return;
                                     }
                                     PersistableBundle config =
@@ -393,7 +394,7 @@
                     }
                     // Put a stub bundle in place so that the rest of the logic continues smoothly.
                     mConfigFromDefaultApp[phoneId] = new PersistableBundle();
-                    notifySubscriptionInfoUpdater(phoneId);
+                    updateSubscriptionDatabase(phoneId);
                     break;
                 }
 
@@ -409,7 +410,7 @@
                         logd("Found carrier config app: " + carrierPackageName);
                         sendMessage(obtainMessage(EVENT_DO_FETCH_CARRIER, phoneId, -1));
                     } else {
-                        notifySubscriptionInfoUpdater(phoneId);
+                        updateSubscriptionDatabase(phoneId);
                     }
                     break;
                 }
@@ -443,7 +444,7 @@
                             // Send broadcast if bind fails.
                             broadcastConfigChangedIntent(phoneId);
                             loge("Bind to carrier app: " + carrierPackageName + " fails");
-                            notifySubscriptionInfoUpdater(phoneId);
+                            updateSubscriptionDatabase(phoneId);
                         }
                     }
                     break;
@@ -476,7 +477,7 @@
                                         loge("Failed to get carrier config from carrier app: "
                                                 + getCarrierPackageForPhoneId(phoneId));
                                         broadcastConfigChangedIntent(phoneId);
-                                        notifySubscriptionInfoUpdater(phoneId);
+                                        updateSubscriptionDatabase(phoneId);
                                         return;
                                     }
                                     PersistableBundle config =
@@ -533,7 +534,7 @@
                     }
                     // Put a stub bundle in place so that the rest of the logic continues smoothly.
                     mConfigFromCarrierApp[phoneId] = new PersistableBundle();
-                    notifySubscriptionInfoUpdater(phoneId);
+                    updateSubscriptionDatabase(phoneId);
                     break;
                 }
                 case EVENT_FETCH_CARRIER_DONE: {
@@ -543,7 +544,7 @@
                             && mServiceConnection[phoneId] == null) {
                         break;
                     }
-                    notifySubscriptionInfoUpdater(phoneId);
+                    updateSubscriptionDatabase(phoneId);
                     break;
                 }
 
@@ -696,7 +697,8 @@
      */
     @VisibleForTesting
     /* package */ CarrierConfigLoader(@NonNull Context context,
-            @NonNull SubscriptionInfoUpdater subscriptionInfoUpdater, @NonNull Looper looper) {
+            //TODO: Remove SubscriptionInfoUpdater.
+            @Nullable SubscriptionInfoUpdater subscriptionInfoUpdater, @NonNull Looper looper) {
         mContext = context;
         mPlatformCarrierConfigPackage =
                 mContext.getString(R.string.platform_carrier_config_package);
@@ -774,17 +776,18 @@
         }
     }
 
-    private void notifySubscriptionInfoUpdater(int phoneId) {
-        String configPackagename;
+    private void updateSubscriptionDatabase(int phoneId) {
+        logd("updateSubscriptionDatabase: phoneId=" + phoneId);
+        String configPackageName;
         PersistableBundle configToSend;
         int carrierId = getSpecificCarrierIdForPhoneId(phoneId);
         // Prefer the carrier privileged carrier app, but if there is not one, use the platform
         // default carrier app.
         if (mConfigFromCarrierApp[phoneId] != null) {
-            configPackagename = getCarrierPackageForPhoneId(phoneId);
+            configPackageName = getCarrierPackageForPhoneId(phoneId);
             configToSend = mConfigFromCarrierApp[phoneId];
         } else {
-            configPackagename = mPlatformCarrierConfigPackage;
+            configPackageName = mPlatformCarrierConfigPackage;
             configToSend = mConfigFromDefaultApp[phoneId];
         }
 
@@ -799,9 +802,16 @@
             configToSend.putAll(config);
         }
 
-        mSubscriptionInfoUpdater.updateSubscriptionByCarrierConfigAndNotifyComplete(
-                phoneId, configPackagename, configToSend,
-                mHandler.obtainMessage(EVENT_SUBSCRIPTION_INFO_UPDATED, phoneId, -1));
+        if (PhoneFactory.isSubscriptionManagerServiceEnabled()) {
+            SubscriptionManagerService.getInstance().updateSubscriptionByCarrierConfig(
+                    phoneId, configPackageName, configToSend,
+                    () -> mHandler.obtainMessage(EVENT_SUBSCRIPTION_INFO_UPDATED, phoneId, -1)
+                            .sendToTarget());
+        } else {
+            mSubscriptionInfoUpdater.updateSubscriptionByCarrierConfigAndNotifyComplete(
+                    phoneId, configPackageName, configToSend,
+                    mHandler.obtainMessage(EVENT_SUBSCRIPTION_INFO_UPDATED, phoneId, -1));
+        }
     }
 
     private void broadcastConfigChangedIntent(int phoneId) {
@@ -1434,7 +1444,7 @@
                     fileToDelete.delete();
                 }
             }
-            notifySubscriptionInfoUpdater(phoneId);
+            updateSubscriptionDatabase(phoneId);
         });
     }
 
diff --git a/src/com/android/phone/EmergencyCallbackModeExitDialog.java b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
index fc0e513..6901789 100644
--- a/src/com/android/phone/EmergencyCallbackModeExitDialog.java
+++ b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
@@ -43,6 +43,8 @@
 
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.domainselection.DomainSelectionResolver;
+import com.android.internal.telephony.emergency.EmergencyStateTracker;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -244,9 +246,16 @@
                     .setMessage(text)
                     .setPositiveButton(R.string.alert_dialog_yes,
                             new DialogInterface.OnClickListener() {
-                                public void onClick(DialogInterface dialog,int whichButton) {
+                                public void onClick(DialogInterface dialog,
+                                        int whichButton) {
                                     // User clicked Yes. Exit Emergency Callback Mode.
-                                    mPhone.exitEmergencyCallbackMode();
+                                    if (DomainSelectionResolver.getInstance()
+                                            .isDomainSelectionSupported()) {
+                                        EmergencyStateTracker.getInstance()
+                                                .exitEmergencyCallbackMode();
+                                    } else {
+                                        mPhone.exitEmergencyCallbackMode();
+                                    }
 
                                     // Show progress dialog
                                     showDialog(EXIT_ECM_PROGRESS_DIALOG);
diff --git a/src/com/android/phone/ErrorDialogActivity.java b/src/com/android/phone/ErrorDialogActivity.java
new file mode 100644
index 0000000..11a92a8
--- /dev/null
+++ b/src/com/android/phone/ErrorDialogActivity.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.app.AlertDialog;
+import android.app.role.RoleManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.UserInfo;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+
+import java.util.List;
+
+/** Used to display an error dialog from Telephony service. */
+public class ErrorDialogActivity extends Activity {
+
+    private static final String TAG = ErrorDialogActivity.class.getSimpleName();
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow()
+                .addSystemFlags(
+                        android.view.WindowManager.LayoutParams
+                                .SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+        showDialog();
+    }
+
+    @Override
+    public void finish() {
+        super.finish();
+        // Don't show the return to previous task animation to avoid showing a black screen.
+        // Just dismiss the dialog and undim the previous activity immediately.
+        overridePendingTransition(0, 0);
+    }
+
+    private void showDialog() {
+        final DialogInterface.OnClickListener listener =
+                new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        switch (which) {
+                            case DialogInterface.BUTTON_POSITIVE:
+                                switchToManagedProfile();
+                                finish();
+                                break;
+                            case DialogInterface.BUTTON_NEGATIVE:
+                            default:
+                                finish();
+                        }
+                    }
+                };
+
+        new AlertDialog.Builder(this)
+            .setTitle(R.string.send_from_work_profile_title)
+            .setMessage(R.string.send_from_work_profile_description)
+            .setPositiveButton(R.string.send_from_work_profile_action_str, listener)
+            .setNegativeButton(R.string.send_from_work_profile_cancel, listener)
+            .setOnCancelListener(
+                new DialogInterface.OnCancelListener() {
+                    @Override
+                    public void onCancel(DialogInterface dialog) {
+                        finish();
+                    }
+                })
+            .show();
+    }
+
+    private void switchToManagedProfile() {
+        try {
+            int managedProfileUserId =
+                    getManagedProfileUserId(
+                            getApplicationContext(), getApplicationContext().getUserId());
+            if (managedProfileUserId == UserHandle.USER_NULL) {
+                finish();
+            }
+
+            String defaultMessagesAppPackage =
+                    getBaseContext()
+                            .getSystemService(RoleManager.class)
+                            .getSmsRoleHolder(managedProfileUserId);
+
+            Intent sendIntent = new Intent(Intent.ACTION_MAIN);
+            sendIntent.addCategory(Intent.CATEGORY_DEFAULT);
+            sendIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+            sendIntent.addCategory(Intent.CATEGORY_APP_MESSAGING);
+
+            sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+            if (defaultMessagesAppPackage != null) {
+                sendIntent.setPackage(defaultMessagesAppPackage);
+            }
+
+            startActivityAsUser(sendIntent,
+                    ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle(),
+                    UserHandle.of(managedProfileUserId));
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to switch to managed profile.", e);
+        }
+    }
+
+    private static int getManagedProfileUserId(Context context, int userId) {
+        UserManager um = context.getSystemService(UserManager.class);
+        List<UserInfo> userProfiles = um.getProfiles(userId);
+        for (UserInfo uInfo : userProfiles) {
+            if (uInfo.id == userId) {
+                continue;
+            }
+            if (uInfo.isManagedProfile()) {
+                return uInfo.id;
+            }
+        }
+        return UserHandle.USER_NULL;
+    }
+}
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index 27e1606..d2c0e6b 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -1071,7 +1071,8 @@
         mSelectedNetworkOperatorName.remove(subId);
     }
 
-    private static long getTimeStamp() {
+    @VisibleForTesting
+    public long getTimeStamp() {
         return SystemClock.elapsedRealtime();
     }
 }
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 78a734a..200dc75 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -527,6 +527,8 @@
 
             imsRcsController = ImsRcsController.init(this);
 
+            configLoader = CarrierConfigLoader.init(this);
+
             if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS)) {
                 mImsStateCallbackController =
                         ImsStateCallbackController.make(this, PhoneFactory.getPhones().length);
@@ -538,8 +540,6 @@
                         ImsProvisioningController.make(this, PhoneFactory.getPhones().length);
             }
 
-            configLoader = CarrierConfigLoader.init(this);
-
             // Create the CallNotifier singleton, which handles
             // asynchronous events from the telephony layer (like
             // launching the incoming-call UI when an incoming call comes
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 14962af..709260c 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -31,6 +31,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
 import android.app.PropertyInvalidatedCache;
@@ -71,6 +72,7 @@
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.provider.Telephony;
+import android.service.carrier.CarrierIdentifier;
 import android.sysprop.TelephonyProperties;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
@@ -222,6 +224,7 @@
 import com.android.phone.callcomposer.ImageData;
 import com.android.phone.settings.PickSmsSubscriptionActivity;
 import com.android.phone.slice.SlicePurchaseController;
+import com.android.phone.utils.CarrierAllowListInfo;
 import com.android.phone.vvm.PhoneAccountHandleConverter;
 import com.android.phone.vvm.RemoteVvmTaskManager;
 import com.android.phone.vvm.VisualVoicemailSettingsUtil;
@@ -373,7 +376,6 @@
     private static final int EVENT_IS_VONR_ENABLED_DONE = 116;
     private static final int CMD_PURCHASE_PREMIUM_CAPABILITY = 117;
     private static final int EVENT_PURCHASE_PREMIUM_CAPABILITY_DONE = 118;
-
     // Parameters of select command.
     private static final int SELECT_COMMAND = 0xA4;
     private static final int SELECT_P1 = 0x04;
@@ -394,11 +396,10 @@
     private AppOpsManager mAppOps;
     private PackageManager mPm;
     private MainThreadHandler mMainThreadHandler;
-    private SubscriptionController mSubscriptionController;
+    private final SubscriptionController mSubscriptionController;
     private SharedPreferences mTelephonySharedPreferences;
     private PhoneConfigurationManager mPhoneConfigurationManager;
     private final RadioInterfaceCapabilityController mRadioInterfaceCapabilities;
-    private final Telephony2gUpdater mTelephony2gUpdater;
 
     /** User Activity */
     private AtomicBoolean mNotifyUserActivity;
@@ -436,6 +437,8 @@
 
     private static final int SET_NETWORK_SELECTION_MODE_AUTOMATIC_TIMEOUT_MS = 2000; // 2 seconds
 
+    private static final int MODEM_ACTIVITY_TIME_OFFSET_CORRECTION_MS = 50;
+
     /**
      * With support for MEP(multiple enabled profile) in Android T, a SIM card can have more than
      * one ICCID active at the same time.
@@ -489,13 +492,11 @@
 
     private static final class PurchasePremiumCapabilityArgument {
         public @TelephonyManager.PremiumCapability int capability;
-        public @NonNull String appName;
         public @NonNull IIntegerConsumer callback;
 
         PurchasePremiumCapabilityArgument(@TelephonyManager.PremiumCapability int capability,
-                @NonNull String appName, @NonNull IIntegerConsumer callback) {
+                @NonNull IIntegerConsumer callback) {
             this.capability = capability;
-            this.appName = appName;
             this.callback = callback;
         }
     }
@@ -1467,6 +1468,8 @@
                         ModemActivityInfo info = (ModemActivityInfo) ar.result;
                         if (isModemActivityInfoValid(info)) {
                             mergeModemActivityInfo(info);
+                        } else {
+                            loge("queryModemActivityInfo: invalid response");
                         }
                         // This is needed to decouple ret from mLastModemActivityInfo
                         // We don't want to return mLastModemActivityInfo which is updated
@@ -1558,7 +1561,39 @@
                             loge("getAllowedCarriers: Unknown exception");
                         }
                     }
-                    notifyRequester(request);
+                    if (request.argument != null) {
+                        // This is for the implementation of carrierRestrictionStatus.
+                        CallerCallbackInfo callbackInfo = (CallerCallbackInfo) request.argument;
+                        Consumer<Integer> callback = callbackInfo.getConsumer();
+                        int callerCarrierId = callbackInfo.getCarrierId();
+                        int lockStatus = TelephonyManager.CARRIER_RESTRICTION_STATUS_UNKNOWN;
+                        if (ar.exception == null && ar.result instanceof CarrierRestrictionRules) {
+                            CarrierRestrictionRules carrierRestrictionRules =
+                                    (CarrierRestrictionRules) ar.result;
+                            int carrierId = -1;
+                            try {
+                                CarrierIdentifier carrierIdentifier =
+                                        carrierRestrictionRules.getAllowedCarriers().get(0);
+                                carrierId = CarrierResolver.getCarrierIdFromIdentifier(mApp,
+                                        carrierIdentifier);
+                            } catch (NullPointerException | IndexOutOfBoundsException ex) {
+                                Rlog.e(LOG_TAG, "CarrierIdentifier exception = " + ex);
+                            }
+                            lockStatus = carrierRestrictionRules.getCarrierRestrictionStatus();
+                            if (carrierId != -1 && callerCarrierId == carrierId && lockStatus
+                                    == TelephonyManager.CARRIER_RESTRICTION_STATUS_RESTRICTED) {
+                                lockStatus =
+                                 TelephonyManager.CARRIER_RESTRICTION_STATUS_RESTRICTED_TO_CALLER;
+                            }
+                        } else {
+                            Rlog.e(LOG_TAG,
+                                    "getCarrierRestrictionStatus: exception ex = " + ar.exception);
+                        }
+                        callback.accept(lockStatus);
+                    } else {
+                        // This is for the implementation of getAllowedCarriers.
+                        notifyRequester(request);
+                    }
                     break;
 
                 case EVENT_GET_FORBIDDEN_PLMNS_DONE:
@@ -2177,7 +2212,7 @@
                     PurchasePremiumCapabilityArgument arg =
                             (PurchasePremiumCapabilityArgument) request.argument;
                     SlicePurchaseController.getInstance(request.phone).purchasePremiumCapability(
-                            arg.capability, arg.appName, onCompleted);
+                            arg.capability, onCompleted);
                     break;
                 }
 
@@ -2410,7 +2445,11 @@
         mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
         mPm = app.getSystemService(PackageManager.class);
         mMainThreadHandler = new MainThreadHandler();
-        mSubscriptionController = SubscriptionController.getInstance();
+        if (!PhoneFactory.isSubscriptionManagerServiceEnabled()) {
+            mSubscriptionController = SubscriptionController.getInstance();
+        } else {
+            mSubscriptionController = null;
+        }
         mTelephonySharedPreferences =
                 PreferenceManager.getDefaultSharedPreferences(mApp);
         mNetworkScanRequestTracker = new NetworkScanRequestTracker();
@@ -2418,10 +2457,8 @@
         mRadioInterfaceCapabilities = RadioInterfaceCapabilityController.getInstance();
         mNotifyUserActivity = new AtomicBoolean(false);
         PropertyInvalidatedCache.invalidateCache(TelephonyManager.CACHE_KEY_PHONE_ACCOUNT_TO_SUBID);
-        mTelephony2gUpdater = new Telephony2gUpdater(
-                Executors.newSingleThreadExecutor(), mApp);
-        mTelephony2gUpdater.init();
         publish();
+        CarrierAllowListInfo.loadInstance(mApp);
     }
 
     @VisibleForTesting
@@ -2460,6 +2497,20 @@
                 ? getDefaultPhone() : getPhone(subId);
     }
 
+    /**
+     * Get phone object associated with a subscription.
+     * Return default phone if phone object associated with subscription is null
+     * @param subId - subscriptionId
+     * @return phone object associated with a subscription or default phone if null.
+     */
+    private Phone getPhoneFromSubIdOrDefault(int subId) {
+        Phone phone = getPhoneFromSubId(subId);
+        if (phone == null) {
+            phone = getDefaultPhone();
+        }
+        return phone;
+    }
+
     @Nullable
     private UiccPort getUiccPortFromRequest(@NonNull MainThreadRequest request) {
         Phone phone = getPhoneFromRequest(request);
@@ -3685,13 +3736,23 @@
     }
 
     /**
-     * Make sure the caller has the MODIFY_PHONE_STATE permission.
+     * Make sure the caller has the READ_PHONE_STATE permission.
      *
      * @throws SecurityException if the caller does not have the required permission
      */
     @VisibleForTesting
     public void enforceReadPermission() {
-        mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, null);
+        enforceReadPermission(null);
+    }
+
+    /**
+     * Make sure the caller has the READ_PHONE_STATE permissions.
+     *
+     * @throws SecurityException if the caller does not have the READ_PHONE_STATE permission.
+     */
+    @VisibleForTesting
+    public void enforceReadPermission(String msg) {
+        mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, msg);
     }
 
     private void enforceActiveEmergencySessionPermission() {
@@ -4389,7 +4450,18 @@
         try {
             int slotId = getSlotIndexOrException(subId);
             verifyImsMmTelConfiguredOrThrow(slotId);
-            ImsManager.getInstance(mApp, slotId).addCapabilitiesCallbackForSubscription(c, subId);
+
+            ImsStateCallbackController controller = ImsStateCallbackController.getInstance();
+            if (controller != null) {
+                ImsManager imsManager = controller.getImsManager(subId);
+                if (imsManager != null) {
+                    imsManager.addCapabilitiesCallbackForSubscription(c, subId);
+                } else {
+                    throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+                }
+            } else {
+                throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
+            }
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4412,13 +4484,18 @@
 
         final long token = Binder.clearCallingIdentity();
         try {
-            ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
-                        .removeCapabilitiesCallbackForSubscription(c, subId);
-        } catch (ImsException e) {
-            Log.i(LOG_TAG, "unregisterMmTelCapabilityCallback: " + subId
-                     + "is inactive, ignoring unregister.");
-             // If the subscription is no longer active, just return, since the callback
-             // will already have been removed internally.
+            ImsStateCallbackController controller = ImsStateCallbackController.getInstance();
+            if (controller != null) {
+                ImsManager imsManager = controller.getImsManager(subId);
+                if (imsManager != null) {
+                    imsManager.removeCapabilitiesCallbackForSubscription(c, subId);
+                } else {
+                    Log.i(LOG_TAG, "unregisterMmTelCapabilityCallback: " + subId
+                            + " is inactive, ignoring unregister.");
+                    // If the ImsManager is not valid, just return, since the callback
+                    // will already have been removed internally.
+                }
+            }
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -4829,8 +4906,18 @@
             }
             int slotId = getSlotIndexOrException(subId);
             verifyImsMmTelConfiguredOrThrow(slotId);
-            ImsManager.getInstance(mApp, slotId)
-                    .addProvisioningCallbackForSubscription(callback, subId);
+
+            ImsStateCallbackController controller = ImsStateCallbackController.getInstance();
+            if (controller != null) {
+                ImsManager imsManager = controller.getImsManager(subId);
+                if (imsManager != null) {
+                    imsManager.addProvisioningCallbackForSubscription(callback, subId);
+                } else {
+                    throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+                }
+            } else {
+                throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
+            }
         } catch (ImsException e) {
             throw new ServiceSpecificException(e.getCode());
         } finally {
@@ -4847,13 +4934,18 @@
             throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
         }
         try {
-            ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
-                    .removeProvisioningCallbackForSubscription(callback, subId);
-        } catch (ImsException e) {
-            Log.i(LOG_TAG, "unregisterImsProvisioningChangedCallback: " + subId
-                    + "is inactive, ignoring unregister.");
-            // If the subscription is no longer active, just return, since the callback will already
-            // have been removed internally.
+            ImsStateCallbackController controller = ImsStateCallbackController.getInstance();
+            if (controller != null) {
+                ImsManager imsManager = controller.getImsManager(subId);
+                if (imsManager != null) {
+                    imsManager.removeProvisioningCallbackForSubscription(callback, subId);
+                } else {
+                    Log.i(LOG_TAG, "unregisterImsProvisioningChangedCallback: " + subId
+                            + " is inactive, ignoring unregister.");
+                    // If the ImsManager is not valid, just return, since the callback will already
+                    // have been removed internally.
+                }
+            }
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -6744,11 +6836,15 @@
             return false;
         }
 
-        log("setAllowedNetworkTypesForReason: " + reason + " value: "
+        log("setAllowedNetworkTypesForReason: subId=" + subId + ", reason=" + reason + " value: "
                 + TelephonyManager.convertNetworkTypeBitmaskToString(allowedNetworkTypes));
 
+        Phone phone = getPhone(subId);
+        if (phone == null) {
+            return false;
+        }
 
-        if (allowedNetworkTypes == getPhoneFromSubId(subId).getAllowedNetworkTypes(reason)) {
+        if (allowedNetworkTypes == phone.getAllowedNetworkTypes(reason)) {
             log("setAllowedNetworkTypesForReason: " + reason + "does not change value");
             return true;
         }
@@ -8025,7 +8121,7 @@
         }
     }
 
-    // Checks that ModemActivityInfo is valid. Sleep time, Idle time, Rx time and Tx time should be
+    // Checks that ModemActivityInfo is valid. Sleep time and Idle time should be
     // less than total activity duration.
     private boolean isModemActivityInfoValid(ModemActivityInfo info) {
         if (info == null) {
@@ -8033,13 +8129,13 @@
         }
         int activityDurationMs =
                 (int) (info.getTimestampMillis() - mLastModemActivityInfo.getTimestampMillis());
+        activityDurationMs += MODEM_ACTIVITY_TIME_OFFSET_CORRECTION_MS;
+
         int totalTxTimeMs = Arrays.stream(info.getTransmitTimeMillis()).sum();
 
         return (info.isValid()
             && (info.getSleepTimeMillis() <= activityDurationMs)
-            && (info.getIdleTimeMillis() <= activityDurationMs)
-            && (info.getReceiveTimeMillis() <= activityDurationMs)
-            && (totalTxTimeMs <= activityDurationMs));
+            && (info.getIdleTimeMillis() <= activityDurationMs));
     }
 
     private void updateLastModemActivityInfo(ModemActivityInfo info, int rat, int freq) {
@@ -8357,7 +8453,8 @@
      *
      * @throws SecurityException if the caller does not have the required permission
      */
-    private void enforceReadPrivilegedPermission(String message) {
+    @VisibleForTesting
+    public void enforceReadPrivilegedPermission(String message) {
         mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
                 message);
     }
@@ -8567,6 +8664,38 @@
     }
 
     /**
+     * Fetches the carrier restriction status of the device and sends the status to the caller
+     * through the callback.
+     *
+     * @param callback The callback that will be used to send the result.
+     * @throws SecurityException if the caller does not have the required permission/privileges or
+     *                           the caller is not allowlisted.
+     */
+    @Override
+    public void getCarrierRestrictionStatus(IIntegerConsumer callback, String packageName) {
+        enforceReadPermission("getCarrierRestrictionStatus");
+        int carrierId = validateCallerAndGetCarrierId(packageName);
+        if (carrierId == CarrierAllowListInfo.INVALID_CARRIER_ID) {
+            Rlog.e(LOG_TAG, "getCarrierRestrictionStatus: caller is not registered");
+            throw new SecurityException("Not an authorized caller");
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            Consumer<Integer> consumer = FunctionalUtils.ignoreRemoteException(callback::accept);
+            CallerCallbackInfo callbackInfo = new CallerCallbackInfo(consumer, carrierId);
+            sendRequestAsync(CMD_GET_ALLOWED_CARRIERS, callbackInfo);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @VisibleForTesting
+    public int validateCallerAndGetCarrierId(String packageName) {
+        CarrierAllowListInfo allowListInfo = CarrierAllowListInfo.loadInstance(mApp);
+        return allowListInfo.validateCallerAndGetCarrierId(packageName);
+    }
+
+    /**
      * Action set from carrier signalling broadcast receivers to enable/disable radio
      * @param subId the subscription ID that this action applies to.
      * @param enabled control enable or disable radio.
@@ -10085,6 +10214,16 @@
     }
 
     @Override
+    public void showSwitchToManagedProfileDialog() {
+        enforceModifyPermission();
+
+        Intent intent = new Intent();
+        intent.setClass(mApp, ErrorDialogActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mApp.startActivity(intent);
+    }
+
+    @Override
     public String getMmsUAProfUrl(int subId) {
         //TODO investigate if this API should require proper permission check in R b/133791609
         final long identity = Binder.clearCallingIdentity();
@@ -10193,8 +10332,9 @@
             throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
         }
         if (!isImsAvailableOnDevice()) {
-            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
-                    "IMS not available on device.");
+            // ProvisioningManager can not handle ServiceSpecificException.
+            // Throw the IllegalStateException and annotate ProvisioningManager.
+            throw new IllegalStateException("IMS not available on device.");
         }
 
         final long identity = Binder.clearCallingIdentity();
@@ -10793,8 +10933,9 @@
             throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
         }
         if (!isImsAvailableOnDevice()) {
-            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
-                    "IMS not available on device.");
+            // operation failed silently
+            Rlog.w(LOG_TAG, "IMS not available on device.");
+            return;
         }
 
         final long identity = Binder.clearCallingIdentity();
@@ -10818,8 +10959,9 @@
             throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
         }
         if (!isImsAvailableOnDevice()) {
-            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
-                    "IMS not available on device.");
+            // ProvisioningManager can not handle ServiceSpecificException.
+            // Throw the IllegalStateException and annotate ProvisioningManager.
+            throw new IllegalStateException("IMS not available on device.");
         }
 
         final long identity = Binder.clearCallingIdentity();
@@ -11449,6 +11591,12 @@
                     + " failed due to missing permissions.");
             throw new SecurityException("purchasePremiumCapability requires permission "
                     + "READ_BASIC_PHONE_STATE.");
+        } else if (!TelephonyPermissions.checkInternetPermissionNoThrow(
+                mApp, "purchasePremiumCapability")) {
+            log("purchasePremiumCapability "
+                    + TelephonyManager.convertPremiumCapabilityToString(capability)
+                    + " failed due to missing permissions.");
+            throw new SecurityException("purchasePremiumCapability requires permission INTERNET.");
         }
 
         Phone phone = getPhone(subId);
@@ -11467,15 +11615,50 @@
             }
             return;
         }
-        String appName;
+
+        String callingProcess;
         try {
-            appName = mApp.getPackageManager().getApplicationLabel(mApp.getPackageManager()
-                    .getApplicationInfo(getCurrentPackageName(), 0)).toString();
+            callingProcess = mApp.getPackageManager().getApplicationInfo(
+                    getCurrentPackageName(), 0).processName;
         } catch (PackageManager.NameNotFoundException e) {
-            appName = "An application";
+            callingProcess = getCurrentPackageName();
         }
+
+        boolean isVisible = false;
+        ActivityManager am = mApp.getSystemService(ActivityManager.class);
+        if (am != null) {
+            List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
+            if (processes != null) {
+                for (ActivityManager.RunningAppProcessInfo process : processes) {
+                    log("purchasePremiumCapability: process " + process.processName
+                            + "has importance " + process.importance);
+                    if (process.processName.equals(callingProcess) && process.importance
+                            <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
+                        isVisible = true;
+                        break;
+                    }
+                }
+            }
+        }
+
+        if (!isVisible) {
+            try {
+                int result = TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_FOREGROUND;
+                callback.accept(result);
+                loge("purchasePremiumCapability: " + callingProcess + " is not in the foreground.");
+            } catch (RemoteException e) {
+                String logStr = "Purchase premium capability "
+                        + TelephonyManager.convertPremiumCapabilityToString(capability)
+                        + " failed due to RemoteException handling background application: " + e;
+                if (DBG) log(logStr);
+                AnomalyReporter.reportAnomaly(
+                        UUID.fromString(PURCHASE_PREMIUM_CAPABILITY_ERROR_UUID), logStr);
+            }
+            return;
+        }
+
         sendRequestAsync(CMD_PURCHASE_PREMIUM_CAPABILITY,
-                new PurchasePremiumCapabilityArgument(capability, appName, callback), phone, null);
+                new PurchasePremiumCapabilityArgument(capability, callback), phone, null);
     }
 
     /**
@@ -11641,6 +11824,8 @@
         try {
             Phone phone = getPhone(subId);
             if (phone == null) return;
+            Log.i(LOG_TAG, "setVoiceServiceStateOverride: subId=" + subId + ", phone=" + phone
+                    + ", hasService=" + hasService + ", callingPackage=" + callingPackage);
             phone.setVoiceServiceStateOverride(hasService);
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -11696,7 +11881,8 @@
             boolean updateIfNeeded) {
         enforceInteractAcrossUsersPermission("getDefaultRespondViaMessageApplication");
 
-        Context context = getPhone(subId).getContext();
+        Context context = getPhoneFromSubIdOrDefault(subId).getContext();
+
         UserHandle userHandle = null;
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -11884,4 +12070,25 @@
         }
         return false;
     }
+
+    /**
+     * Class binds the consumer[callback] and carrierId.
+     */
+    private static class CallerCallbackInfo {
+        private final Consumer<Integer> mConsumer;
+        private final int mCarrierId;
+
+        public CallerCallbackInfo(Consumer<Integer> consumer, int carrierId) {
+            mConsumer = consumer;
+            mCarrierId = carrierId;
+        }
+
+        public Consumer<Integer> getConsumer() {
+            return mConsumer;
+        }
+
+        public int getCarrierId() {
+            return mCarrierId;
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/phone/Telephony2gUpdater.java b/src/com/android/phone/Telephony2gUpdater.java
deleted file mode 100644
index 0919385..0000000
--- a/src/com/android/phone/Telephony2gUpdater.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.phone;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.UserManager;
-import android.telephony.RadioAccessFamily;
-import android.telephony.SubscriptionInfo;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.RILConstants;
-
-import java.util.List;
-import java.util.concurrent.Executor;
-
-/**
- * A {@link BroadcastReceiver} that ensures that user restrictions are correctly applied to
- * telephony.
- * This includes handling broadcasts from user restriction state changes, as well as ensuring that
- * SIM-specific settings are correctly applied when new subscriptions become active.
- *
- * Callers are expected to call {@code init()} and keep an instance of this class alive.
- */
-public class Telephony2gUpdater extends BroadcastReceiver {
-    private static final String TAG = "TelephonyUserManagerReceiver";
-
-    // We can't interact with the HAL on the main thread of the phone process (where
-    // receivers are run by default), so we execute our logic from a separate thread.
-    private final Executor mExecutor;
-    private final Context mContext;
-    private final long mBaseAllowedNetworks;
-
-    public Telephony2gUpdater(Executor executor, Context context) {
-        this(executor, context,
-                RadioAccessFamily.getRafFromNetworkType(RILConstants.PREFERRED_NETWORK_MODE));
-    }
-
-    public Telephony2gUpdater(Executor executor, Context context,
-            long baseAllowedNetworks) {
-        mExecutor = executor;
-        mContext = context;
-        mBaseAllowedNetworks = baseAllowedNetworks;
-    }
-
-    /**
-     * Register the given instance as a {@link BroadcastReceiver} and a {@link
-     * SubscriptionManager.OnSubscriptionsChangedListener}.
-     */
-    public void init() {
-        mContext.getSystemService(SubscriptionManager.class).addOnSubscriptionsChangedListener(
-                mExecutor, new SubscriptionListener());
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED);
-        mContext.registerReceiver(this, filter);
-    }
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        if (context == null || intent == null) return;
-        Log.i(TAG, "Received callback for action " + intent.getAction());
-        final PendingResult result = goAsync();
-        mExecutor.execute(() -> {
-            Log.i(TAG, "Running handler for action " + intent.getAction());
-            handleUserRestrictionsChanged(context);
-            result.finish();
-        });
-    }
-
-    /**
-     * Update all active subscriptions with allowed network types depending on the current state
-     * of the {@link UserManager.DISALLOW_2G}.
-     */
-    @VisibleForTesting
-    public void handleUserRestrictionsChanged(Context context) {
-        UserManager um = context.getSystemService(UserManager.class);
-        TelephonyManager tm = context.getSystemService(TelephonyManager.class);
-        SubscriptionManager sm = context.getSystemService(SubscriptionManager.class);
-        final long twoGBitmask = TelephonyManager.NETWORK_CLASS_BITMASK_2G;
-
-        boolean shouldDisable2g = um.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G);
-
-        // This is expected when subscription info cannot be determined. We'll get another
-        // callback in the future from our SubscriptionListener once we have valid subscriptions.
-        List<SubscriptionInfo> subscriptionInfoList = sm.getAvailableSubscriptionInfoList();
-        if (subscriptionInfoList == null) {
-            return;
-        }
-
-        long allowedNetworkTypes = mBaseAllowedNetworks;
-
-        // 2G device admin controls are global
-        for (SubscriptionInfo info : subscriptionInfoList) {
-            TelephonyManager telephonyManager = tm.createForSubscriptionId(
-                    info.getSubscriptionId());
-            if (shouldDisable2g) {
-                allowedNetworkTypes &= ~twoGBitmask;
-            } else {
-                allowedNetworkTypes |= twoGBitmask;
-            }
-            telephonyManager.setAllowedNetworkTypesForReason(
-                    TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS,
-                    allowedNetworkTypes);
-        }
-    }
-
-    private class SubscriptionListener extends SubscriptionManager.OnSubscriptionsChangedListener {
-        @Override
-        public void onSubscriptionsChanged() {
-            Log.i(TAG, "Running handler for subscription change.");
-            handleUserRestrictionsChanged(mContext);
-        }
-    }
-
-}
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index fdaf1bb..f002e25 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -57,6 +57,7 @@
 import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.modules.utils.BasicShellCommandHandler;
 import com.android.phone.callcomposer.CallComposerPictureManager;
+import com.android.phone.utils.CarrierAllowListInfo;
 
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -97,6 +98,8 @@
     private static final String ENABLE = "enable";
     private static final String DISABLE = "disable";
     private static final String QUERY = "query";
+    private static final String CARRIER_RESTRICTION_STATUS_TEST = "carrier_restriction_status_test";
+    private final String QUOTES = "\"";
 
     private static final String CALL_COMPOSER_TEST_MODE = "test-mode";
     private static final String CALL_COMPOSER_SIMULATE_CALL = "simulate-outgoing-call";
@@ -341,6 +344,8 @@
                 return handleGetSimSlotsMapping();
             case RADIO_SUBCOMMAND:
                 return handleRadioCommand();
+            case CARRIER_RESTRICTION_STATUS_TEST:
+                return handleCarrierRestrictionStatusCommand();
             default: {
                 return handleDefaultCommands(cmd);
             }
@@ -3011,4 +3016,74 @@
 
         return -1;
     }
+
+    private int handleCarrierRestrictionStatusCommand() {
+        try {
+            String MOCK_MODEM_SERVICE_NAME = "android.telephony.mockmodem.MockModemService";
+            if (!(checkShellUid() && MOCK_MODEM_SERVICE_NAME.equalsIgnoreCase(
+                    mInterface.getModemService()))) {
+                Log.v(LOG_TAG,
+                        "handleCarrierRestrictionStatusCommand, MockModem service check fails or "
+                                + " checkShellUid fails");
+                return -1;
+            }
+        } catch (RemoteException ex) {
+            ex.printStackTrace();
+        }
+        String callerInfo = getNextOption();
+        CarrierAllowListInfo allowListInfo = CarrierAllowListInfo.loadInstance(mContext);
+        if (TextUtils.isEmpty(callerInfo)) {
+            // reset the Json content after testing
+            allowListInfo.updateJsonForTest(null);
+            return 0;
+        }
+        if (callerInfo.startsWith("--")) {
+            callerInfo = callerInfo.replace("--", "");
+        }
+        String params[] = callerInfo.split(",");
+        StringBuffer jsonStrBuffer = new StringBuffer();
+        String tokens;
+        for (int index = 0; index < params.length; index++) {
+            tokens = convertToJsonString(index, params[index]);
+            if (TextUtils.isEmpty(tokens)) {
+                // received wrong format from CTS
+                if (VDBG) {
+                    Log.v(LOG_TAG,
+                            "handleCarrierRestrictionStatusCommand, Shell command parsing error");
+                }
+                return -1;
+            }
+            jsonStrBuffer.append(tokens);
+        }
+        int result = allowListInfo.updateJsonForTest(jsonStrBuffer.toString());
+        return result;
+    }
+
+
+    /**
+     * Building the string that can be used to build the JsonObject which supports to stub the data
+     * in CarrierAllowListInfo for CTS testing. sample format is like
+     * {"com.android.example":{"carrierId":"10000","callerSHA1Id":["XXXXXXXXXXXXXX"]}}
+     */
+    private String convertToJsonString(int index, String param) {
+
+        String token[] = param.split(":");
+        String jSonString;
+        switch (index) {
+            case 0:
+                jSonString = "{" + QUOTES + token[1] + QUOTES + ":";
+                break;
+            case 1:
+                jSonString =
+                        "{" + QUOTES + token[0] + QUOTES + ":" + QUOTES + token[1] + QUOTES + ",";
+                break;
+            case 2:
+                jSonString =
+                        QUOTES + token[0] + QUOTES + ":" + "[" + QUOTES + token[1] + QUOTES + "]}}";
+                break;
+            default:
+                jSonString = null;
+        }
+        return jSonString;
+    }
 }
diff --git a/src/com/android/phone/slice/SlicePurchaseController.java b/src/com/android/phone/slice/SlicePurchaseController.java
index 3864119..e36325e 100644
--- a/src/com/android/phone/slice/SlicePurchaseController.java
+++ b/src/com/android/phone/slice/SlicePurchaseController.java
@@ -40,6 +40,7 @@
 import android.os.Message;
 import android.os.PersistableBundle;
 import android.provider.DeviceConfig;
+import android.sysprop.TelephonyProperties;
 import android.telephony.AnomalyReporter;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
@@ -204,11 +205,9 @@
     public static final String EXTRA_FAILURE_REASON =
             "com.android.phone.slice.extra.FAILURE_REASON";
     /**
-     * Extra for the application name requesting to purchase the premium capability
-     * from the slice purchase application.
+     * Extra for the user's carrier.
      */
-    public static final String EXTRA_REQUESTING_APP_NAME =
-            "com.android.phone.slice.extra.REQUESTING_APP_NAME";
+    public static final String EXTRA_CARRIER = "com.android.phone.slice.extra.CARRIER";
     /**
      * Extra for the canceled PendingIntent that the slice purchase application can send as a
      * response if the performance boost notification or WebView was canceled by the user.
@@ -497,11 +496,10 @@
                 break;
             }
             case EVENT_START_SLICE_PURCHASE_APP: {
-                int capability = msg.arg1;
-                String appName = (String) msg.obj;
-                logd("EVENT_START_SLICE_PURCHASE_APP: " + appName + " requests capability "
+                int capability = (int) msg.obj;
+                logd("EVENT_START_SLICE_PURCHASE_APP: "
                         + TelephonyManager.convertPremiumCapabilityToString(capability));
-                onStartSlicePurchaseApplication(capability, appName);
+                onStartSlicePurchaseApplication(capability);
                 break;
             }
             case EVENT_PURCHASE_TIMEOUT: {
@@ -565,13 +563,11 @@
      * Purchase the given premium capability from the carrier.
      *
      * @param capability The premium capability to purchase.
-     * @param appName The name of the application requesting premium capabilities.
      * @param onComplete The callback message to send when the purchase request is complete.
      */
     public synchronized void purchasePremiumCapability(
-            @TelephonyManager.PremiumCapability int capability, @NonNull String appName,
-            @NonNull Message onComplete) {
-        logd("purchasePremiumCapability: " + appName + " requests capability "
+            @TelephonyManager.PremiumCapability int capability, @NonNull Message onComplete) {
+        logd("purchasePremiumCapability: "
                 + TelephonyManager.convertPremiumCapabilityToString(capability));
         // Check whether the premium capability can be purchased.
         if (!arePremiumCapabilitiesSupportedByDevice()) {
@@ -627,8 +623,7 @@
         // All state checks passed. Mark purchase pending and start the slice purchase application.
         // Process through the handler since this method is synchronized.
         mPendingPurchaseCapabilities.put(capability, onComplete);
-        sendMessage(obtainMessage(EVENT_START_SLICE_PURCHASE_APP, capability, 0 /* unused */,
-                appName));
+        sendMessage(obtainMessage(EVENT_START_SLICE_PURCHASE_APP, capability));
     }
 
     private void sendPurchaseResult(@TelephonyManager.PremiumCapability int capability,
@@ -687,8 +682,8 @@
         }
     }
 
-    private void onStartSlicePurchaseApplication(@TelephonyManager.PremiumCapability int capability,
-            @NonNull String appName) {
+    private void onStartSlicePurchaseApplication(
+            @TelephonyManager.PremiumCapability int capability) {
         PremiumNetworkEntitlementResponse premiumNetworkEntitlementResponse =
                 mPremiumNetworkEntitlementApi.checkEntitlementStatus(capability);
 
@@ -721,7 +716,8 @@
         }
 
         String purchaseUrl = getPurchaseUrl(premiumNetworkEntitlementResponse);
-        if (TextUtils.isEmpty(purchaseUrl)) {
+        String carrier = getSimOperator();
+        if (TextUtils.isEmpty(purchaseUrl) || TextUtils.isEmpty(carrier)) {
             handlePurchaseResult(capability,
                     PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED, false);
             return;
@@ -753,7 +749,7 @@
         intent.putExtra(EXTRA_SUB_ID, mPhone.getSubId());
         intent.putExtra(EXTRA_PREMIUM_CAPABILITY, capability);
         intent.putExtra(EXTRA_PURCHASE_URL, purchaseUrl);
-        intent.putExtra(EXTRA_REQUESTING_APP_NAME, appName);
+        intent.putExtra(EXTRA_CARRIER, carrier);
         intent.putExtra(EXTRA_INTENT_CANCELED, createPendingIntent(
                 ACTION_SLICE_PURCHASE_APP_RESPONSE_CANCELED, capability, false));
         intent.putExtra(EXTRA_INTENT_CARRIER_ERROR, createPendingIntent(
@@ -805,6 +801,20 @@
     }
 
     /**
+     * Get the SIM operator. This is the carrier name from the SIM rather than from the network,
+     * which will be the same regardless of whether the user is roaming or not.
+     *
+     * @return The operator name from the SIM.
+     */
+    @VisibleForTesting
+    @Nullable public String getSimOperator() {
+        if (mPhone.getPhoneId() < TelephonyProperties.icc_operator_alpha().size()) {
+            return TelephonyProperties.icc_operator_alpha().get(mPhone.getPhoneId());
+        }
+        return null;
+    }
+
+    /**
      * Create the PendingIntent to allow the slice purchase application to send back responses.
      *
      * @param action The action that will be sent for this PendingIntent
@@ -819,6 +829,7 @@
         Intent intent = new Intent(action);
         intent.putExtra(EXTRA_PHONE_ID, mPhone.getPhoneId());
         intent.putExtra(EXTRA_PREMIUM_CAPABILITY, capability);
+        intent.setPackage(mPhone.getContext().getPackageName());
         return PendingIntent.getBroadcast(mPhone.getContext(), capability, intent,
                 PendingIntent.FLAG_CANCEL_CURRENT
                         | (mutable ? PendingIntent.FLAG_MUTABLE : PendingIntent.FLAG_IMMUTABLE));
@@ -1028,6 +1039,11 @@
     }
 
     private boolean isNetworkAvailable() {
+        if (mPhone.getServiceState().getDataRoaming()) {
+            logd("Network unavailable because it is roaming.");
+            return false;
+        }
+
         // TODO (b/251558673): Create a listener for data network type changed to dismiss
         //  notification and activity when the network is no longer available.
         switch (mPhone.getServiceState().getDataNetworkType()) {
diff --git a/src/com/android/phone/utils/CarrierAllowListInfo.java b/src/com/android/phone/utils/CarrierAllowListInfo.java
new file mode 100644
index 0000000..208eff3
--- /dev/null
+++ b/src/com/android/phone/utils/CarrierAllowListInfo.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone.utils;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
+import android.telephony.Rlog;
+import android.text.TextUtils;
+
+import com.android.internal.telephony.uicc.IccUtils;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class CarrierAllowListInfo {
+    private static final String LOG_TAG = "CarrierAllowListInfo";
+    private JSONObject mDataJSON;
+    private static final String JSON_CHARSET = "UTF-8";
+    private static final String MESSAGE_DIGEST_ALGORITHM = "SHA1";
+    private static final String CALLER_SHA_1_ID = "callerSHA1Id";
+    private static final String CALLER_CARRIER_ID = "carrierId";
+    public static final int INVALID_CARRIER_ID = -1;
+
+    private static final String CARRIER_RESTRICTION_OPERATOR_REGISTERED_FILE =
+            "CarrierRestrictionOperatorDetails.json";
+
+    private static CarrierAllowListInfo mInstance = null;
+    private Context mContext;
+
+    private CarrierAllowListInfo(Context context) {
+        mContext = context;
+        loadJsonFile(context);
+    }
+
+    public static CarrierAllowListInfo loadInstance(Context context) {
+        if (mInstance == null) {
+            mInstance = new CarrierAllowListInfo(context);
+        }
+        return mInstance;
+    }
+
+    public int validateCallerAndGetCarrierId(String packageName) {
+        CarrierInfo carrierInfo = parseJsonForCallerInfo(packageName);
+        boolean isValid = (carrierInfo != null) && validateCallerSignature(mContext, packageName,
+                carrierInfo.getSHAIdList());
+        return (isValid) ? carrierInfo.getCallerCarrierId() : INVALID_CARRIER_ID;
+    }
+
+    private void loadJsonFile(Context context) {
+        try {
+            String jsonString = getJsonFromAssets(context,
+                    CARRIER_RESTRICTION_OPERATOR_REGISTERED_FILE, JSON_CHARSET);
+            if (!TextUtils.isEmpty(jsonString)) {
+                mDataJSON = new JSONObject(jsonString);
+            }
+        } catch (Exception ex) {
+            Rlog.e(LOG_TAG, "CarrierAllowListInfo: JSON file reading exception = " + ex);
+        }
+    }
+
+    /**
+     * Parse the JSON object to fetch the given caller's SHA-Ids and carrierId.
+     */
+    private CarrierInfo parseJsonForCallerInfo(String callerPackage) {
+        try {
+            if (mDataJSON != null && callerPackage != null) {
+                JSONObject callerJSON = mDataJSON.getJSONObject(callerPackage.trim());
+                JSONArray callerJSONArray = callerJSON.getJSONArray(CALLER_SHA_1_ID);
+                int carrierId = callerJSON.getInt(CALLER_CARRIER_ID);
+                List<String> appSignatures = new ArrayList<>();
+                for (int index = 0; index < callerJSONArray.length(); index++) {
+                    appSignatures.add((String) callerJSONArray.get(index));
+                }
+                return new CarrierInfo(carrierId, appSignatures);
+            }
+        } catch (JSONException ex) {
+            Rlog.e(LOG_TAG, "getCallerSignatureInfo: JSONException = " + ex);
+        }
+        return null;
+    }
+
+    /**
+     * Read the Json file from the assert folder.
+     *
+     * @param context  context
+     * @param fileName JSON file name in assets folder
+     * @param charset  JSON file data format
+     * @return JSON file content in string format or null in case of IOException
+     */
+    private static String getJsonFromAssets(Context context, String fileName, String charset) {
+        String jsonStr;
+        try {
+            InputStream ipStream = context.getAssets().open(fileName);
+            int bufSize = ipStream.available();
+            byte[] fileBuffer = new byte[bufSize];
+            ipStream.read(fileBuffer);
+            ipStream.close();
+            jsonStr = new String(fileBuffer, charset);
+        } catch (IOException ex) {
+            Rlog.e(LOG_TAG, "getJsonFromAssets: Exception = " + ex);
+            return null;
+        }
+        return jsonStr;
+    }
+
+    /**
+     * API fetches all the related signatures of the given package from the packageManager
+     * and validate all the signatures.
+     *
+     * @param context             context
+     * @param packageName         package name of the caller to validate the signatures.
+     * @param allowListSignatures list of signatures to be validated.
+     * @return {@code true} if all the signatures are available with package manager.
+     * {@code false} if any one of the signatures won't match with package manager.
+     */
+    public static boolean validateCallerSignature(Context context, String packageName,
+            List<String> allowListSignatures) {
+        if (TextUtils.isEmpty(packageName) || allowListSignatures.size() == 0) {
+            // package name is mandatory
+            return false;
+        }
+        final PackageManager packageManager = context.getPackageManager();
+        try {
+            MessageDigest sha1MDigest = MessageDigest.getInstance(MESSAGE_DIGEST_ALGORITHM);
+            final PackageInfo packageInfo = packageManager.getPackageInfo(packageName,
+                    PackageManager.GET_SIGNATURES);
+            for (Signature signature : packageInfo.signatures) {
+                final byte[] signatureSha1 = sha1MDigest.digest(signature.toByteArray());
+                final String hexSignatureSha1 = IccUtils.bytesToHexString(signatureSha1);
+                if (!allowListSignatures.contains(hexSignatureSha1)) {
+                    return false;
+                }
+            }
+            return true;
+        } catch (NoSuchAlgorithmException | PackageManager.NameNotFoundException ex) {
+            Rlog.e(LOG_TAG, "validateCallerSignature: Exception = " + ex);
+            return false;
+        }
+    }
+
+    public int updateJsonForTest(String callerInfo) {
+        try {
+            if (callerInfo == null) {
+                // reset the Json content after testing
+                loadJsonFile(mContext);
+            } else {
+                mDataJSON = new JSONObject(callerInfo);
+            }
+            return 0;
+        } catch (JSONException ex) {
+            Rlog.e(LOG_TAG, "updateJsonForTest: Exception = " + ex);
+        }
+        return -1;
+    }
+
+    private static class CarrierInfo {
+        final private int mCallerCarrierId;
+        final private List<String> mSHAIdList;
+
+        public CarrierInfo(int carrierId, List<String> SHAIds) {
+            mCallerCarrierId = carrierId;
+            mSHAIdList = SHAIds;
+        }
+
+        public int getCallerCarrierId() {
+            return mCallerCarrierId;
+        }
+
+        public List<String> getSHAIdList() {
+            return mSHAIdList;
+        }
+    }
+}
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index d92b136..6650eac 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -275,6 +275,8 @@
 
         private PhoneAccount registerPstnPhoneAccount(boolean isEmergency, boolean isTestAccount) {
             PhoneAccount account = buildPstnPhoneAccount(mIsEmergency, mIsTestAccount);
+            Log.i(this, "registerPstnPhoneAccount: Registering account=%s with "
+                    + "Telecom. subId=%d", account, getSubId());
             // Register with Telecom and put into the account entry.
             mTelecomManager.registerPhoneAccount(account);
             return account;
@@ -1175,7 +1177,10 @@
         @Override
         public void onServiceStateChanged(ServiceState serviceState) {
             int newState = serviceState.getState();
+            Log.i(this, "onServiceStateChanged: newState=%d, mServiceState=%d",
+                    newState, mServiceState);
             if (newState == ServiceState.STATE_IN_SERVICE && mServiceState != newState) {
+                Log.i(this, "onServiceStateChanged: Tearing down and re-setting up accounts.");
                 tearDownAccounts();
                 setupAccounts();
             } else {
@@ -1622,6 +1627,7 @@
 
             // Add a fake account entry.
             if (DBG && phones.length > 0 && "TRUE".equals(System.getProperty("test_sim"))) {
+                Log.i(this, "setupAccounts: adding a fake AccountEntry");
                 mAccounts.add(new AccountEntry(phones[0], false /* emergency */,
                         true /* isTest */));
             }
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 1cf35a5..e278240 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -2494,6 +2494,7 @@
 
                         if (mTelephonyConnectionService.maybeReselectDomain(this,
                                   mOriginalConnection.getPreciseDisconnectCause(), reasonInfo)) {
+                            clearOriginalConnection();
                             break;
                         }
                     }
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 0b71feb..09b9b6d 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -532,7 +532,17 @@
      */
     private final TelephonyConnection.TelephonyConnectionListener mEmergencyConnectionListener =
             new TelephonyConnection.TelephonyConnectionListener() {
-        @Override
+                @Override
+                public void onOriginalConnectionConfigured(TelephonyConnection c) {
+                    com.android.internal.telephony.Connection origConn = c.getOriginalConnection();
+                    if (origConn == null) return;
+                    // Update the domain in the case that it changes,for example during initial
+                    // setup or when there was an srvcc or internal redial.
+                    mEmergencyStateTracker.onEmergencyCallDomainUpdated(
+                            origConn.getPhoneType(), c.getTelecomCallId());
+                }
+
+                @Override
         public void onStateChanged(Connection connection, @Connection.ConnectionState int state) {
             if (connection != null) {
                 TelephonyConnection c = (TelephonyConnection) connection;
@@ -557,13 +567,22 @@
                         Connection connection, @Connection.ConnectionState int state) {
                     TelephonyConnection c = (TelephonyConnection) connection;
                     if (c != null) {
-                        if (c.getState() == Connection.STATE_ACTIVE) {
-                            Log.d(LOG_TAG, "Call State->ACTIVE."
-                                    + "Clearing DomainSelectionConnection");
-                            c.removeTelephonyConnectionListener(mNormalCallConnectionListener);
-                            mDomainSelectionConnection.finishSelection();
-                            mDomainSelectionConnection = null;
-                            mNormalCallConnection = null;
+                        switch(c.getState()) {
+                            case Connection.STATE_ACTIVE: {
+                                Log.d(LOG_TAG, "Call State->ACTIVE."
+                                        + "Clearing DomainSelectionConnection");
+                                if (mDomainSelectionConnection != null) {
+                                    mDomainSelectionConnection.finishSelection();
+                                    mDomainSelectionConnection = null;
+                                }
+                                mNormalCallConnection = null;
+                            }
+                            break;
+
+                            case Connection.STATE_DISCONNECTED: {
+                                c.removeTelephonyConnectionListener(mNormalCallConnectionListener);
+                            }
+                            break;
                         }
                     }
                 }
@@ -590,36 +609,40 @@
             new DomainSelectionConnection.DomainSelectionConnectionCallback() {
                 @Override
                 public void onSelectionTerminated(@DisconnectCauses int cause) {
-                    Log.v(this, "Call domain selection terminated.");
-                    if (mDomainSelectionConnection != null) {
-                        mDomainSelectionConnection = null;
-                    }
-
-                    if (mNormalCallConnection != null) {
-                        // TODO: To support ShowPreciseFailedCause,
-                        //  TelephonyConnection.getShowPreciseFailedCause API should be added.
-
-                        // If cause is NOT_VALID then, it's a redial cancellation and use cause
-                        // code from original connection.
-                        com.android.internal.telephony.Connection connection =
-                                mNormalCallConnection.getOriginalConnection();
-                        if (connection != null) {
-                            if (cause == android.telephony.DisconnectCause.NOT_VALID) {
-                                cause = connection.getDisconnectCause();
+                    mDomainSelectionMainExecutor.execute(new Runnable() {
+                        int mCause = cause;
+                        @Override
+                        public void run() {
+                            Log.v(this, "Call domain selection terminated.");
+                            if (mDomainSelectionConnection != null) {
+                                mDomainSelectionConnection = null;
                             }
+                            if (mNormalCallConnection != null) {
+                                // TODO: To support ShowPreciseFailedCause, TelephonyConnection
+                                //  .getShowPreciseFailedCause API should be added.
 
-                            String reason = connection.getVendorDisconnectCause();
+                                // If cause is NOT_VALID then, it's a redial cancellation and
+                                // use cause code from original connection.
+                                com.android.internal.telephony.Connection connection =
+                                        mNormalCallConnection.getOriginalConnection();
+                                if (connection != null) {
+                                    if (mCause == android.telephony.DisconnectCause.NOT_VALID) {
+                                        mCause = connection.getDisconnectCause();
+                                    }
 
-                            mNormalCallConnection.setTelephonyConnectionDisconnected(
-                                    mDisconnectCauseFactory.toTelecomDisconnectCause(
-                                            cause, reason));
-                            Log.d(this, "Call connection closed. Cause: " + cause
-                                    + " Reason: " + reason);
+                                    String reason = connection.getVendorDisconnectCause();
+                                    int phoneId = mNormalCallConnection.getPhone().getPhoneId();
+                                    mNormalCallConnection.setTelephonyConnectionDisconnected(
+                                            mDisconnectCauseFactory.toTelecomDisconnectCause(
+                                                    mCause, reason, phoneId));
+                                    Log.d(this, "Call connection closed. Cause: " + mCause
+                                            + " Reason: " + reason);
+                                }
+                                mNormalCallConnection.close();
+                                mNormalCallConnection = null;
+                            }
                         }
-                        mNormalCallConnection.close();
-                        mNormalCallConnection = null;
-                    }
-
+                    });
                 }
             };
 
@@ -932,7 +955,8 @@
                 handle == null ? null : handle.getSchemeSpecificPart());
 
         if (mDomainSelectionResolver.isDomainSelectionSupported()) {
-            if (isEmergencyNumber) {
+            // Normal routing emergency number shall be handled by normal call domain selctor.
+            if (isEmergencyNumber && !isNormalRouting(phone, number)) {
                 final Connection resultConnection =
                         placeEmergencyConnection(phone,
                                 request, numberToDial, isTestEmergencyNumber,
@@ -1942,6 +1966,16 @@
                             }
                         }
                     }
+                    if (mDomainSelectionResolver.isDomainSelectionSupported()) {
+                        if (isNormalRouting(phone, number)
+                                    && handleOutgoingCallConnection(number, connection,
+                                            phone, videoState)) {
+                            /** Normal routing emergency number shall be handled
+                             * by normal call domain selctor.*/
+                            Log.i(this, "placeOutgoingConnection normal routing number");
+                            return;
+                        }
+                    }
                 } else if (handleOutgoingCallConnection(number, connection,
                         phone, videoState)) {
                     return;
@@ -2017,6 +2051,8 @@
                                         .setVideoState(videoState)
                                         .setIntentExtras(extras)
                                         .setRttTextStream(mNormalCallConnection.getRttTextStream())
+                                        .setIsWpsCall(NormalCallDomainSelectionConnection
+                                                .isWpsCall(number))
                                         .build(),
                                 mNormalCallConnection::registerForCallEvents);
 
@@ -2043,8 +2079,10 @@
                             e.getMessage(), phone.getPhoneId()));
             mNormalCallConnection.close();
         }
-        mDomainSelectionConnection.finishSelection();
-        mDomainSelectionConnection = null;
+        if (mDomainSelectionConnection != null) {
+            mDomainSelectionConnection.finishSelection();
+            mDomainSelectionConnection = null;
+        }
         mNormalCallConnection = null;
     }
 
@@ -2055,6 +2093,10 @@
             return false;
         }
 
+        if (phone == null) {
+            return false;
+        }
+
         String dialPart = PhoneNumberUtils.extractNetworkPortionAlt(
                 PhoneNumberUtils.stripSeparators(number));
         boolean isMmiCode = (dialPart.startsWith("*") || dialPart.startsWith("#"))
@@ -2064,9 +2106,21 @@
         // If the number is both an MMI code and a supplementary service code,
         // it shall be treated as UT. In this case, domain selection is not performed.
         if (isMmiCode && isSuppServiceCode) {
+            Log.v(LOG_TAG, "UT code not handled by call domain selection.");
             return false;
         }
 
+        // Check and select same domain as ongoing call on the same subscription (if exists)
+        int activeCallDomain = getActiveCallDomain(phone.getSubId());
+        if (activeCallDomain != NetworkRegistrationInfo.DOMAIN_UNKNOWN
+                && !NormalCallDomainSelectionConnection.isWpsCall(number)) {
+            Log.d(LOG_TAG, "Selecting same domain as ongoing call on same subId");
+            mNormalCallConnection = connection;
+            handleOutgoingCallConnectionByCallDomainSelection(
+                    activeCallDomain, phone, number, videoState);
+            return true;
+        }
+
         mDomainSelectionConnection = mDomainSelectionResolver
                 .getDomainSelectionConnection(phone, SELECTOR_TYPE_CALLING, false);
         if (mDomainSelectionConnection == null) {
@@ -2076,6 +2130,7 @@
         SelectionAttributes selectionAttributes =
                 new SelectionAttributes.Builder(phone.getPhoneId(), phone.getSubId(),
                         SELECTOR_TYPE_CALLING)
+                        .setNumber(number)
                         .setEmergency(false)
                         .setVideoCall(VideoProfile.isVideo(videoState))
                         .build();
@@ -2243,7 +2298,7 @@
 
         if (reasonInfo != null
                 && reasonInfo.getCode() == ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL) {
-            onEmergencyRedial(c, c.getPhone());
+            onEmergencyRedial(c, c.getPhone().getDefaultPhone());
             return true;
         }
 
@@ -2278,7 +2333,7 @@
             if (future != null) {
                 future.thenAcceptAsync((result) -> {
                     Log.d(this, "reselectDomain-complete");
-                    onEmergencyRedialOnDomain(c, c.getPhone(), result);
+                    onEmergencyRedialOnDomain(c, c.getPhone().getDefaultPhone(), result);
                 }, mDomainSelectionMainExecutor);
                 return true;
             }
@@ -2292,6 +2347,17 @@
         return false;
     }
 
+    private boolean isNormalRouting(Phone phone, String number) {
+        if (phone.getEmergencyNumberTracker() != null) {
+            EmergencyNumber num = phone.getEmergencyNumberTracker().getEmergencyNumber(number);
+            if (num != null) {
+                return num.getEmergencyCallRouting()
+                        == EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL;
+            }
+        }
+        return false;
+    }
+
     private boolean maybeReselectDomainForNormalCall(
             final TelephonyConnection c, int callFailCause, ImsReasonInfo reasonInfo) {
 
@@ -2308,6 +2374,7 @@
                             callFailCause, reasonInfo);
 
             Log.d(LOG_TAG, "Reselecting the domain for call");
+            mNormalCallConnection = c;
             CompletableFuture<Integer> future = mDomainSelectionConnection
                     .reselectDomain(selectionAttributes);
             if (future != null) {
@@ -2324,7 +2391,7 @@
             mDomainSelectionConnection = null;
         }
         mNormalCallConnection = null;
-        Log.d(LOG_TAG, "Reselecting the domain for call failed");
+        Log.d(LOG_TAG, "Reselect call domain not triggered.");
         return false;
     }
 
@@ -3454,4 +3521,25 @@
                     }
                 });
     }
+
+    private @NetworkRegistrationInfo.Domain int getActiveCallDomain(int subId) {
+        for (Connection c: getAllConnections()) {
+            if ((c instanceof TelephonyConnection)) {
+                TelephonyConnection connection = (TelephonyConnection) c;
+                Phone phone = connection.getPhone();
+                if (phone == null) {
+                    continue;
+                }
+
+                if (phone.getSubId() == subId) {
+                    if (phone instanceof GsmCdmaPhone) {
+                        return NetworkRegistrationInfo.DOMAIN_CS;
+                    } else if (phone instanceof ImsPhone) {
+                        return NetworkRegistrationInfo.DOMAIN_PS;
+                    }
+                }
+            }
+        }
+        return NetworkRegistrationInfo.DOMAIN_UNKNOWN;
+    }
 }
diff --git a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
index 9aaf6da..fa11a5d 100644
--- a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
@@ -41,14 +41,22 @@
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL;
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL;
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_SCAN_TIMER_SEC_INT;
+import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT;
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT;
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL;
 import static android.telephony.CarrierConfigManager.ImsEmergency.SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_SETTING_ENABLED;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_VALID_EID;
+import static android.telephony.CarrierConfigManager.ImsWfc.KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL;
 import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME;
 import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING;
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
 import android.os.CancellationSignal;
 import android.os.Looper;
 import android.os.Message;
@@ -69,6 +77,7 @@
 import android.telephony.TransportSelectorCallback;
 import android.telephony.ims.ImsManager;
 import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ProvisioningManager;
 import android.text.TextUtils;
 import android.util.LocalLog;
 
@@ -97,6 +106,30 @@
 
     private static final LocalLog sLocalLog = new LocalLog(LOG_SIZE);
 
+    /**
+     * Network callback used to determine whether Wi-Fi is connected or not.
+     */
+    private ConnectivityManager.NetworkCallback mNetworkCallback =
+            new ConnectivityManager.NetworkCallback() {
+                @Override
+                public void onAvailable(Network network) {
+                    logi("onAvailable: " + network);
+                    mWiFiAvailable = true;
+                }
+
+                @Override
+                public void onLost(Network network) {
+                    logi("onLost: " + network);
+                    mWiFiAvailable = false;
+                }
+
+                @Override
+                public void onUnavailable() {
+                    logi("onUnavailable");
+                    mWiFiAvailable = false;
+                }
+            };
+
     private boolean mIsEmergencyBarred;
     private boolean mImsRegistered;
     private boolean mIsVoiceCapable;
@@ -122,10 +155,14 @@
     private @CarrierConfigManager.ImsEmergency.EmergencyDomain int[] mDomainPreferenceRoam;
     private List<String> mCdmaPreferredNumbers;
     private boolean mPreferImsWhenCallsOnCs;
+    private int mVoWifiRequiresCondition;
+    private boolean mIsMonitoringConnectivity;
+    private boolean mWiFiAvailable;
     private int mScanTimeout;
     private int mMaxNumOfVoWifiTries;
+    private boolean mVoWifiOverEmergencyPdn;
     private @CarrierConfigManager.ImsEmergency.EmergencyScanType int mPreferredNetworkScanType;
-    private int mCallSetupTimerOnCurrentRatSec;
+    private int mCallSetupTimerOnCurrentRat;
     private boolean mRequiresImsRegistration;
     private boolean mRequiresVoLteEnabled;
     private boolean mLtePreferredAfterNrFailure;
@@ -221,8 +258,14 @@
 
     @Override
     public void reselectDomain(SelectionAttributes attr) {
-        logi("reselectDomain tryCsWhenPsFails=" + mTryCsWhenPsFails + ", attr=" + attr);
+        logi("reselectDomain attr=" + attr);
         mSelectionAttributes = attr;
+        post(() -> { reselectDomain(); });
+    }
+
+    private void reselectDomain() {
+        logi("reselectDomain tryCsWhenPsFails=" + mTryCsWhenPsFails);
+
         if (mTryCsWhenPsFails) {
             mTryCsWhenPsFails = false;
             mCsNetworkType = getSelectableCsNetworkType();
@@ -231,20 +274,11 @@
                 onWwanNetworkTypeSelected(mCsNetworkType);
                 return;
             }
-        } else if (getImsNetworkTypeConfiguration().isEmpty()
-                || (mRequiresVoLteEnabled && !isAdvancedCallingSettingEnabled())) {
-            // Emergency call over IMS is not supported.
-            mCsNetworkType = UTRAN;
-            onWwanNetworkTypeSelected(mCsNetworkType);
-            return;
         }
 
         if (mLastTransportType == TRANSPORT_TYPE_WLAN) {
             // Dialing over Wi-Fi failed. Try scanning cellular networks.
-            onWwanSelected(() -> {
-                requestScan(true, false, true);
-                mDomainSelected = false;
-            });
+            onWwanSelected(this::reselectDomainInternal);
             return;
         }
 
@@ -252,6 +286,13 @@
         mDomainSelected = false;
     }
 
+    private void reselectDomainInternal() {
+        post(() -> {
+            requestScan(true, false, true);
+            mDomainSelected = false;
+        });
+    }
+
     @Override
     public void finishSelection() {
         logi("finishSelection");
@@ -343,11 +384,13 @@
         mDomainPreferenceRoam = b.getIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_ROAMING_INT_ARRAY);
         mPreferImsWhenCallsOnCs = b.getBoolean(
                 KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL);
-        mScanTimeout = b.getInt(KEY_EMERGENCY_SCAN_TIMER_SEC_INT);
+        mVoWifiRequiresCondition = b.getInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT);
+        mScanTimeout = b.getInt(KEY_EMERGENCY_SCAN_TIMER_SEC_INT) * 1000;
         mMaxNumOfVoWifiTries = b.getInt(KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT);
+        mVoWifiOverEmergencyPdn = b.getBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL);
         mPreferredNetworkScanType = b.getInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT);
-        mCallSetupTimerOnCurrentRatSec = b.getInt(
-                KEY_EMERGENCY_CALL_SETUP_TIMER_ON_CURRENT_NETWORK_SEC_INT);
+        mCallSetupTimerOnCurrentRat = b.getInt(
+                KEY_EMERGENCY_CALL_SETUP_TIMER_ON_CURRENT_NETWORK_SEC_INT) * 1000;
         mRequiresImsRegistration = b.getBoolean(KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL);
         mRequiresVoLteEnabled = b.getBoolean(KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL);
         mLtePreferredAfterNrFailure = b.getBoolean(
@@ -376,11 +419,13 @@
                 + ", domainPrefRoam=" + arrayToString(mDomainPreferenceRoam,
                         EmergencyCallDomainSelector::domainPreferenceToString)
                 + ", preferImsOnCs=" + mPreferImsWhenCallsOnCs
+                + ", voWifiRequiresCondition=" + mVoWifiRequiresCondition
                 + ", scanTimeout=" + mScanTimeout
                 + ", maxNumOfVoWifiTries=" + mMaxNumOfVoWifiTries
+                + ", voWifiOverEmergencyPdn=" + mVoWifiOverEmergencyPdn
                 + ", preferredScanType=" + carrierConfigNetworkScanTypeToString(
                         mPreferredNetworkScanType)
-                + ", callSetupTimer=" + mCallSetupTimerOnCurrentRatSec
+                + ", callSetupTimer=" + mCallSetupTimerOnCurrentRat
                 + ", requiresImsReg=" + mRequiresImsRegistration
                 + ", requiresVoLteEnabled=" + mRequiresVoLteEnabled
                 + ", ltePreferredAfterNr=" + mLtePreferredAfterNrFailure
@@ -422,14 +467,10 @@
     }
 
     private void selectDomainInternal() {
-        if (getImsNetworkTypeConfiguration().isEmpty()
-                || (mRequiresVoLteEnabled && !isAdvancedCallingSettingEnabled())) {
-            // Emergency call over IMS is not supported.
-            mCsNetworkType = UTRAN;
-            onWwanNetworkTypeSelected(mCsNetworkType);
-            return;
-        }
+        post(this::selectDomainFromInitialState);
+    }
 
+    private void selectDomainFromInitialState() {
         boolean csInService = isCsInService();
         boolean psInService = isPsInService();
 
@@ -546,6 +587,7 @@
                 // remove any pending timers.
                 removeMessages(MSG_NETWORK_SCAN_TIMEOUT);
                 sendEmptyMessageDelayed(MSG_NETWORK_SCAN_TIMEOUT, mScanTimeout);
+                registerForConnectivityChanges();
             }
         }
     }
@@ -557,6 +599,12 @@
      * @return The list of preferred network types.
      */
     private @RadioAccessNetworkType List<Integer> getNextPreferredNetworks(boolean csPreferred) {
+        if (mRequiresVoLteEnabled && !isAdvancedCallingSettingEnabled()) {
+            // Emergency call over IMS is not supported.
+            logi("getNextPreferredNetworks VoLte setting is not enabled.");
+            return generatePreferredNetworks(getCsNetworkTypeConfiguration());
+        }
+
         List<Integer> preferredNetworks = new ArrayList<>();
 
         List<Integer> domains = getDomainPreference();
@@ -625,8 +673,33 @@
     }
 
     private void handleNetworkScanTimeout() {
-        if (isImsRegisteredWithVoiceCapability()
-                && isImsRegisteredOverWifi()) {
+        logi("handleNetworkScanTimeout overEmergencyPdn=" + mVoWifiOverEmergencyPdn
+                + ", wifiAvailable=" + mWiFiAvailable);
+        boolean available = mWiFiAvailable;
+        if (mVoWifiOverEmergencyPdn) {
+            // SOS APN
+            if (!available && isImsRegisteredOverCrossSim()) {
+                available = true;
+            }
+            if (available) {
+                switch (mVoWifiRequiresCondition) {
+                    case VOWIFI_REQUIRES_SETTING_ENABLED:
+                        available = isWifiCallingSettingEnabled();
+                        break;
+                    case VOWIFI_REQUIRES_VALID_EID:
+                        available = isWifiCallingActivated();
+                        break;
+                    default:
+                        break;
+                }
+            }
+        } else {
+            // IMS APN. When IMS is already registered over Wi-Fi.
+            available = isImsRegisteredWithVoiceCapability() && isImsRegisteredOverWifi();
+        }
+
+        logi("handleNetworkScanTimeout VoWi-Fi available=" + available);
+        if (available) {
             if (mCancelSignal != null) {
                 mCancelSignal.cancel();
                 mCancelSignal = null;
@@ -674,7 +747,7 @@
 
         if ((regResult.getAccessNetwork() == EUTRAN)
                 && ((regResult.getDomain() & NetworkRegistrationInfo.DOMAIN_CS) > 0)) {
-            return UTRAN;
+            if (ratList.contains(UTRAN)) return UTRAN;
         }
 
         return UNKNOWN;
@@ -710,6 +783,11 @@
         EmergencyRegResult regResult = mSelectionAttributes.getEmergencyRegResult();
         logi("getSelectablePsNetworkType regResult=" + regResult);
         if (regResult == null) return UNKNOWN;
+        if (mRequiresVoLteEnabled && !isAdvancedCallingSettingEnabled()) {
+            // Emergency call over IMS is not supported.
+            logi("getSelectablePsNetworkType VoLte setting is not enabled.");
+            return UNKNOWN;
+        }
 
         int accessNetwork = regResult.getAccessNetwork();
         List<Integer> ratList = getImsNetworkTypeConfiguration();
@@ -797,6 +875,41 @@
         return true;
     }
 
+    private boolean isWifiCallingActivated() {
+        try {
+            ImsManager imsMngr = mContext.getSystemService(ImsManager.class);
+            ProvisioningManager pm = imsMngr.getProvisioningManager(getSubId());
+            String eid = pm.getProvisioningStringValue(
+                    ProvisioningManager.KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID);
+            boolean activated = (!TextUtils.isEmpty(eid)) && (!TextUtils.equals("0", eid));
+            logi("isWifiCallingActivated " + activated);
+            return activated;
+        } catch (Exception e) {
+            logi("isWifiCallingActivated e=" + e);
+        }
+        return false;
+    }
+
+    private boolean isWifiCallingSettingEnabled() {
+        boolean result = false;
+        try {
+            if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
+                ImsManager imsMngr = mContext.getSystemService(ImsManager.class);
+                ImsMmTelManager mmTelManager = imsMngr.getImsMmTelManager(getSubId());
+                if (isInRoaming()) {
+                    result = mmTelManager.isVoWiFiRoamingSettingEnabled();
+                } else {
+                    result = mmTelManager.isVoWiFiSettingEnabled();
+                }
+                logi("isWifiCallingSettingEnabled " + result);
+                return result;
+            }
+        } catch (Exception e) {
+            logi("isWifiCallingSettingEnabled e=" + e);
+        }
+        return result;
+    }
+
     private @NonNull List<Integer> getImsNetworkTypeConfiguration() {
         int[] rats = mImsRatsConfig;
         if (isInRoaming()) rats = mImsRoamRatsConfig;
@@ -883,6 +996,21 @@
     }
 
     /**
+     * Determines whether IMS is registered over the mobile data of another subscription.
+     *
+     * @return {@code true} if IMS is registered over the mobile data of another subscription.
+     */
+    private boolean isImsRegisteredOverCrossSim() {
+        boolean ret = false;
+        if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
+            ret = mImsStateTracker.isImsRegisteredOverCrossSim();
+        }
+
+        logi("isImsRegisteredOverCrossSim " + ret);
+        return ret;
+    }
+
+    /**
      * Determines whether IMS is registered with voice capability.
      *
      * @return {@code true} if IMS is registered with voice capability.
@@ -896,6 +1024,12 @@
 
     private void onWlanSelected() {
         logi("onWlanSelected");
+        if (mLastTransportType == TRANSPORT_TYPE_WLAN) {
+            logi("onWlanSelected ignore duplicated callback");
+            return;
+        }
+
+        mDomainSelected = true;
         mLastTransportType = TRANSPORT_TYPE_WLAN;
         mVoWifiTrialCount++;
         mTransportSelectorCallback.onWlanSelected();
@@ -904,10 +1038,8 @@
 
     private void onWwanSelected(Runnable runnable) {
         logi("onWwanSelected");
-        if (mLastTransportType == TRANSPORT_TYPE_WWAN
-                && mWwanSelectorCallback != null) {
-            logi("onWwanSelected already notified");
-            runnable.run();
+        if (mLastTransportType == TRANSPORT_TYPE_WWAN) {
+            logi("onWwanSelected ignore duplicated callback");
             return;
         }
 
@@ -934,6 +1066,40 @@
         mWwanSelectorCallback.onDomainSelected(domain);
     }
 
+    /**
+     * Registers for changes to network connectivity.
+     */
+    private void registerForConnectivityChanges() {
+        if (mIsMonitoringConnectivity) {
+            return;
+        }
+
+        ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+        if (cm != null) {
+            logi("registerForConnectivityChanges");
+            NetworkRequest.Builder builder = new NetworkRequest.Builder();
+            builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+            cm.registerNetworkCallback(builder.build(), mNetworkCallback);
+            mIsMonitoringConnectivity = true;
+        }
+    }
+
+    /**
+     * Unregisters for connectivity changes.
+     */
+    private void unregisterForConnectivityChanges() {
+        if (!mIsMonitoringConnectivity) {
+            return;
+        }
+
+        ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+        if (cm != null) {
+            logi("unregisterForConnectivityChanges");
+            cm.unregisterNetworkCallback(mNetworkCallback);
+            mIsMonitoringConnectivity = false;
+        }
+    }
+
     private static String arrayToString(int[] intArray, IntFunction<String> func) {
         int length = intArray.length;
         StringBuilder sb = new StringBuilder("{");
@@ -1009,6 +1175,7 @@
         mDestroyed = true;
         mImsStateTracker.removeBarringInfoListener(this);
         mImsStateTracker.removeImsStateListener(this);
+        unregisterForConnectivityChanges();
 
         super.destroy();
     }
diff --git a/src/com/android/services/telephony/domainselection/ImsStateTracker.java b/src/com/android/services/telephony/domainselection/ImsStateTracker.java
index e1d0d31..fc3f811 100644
--- a/src/com/android/services/telephony/domainselection/ImsStateTracker.java
+++ b/src/com/android/services/telephony/domainselection/ImsStateTracker.java
@@ -130,6 +130,7 @@
     /** The IMS registration state and the network type that performed IMS registration. */
     private Boolean mImsRegistered;
     private @RadioAccessNetworkType int mImsAccessNetworkType = AccessNetworkType.UNKNOWN;
+    private Boolean mImsRegisteredOverCrossSim;
     /** The MMTEL capabilities - Voice, Video, SMS, and Ut. */
     private MmTelCapabilities mMmTelCapabilities;
     private final Runnable mMmTelFeatureUnavailableRunnable = new Runnable() {
@@ -361,6 +362,13 @@
     }
 
     /**
+     * Returns {@code true} if IMS is registered over the mobile data of another subscription.
+     */
+    public boolean isImsRegisteredOverCrossSim() {
+        return mImsRegisteredOverCrossSim != null && mImsRegisteredOverCrossSim;
+    }
+
+    /**
      * Returns {@code true} if IMS voice call is capable, {@code false} otherwise.
      */
     public boolean isImsVoiceCapable() {
@@ -406,6 +414,7 @@
         mMmTelFeatureAvailable = null;
         mImsRegistered = null;
         mImsAccessNetworkType = AccessNetworkType.UNKNOWN;
+        mImsRegisteredOverCrossSim = null;
         mMmTelCapabilities = null;
     }
 
@@ -418,6 +427,7 @@
         setMmTelFeatureAvailable(false);
         setImsRegistered(false);
         setImsAccessNetworkType(AccessNetworkType.UNKNOWN);
+        setImsRegisteredOverCrossSim(false);
         setMmTelCapabilities(new MmTelCapabilities());
     }
 
@@ -450,6 +460,13 @@
         }
     }
 
+    private void setImsRegisteredOverCrossSim(boolean crossSim) {
+        if (!Objects.equals(mImsRegisteredOverCrossSim, Boolean.valueOf(crossSim))) {
+            logi("setImsRegisteredOverCrossSim: " + mImsRegisteredOverCrossSim + " >> " + crossSim);
+            mImsRegisteredOverCrossSim = Boolean.valueOf(crossSim);
+        }
+    }
+
     /**
      * Notifies the specified listener of the current IMS state if it's valid.
      *
@@ -548,6 +565,8 @@
             setImsStateAsUnavailable();
             unregisterImsRegistrationCallback();
             unregisterMmTelCapabilityCallback();
+            // ImsStateCallback has already been removed after calling onUnavailable.
+            mImsStateCallback = null;
             notifyImsMmTelFeatureAvailableChanged();
         } else {
             logw("onMmTelFeatureUnavailable: unexpected reason=" + reason);
@@ -563,6 +582,8 @@
         setImsRegistered(true);
         setImsAccessNetworkType(
                 imsRegTechToAccessNetworkType(attributes.getRegistrationTechnology()));
+        setImsRegisteredOverCrossSim(attributes.getRegistrationTechnology()
+                == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM);
         notifyImsRegistrationStateChanged();
     }
 
@@ -573,6 +594,7 @@
         logd("onImsUnregistered: " + info);
         setImsRegistered(false);
         setImsAccessNetworkType(AccessNetworkType.UNKNOWN);
+        setImsRegisteredOverCrossSim(false);
         setMmTelCapabilities(new MmTelCapabilities());
         notifyImsRegistrationStateChanged();
     }
@@ -773,6 +795,7 @@
             case ImsRegistrationImplBase.REGISTRATION_TECH_NR:
                 return AccessNetworkType.NGRAN;
             case ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN:
+            case ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM:
                 return AccessNetworkType.IWLAN;
             default:
                 return AccessNetworkType.UNKNOWN;
diff --git a/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java b/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
index 146874c..3da0044 100644
--- a/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
@@ -21,7 +21,10 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.os.Looper;
+import android.os.PersistableBundle;
+import android.telecom.TelecomManager;
 import android.telephony.Annotation.DisconnectCauses;
+import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
 import android.telephony.DomainSelectionService.SelectionAttributes;
 import android.telephony.NetworkRegistrationInfo;
@@ -30,6 +33,8 @@
 import android.telephony.TransportSelectorCallback;
 import android.telephony.ims.ImsReasonInfo;
 
+import com.android.internal.telephony.domainselection.NormalCallDomainSelectionConnection;
+
 /**
  * Implements domain selector for outgoing non-emergency calls.
  */
@@ -131,14 +136,16 @@
 
     @Override
     public void onImsRegistrationStateChanged() {
-        logd("onImsRegistrationStateChanged");
+        logd("onImsRegistrationStateChanged. IsImsRegistered: "
+                + mImsStateTracker.isImsRegistered());
         mImsRegStateReceived = true;
         selectDomain();
     }
 
     @Override
     public void onImsMmTelCapabilitiesChanged() {
-        logd("onImsMmTelCapabilitiesChanged");
+        logd("onImsMmTelCapabilitiesChanged. ImsVoiceCap: " + mImsStateTracker.isImsVoiceCapable()
+                + " ImsVideoCap: " + mImsStateTracker.isImsVideoCapable());
         mMmTelCapabilitiesReceived = true;
         selectDomain();
     }
@@ -221,6 +228,54 @@
                 || mServiceState.getState() == ServiceState.STATE_EMERGENCY_ONLY);
     }
 
+    private boolean isWpsCallSupportedByIms() {
+        CarrierConfigManager configManager = mContext.getSystemService(CarrierConfigManager.class);
+
+        PersistableBundle config = null;
+        if (configManager != null) {
+            config = configManager.getConfigForSubId(mSelectionAttributes.getSubId());
+        }
+
+        return (config != null)
+                ? config.getBoolean(CarrierConfigManager.KEY_SUPPORT_WPS_OVER_IMS_BOOL) : false;
+    }
+
+    private void handleWpsCall() {
+        if (isWpsCallSupportedByIms()) {
+            logd("WPS call placed over PS");
+            notifyPsSelected();
+        } else {
+            if (isOutOfService()) {
+                loge("Cannot place call in current ServiceState: " + mServiceState.getState());
+                notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
+            } else {
+                logd("WPS call placed over CS");
+                notifyCsSelected();
+            }
+        }
+    }
+
+    private boolean isTtySupportedByIms() {
+        CarrierConfigManager configManager = mContext.getSystemService(CarrierConfigManager.class);
+
+        PersistableBundle config = null;
+        if (configManager != null) {
+            config = configManager.getConfigForSubId(mSelectionAttributes.getSubId());
+        }
+
+        return (config != null)
+                && config.getBoolean(CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL);
+    }
+
+    private boolean isTtyModeEnabled() {
+        TelecomManager tm = mContext.getSystemService(TelecomManager.class);
+        if (tm == null) {
+            loge("isTtyModeEnabled: telecom not available");
+            return false;
+        }
+        return tm.getCurrentTtyMode() != TelecomManager.TTY_MODE_OFF;
+    }
+
     private synchronized void selectDomain() {
         if (mStopDomainSelection || mSelectionAttributes == null
                 || mTransportSelectorCallback == null) {
@@ -265,49 +320,71 @@
             return;
         }
 
-        if (mImsStateTracker.isMmTelFeatureAvailable()) {
-
-            if (!mImsRegStateReceived || !mMmTelCapabilitiesReceived) {
-                loge("Waiting for ImsState and MmTelCapabilities callbacks");
-                return;
+        if (!mImsStateTracker.isMmTelFeatureAvailable()) {
+            logd("MmTelFeatureAvailable unavailable");
+            if (isOutOfService()) {
+                loge("Cannot place call in current ServiceState: " + mServiceState.getState());
+                notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
+            } else {
+                notifyCsSelected();
             }
+            return;
+        }
 
-            if (!mImsStateTracker.isImsRegistered()) {
-                logd("IMS is NOT registered");
-                if (isOutOfService()) {
-                    loge("Cannot place call in current ServiceState: " + mServiceState.getState());
-                    notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
-                } else {
-                    notifyCsSelected();
-                }
-                return;
+        if (!mImsRegStateReceived || !mMmTelCapabilitiesReceived) {
+            loge("Waiting for ImsState and MmTelCapabilities callbacks");
+            return;
+        }
+
+        // Check IMS registration state.
+        if (!mImsStateTracker.isImsRegistered()) {
+            logd("IMS is NOT registered");
+            if (isOutOfService()) {
+                loge("Cannot place call in current ServiceState: " + mServiceState.getState());
+                notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
+            } else {
+                notifyCsSelected();
             }
+            return;
+        }
 
-            if (mSelectionAttributes.isVideoCall()) {
-                logd("It's a video call");
-                if (mImsStateTracker.isImsVideoCapable()) {
-                    logd("IMS is video capable");
-                    notifyPsSelected();
-                } else {
-                    logd("IMS is not video capable. Ending the call");
-                    notifySelectionTerminated(DisconnectCause.OUTGOING_FAILURE);
-                }
-            } else if (mImsStateTracker.isImsVoiceCapable()) {
-                logd("IMS is voice capable");
-                // Voice call over PS
+        // Check TTY
+        if (isTtyModeEnabled() && !isTtySupportedByIms()) {
+            if (isOutOfService()) {
+                loge("Cannot place call in current ServiceState: " + mServiceState.getState());
+                notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
+            } else {
+                notifyCsSelected();
+            }
+            return;
+        }
+
+        // Handle video call.
+        if (mSelectionAttributes.isVideoCall()) {
+            logd("It's a video call");
+            if (mImsStateTracker.isImsVideoCapable()) {
+                logd("IMS is video capable");
                 notifyPsSelected();
             } else {
-                logd("IMS is not voice capable");
-                // Voice call CS fallback
-                if (isOutOfService()) {
-                    loge("Cannot place call in current ServiceState: " + mServiceState.getState());
-                    notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
-                } else {
-                    notifyCsSelected();
-                }
+                logd("IMS is not video capable. Ending the call");
+                notifySelectionTerminated(DisconnectCause.OUTGOING_FAILURE);
+            }
+            return;
+        }
+
+        // Handle voice call.
+        if (mImsStateTracker.isImsVoiceCapable()) {
+            logd("IMS is voice capable");
+            // TODO(b/266175810) Remove this dependency.
+            if (NormalCallDomainSelectionConnection
+                    .isWpsCall(mSelectionAttributes.getNumber())) {
+                handleWpsCall();
+            } else {
+                notifyPsSelected();
             }
         } else {
-            logd("IMS is not registered or unavailable");
+            logd("IMS is not voice capable");
+            // Voice call CS fallback
             if (isOutOfService()) {
                 loge("Cannot place call in current ServiceState: " + mServiceState.getState());
                 notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
diff --git a/src/com/android/services/telephony/rcs/TelephonyRcsService.java b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
index 13b3a7d..3a8ad62 100644
--- a/src/com/android/services/telephony/rcs/TelephonyRcsService.java
+++ b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
@@ -25,6 +25,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.util.Log;
@@ -351,23 +352,17 @@
 
     private boolean doesSubscriptionSupportPresence(int subId) {
         if (!SubscriptionManager.isValidSubscriptionId(subId)) return false;
-        CarrierConfigManager carrierConfigManager =
-                mContext.getSystemService(CarrierConfigManager.class);
-        if (carrierConfigManager == null) return false;
-        boolean supportsUce = carrierConfigManager.getConfigForSubId(subId).getBoolean(
-                CarrierConfigManager.Ims.KEY_ENABLE_PRESENCE_PUBLISH_BOOL);
-        supportsUce |= carrierConfigManager.getConfigForSubId(subId).getBoolean(
-                CarrierConfigManager.KEY_USE_RCS_SIP_OPTIONS_BOOL);
+        boolean supportsUce = getConfig(subId,
+                CarrierConfigManager.Ims.KEY_ENABLE_PRESENCE_PUBLISH_BOOL, false /*default*/);
+        supportsUce |= getConfig(subId,
+                CarrierConfigManager.KEY_USE_RCS_SIP_OPTIONS_BOOL, false /*default*/);
         return supportsUce;
     }
 
     private boolean doesSubscriptionSupportSingleRegistration(int subId) {
         if (!SubscriptionManager.isValidSubscriptionId(subId)) return false;
-        CarrierConfigManager carrierConfigManager =
-                mContext.getSystemService(CarrierConfigManager.class);
-        if (carrierConfigManager == null) return false;
-        return carrierConfigManager.getConfigForSubId(subId).getBoolean(
-                CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL);
+        return getConfig(subId, CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL,
+                false /*defaultValue*/);
     }
 
     private int getSubscriptionFromSlot(int slotId) {
@@ -384,6 +379,16 @@
     }
 
     /**
+     * @return the boolean result corresponding to a boolean {@link CarrierConfigManager} key.
+     */
+    private boolean getConfig(int subId, String key, boolean defaultValue) {
+        CarrierConfigManager c = mContext.getSystemService(CarrierConfigManager.class);
+        if (c == null) return defaultValue;
+        PersistableBundle b = c.getConfigForSubId(subId, key);
+        return b != null ? b.getBoolean(key, defaultValue) : defaultValue;
+    }
+
+    /**
      * Dump this instance into a readable format for dumpsys usage.
      */
     public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
diff --git a/testapps/GbaTestApp/res/values-ky/strings.xml b/testapps/GbaTestApp/res/values-ky/strings.xml
index bf5cd30..00383d5 100644
--- a/testapps/GbaTestApp/res/values-ky/strings.xml
+++ b/testapps/GbaTestApp/res/values-ky/strings.xml
@@ -2,7 +2,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="2922839697457005451">"GbaTestApp"</string>
-    <string name="label_settings" msgid="8030871890526865502">"Жөндөөлөр"</string>
+    <string name="label_settings" msgid="8030871890526865502">"Параметрлер"</string>
     <string name="label_carrier" msgid="1470455313066422804">"Байланыш операторунун конфигурациясы"</string>
     <string name="label_service" msgid="2668963955237345578">"Кызматтын конфигурациясы"</string>
     <string name="label_test" msgid="8425079572898571918">"Сыноо конфигурациясы"</string>
diff --git a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java
index 0f120f4..a74e7f0 100644
--- a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java
+++ b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java
@@ -23,7 +23,7 @@
 import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_FEATURE_NOT_SUPPORTED;
 import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE;
 import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION;
-import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_OVERRIDDEN;
+import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_FOREGROUND;
 import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP;
 import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_SUCCESS;
 import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED;
@@ -271,8 +271,8 @@
                 return "Already purchased";
             case PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS:
                 return "Already in progress";
-            case PURCHASE_PREMIUM_CAPABILITY_RESULT_OVERRIDDEN:
-                return "Overridden";
+            case PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_FOREGROUND:
+                return "Not foreground";
             case PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_CANCELED:
                 return "User canceled";
             case PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED:
diff --git a/tests/src/com/android/TestContext.java b/tests/src/com/android/TestContext.java
index 720d235..111df53 100644
--- a/tests/src/com/android/TestContext.java
+++ b/tests/src/com/android/TestContext.java
@@ -17,6 +17,7 @@
 package com.android;
 
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.doAnswer;
 
 import android.content.AttributionSource;
@@ -73,13 +74,12 @@
         MockitoAnnotations.initMocks(this);
         doAnswer((Answer<PersistableBundle>) invocation -> {
             int subId = (int) invocation.getArguments()[0];
-            if (subId < 0) {
-                return new PersistableBundle();
-            }
-            PersistableBundle b = mCarrierConfigs.get(subId);
-
-            return (b != null ? b : new PersistableBundle());
+            return getTestConfigs(subId);
         }).when(mMockCarrierConfigManager).getConfigForSubId(anyInt());
+        doAnswer((Answer<PersistableBundle>) invocation -> {
+            int subId = (int) invocation.getArguments()[0];
+            return getTestConfigs(subId);
+        }).when(mMockCarrierConfigManager).getConfigForSubId(anyInt(), anyString());
     }
 
     @Override
@@ -252,18 +252,16 @@
 
     public void grantPermission(String permission) {
         synchronized (mPermissionTable) {
-            if (mPermissionTable != null && permission != null) {
-                mPermissionTable.remove(STUB_PERMISSION_ENABLE_ALL);
-                mPermissionTable.add(permission);
-            }
+            if (permission == null) return;
+            mPermissionTable.remove(STUB_PERMISSION_ENABLE_ALL);
+            mPermissionTable.add(permission);
         }
     }
 
     public void revokePermission(String permission) {
         synchronized (mPermissionTable) {
-            if (mPermissionTable != null && permission != null) {
-                mPermissionTable.remove(permission);
-            }
+            if (permission == null) return;
+            mPermissionTable.remove(permission);
         }
     }
 
@@ -281,6 +279,14 @@
         return mReceiver;
     }
 
+    private PersistableBundle getTestConfigs(int subId) {
+        if (subId < 0) {
+            return new PersistableBundle();
+        }
+        PersistableBundle b = getCarrierConfig(subId);
+        return (b != null ? b : new PersistableBundle());
+    }
+
     private static void logd(String s) {
         Log.d(TAG, s);
     }
diff --git a/tests/src/com/android/phone/CarrierConfigLoaderTest.java b/tests/src/com/android/phone/CarrierConfigLoaderTest.java
index 6807422..45a53f7 100644
--- a/tests/src/com/android/phone/CarrierConfigLoaderTest.java
+++ b/tests/src/com/android/phone/CarrierConfigLoaderTest.java
@@ -54,7 +54,9 @@
 
 import com.android.TelephonyTestBase;
 import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.SubscriptionInfoUpdater;
+import com.android.internal.telephony.subscription.SubscriptionManagerService;
 
 import org.junit.After;
 import org.junit.Before;
@@ -87,6 +89,7 @@
     @Mock PackageManager mPackageManager;
     @Mock PackageInfo mPackageInfo;
     @Mock SubscriptionInfoUpdater mSubscriptionInfoUpdater;
+    @Mock SubscriptionManagerService mSubscriptionManagerService;
     @Mock SharedPreferences mSharedPreferences;
     @Mock TelephonyRegistryManager mTelephonyRegistryManager;
 
@@ -100,6 +103,9 @@
     public void setUp() throws Exception {
         super.setUp();
 
+        replaceInstance(SubscriptionManagerService.class, "sInstance", null,
+                mSubscriptionManagerService);
+
         // TODO: replace doReturn/when with when/thenReturn which is more readable
         doReturn(mSharedPreferences).when(mContext).getSharedPreferences(anyString(), anyInt());
         doReturn(Build.FINGERPRINT).when(mSharedPreferences).getString(eq("build_fingerprint"),
@@ -271,9 +277,15 @@
         mTestableLooper.processAllMessages();
 
         assertThat(mCarrierConfigLoader.getOverrideConfig(DEFAULT_PHONE_ID).isEmpty()).isTrue();
-        verify(mSubscriptionInfoUpdater).updateSubscriptionByCarrierConfigAndNotifyComplete(
-                eq(DEFAULT_PHONE_ID), eq(PLATFORM_CARRIER_CONFIG_PACKAGE),
-                any(PersistableBundle.class), any(Message.class));
+        if (PhoneFactory.isSubscriptionManagerServiceEnabled()) {
+            verify(mSubscriptionManagerService).updateSubscriptionByCarrierConfig(
+                    eq(DEFAULT_PHONE_ID), eq(PLATFORM_CARRIER_CONFIG_PACKAGE),
+                    any(PersistableBundle.class), any(Runnable.class));
+        } else {
+            verify(mSubscriptionInfoUpdater).updateSubscriptionByCarrierConfigAndNotifyComplete(
+                    eq(DEFAULT_PHONE_ID), eq(PLATFORM_CARRIER_CONFIG_PACKAGE),
+                    any(PersistableBundle.class), any(Message.class));
+        }
     }
 
     /**
@@ -294,9 +306,15 @@
 
         assertThat(mCarrierConfigLoader.getOverrideConfig(DEFAULT_PHONE_ID).getInt(
                 CARRIER_CONFIG_EXAMPLE_KEY)).isEqualTo(CARRIER_CONFIG_EXAMPLE_VALUE);
-        verify(mSubscriptionInfoUpdater).updateSubscriptionByCarrierConfigAndNotifyComplete(
-                eq(DEFAULT_PHONE_ID), eq(PLATFORM_CARRIER_CONFIG_PACKAGE),
-                any(PersistableBundle.class), any(Message.class));
+        if (PhoneFactory.isSubscriptionManagerServiceEnabled()) {
+            verify(mSubscriptionManagerService).updateSubscriptionByCarrierConfig(
+                    eq(DEFAULT_PHONE_ID), eq(PLATFORM_CARRIER_CONFIG_PACKAGE),
+                    any(PersistableBundle.class), any(Runnable.class));
+        } else {
+            verify(mSubscriptionInfoUpdater).updateSubscriptionByCarrierConfigAndNotifyComplete(
+                    eq(DEFAULT_PHONE_ID), eq(PLATFORM_CARRIER_CONFIG_PACKAGE),
+                    any(PersistableBundle.class), any(Message.class));
+        }
     }
 
     /**
diff --git a/tests/src/com/android/phone/NotificationMgrTest.java b/tests/src/com/android/phone/NotificationMgrTest.java
index 3e8cf28..e009446 100644
--- a/tests/src/com/android/phone/NotificationMgrTest.java
+++ b/tests/src/com/android/phone/NotificationMgrTest.java
@@ -44,8 +44,10 @@
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -58,6 +60,7 @@
 import android.content.res.Resources;
 import android.os.Build;
 import android.os.PersistableBundle;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.telecom.TelecomManager;
@@ -89,6 +92,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.Collections;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Unit Test for NotificationMgr
@@ -128,6 +132,7 @@
 
     private Phone[] mPhones;
     private NotificationMgr mNotificationMgr;
+    private TestableLooper mTestableLooper;
 
     @Before
     public void setUp() throws Exception {
@@ -182,7 +187,10 @@
         when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
         when(mTelephonyManager.getServiceState()).thenReturn(mServiceState);
 
-        mNotificationMgr = new NotificationMgr(mApp);
+        mTestableLooper = TestableLooper.get(this);
+        // Spy it only to avoid sleep for SystemClock.elapsedRealtime()
+        mNotificationMgr = spy(new NotificationMgr(mApp));
+        mTestableLooper.processAllMessages();
     }
 
     @Test
@@ -278,10 +286,7 @@
         prepareResourcesForNetworkSelection();
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(2000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(2 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verify(mNotificationManager, never()).notify(any(), anyInt(), any());
@@ -298,12 +303,11 @@
         config.putBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL, true);
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
 
+        // update to OOS as base state
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        // TODO: use effective TestLooper time eclipse instead of sleeping
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        // 10 seconds later
+        moveTimeForward(10 /* seconds */);
+        // verify the behavior on new request
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verifyNotificationSentWithChannelId(NotificationChannelController.CHANNEL_ID_ALERT);
@@ -322,10 +326,7 @@
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE,
                 INVALID_SUBSCRIPTION_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE,
                 INVALID_SUBSCRIPTION_ID);
 
@@ -339,10 +340,7 @@
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(null);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verify(mNotificationManager, never()).notify(any(), anyInt(), any());
@@ -362,10 +360,7 @@
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verify(mNotificationManager, never()).notify(any(), anyInt(), any());
@@ -386,10 +381,7 @@
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verify(mNotificationManager, never()).notify(any(), anyInt(), any());
@@ -410,10 +402,7 @@
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verify(mNotificationManager, never()).notify(any(), anyInt(), any());
@@ -439,10 +428,7 @@
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verify(mNotificationManager, never()).notify(any(), anyInt(), any());
@@ -469,10 +455,7 @@
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verify(mNotificationManager, never()).notify(any(), anyInt(), any());
@@ -500,10 +483,7 @@
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verifyNotificationSentWithChannelId(NotificationChannelController.CHANNEL_ID_ALERT);
@@ -524,10 +504,7 @@
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verifyNotificationSentWithChannelId(NotificationChannelController.CHANNEL_ID_ALERT);
@@ -549,10 +526,7 @@
         when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verifyNotificationSentWithChannelId(NotificationChannelController.CHANNEL_ID_ALERT);
@@ -572,10 +546,7 @@
         when(mTelephonyManager.getPhoneType()).thenReturn(TelephonyManager.PHONE_TYPE_CDMA);
 
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
-        try {
-            Thread.sleep(10000);
-        } catch (InterruptedException ignored) {
-        }
+        moveTimeForward(10 /* seconds */);
         mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
 
         verify(mNotificationManager, never()).notify(any(), anyInt(), any());
@@ -661,4 +632,11 @@
         when(mApp.getString(R.string.mobile_network_settings_class)).thenReturn(
                 MOBILE_NETWORK_SELECTION_CLASS);
     }
+
+    private void moveTimeForward(long seconds) {
+        final long millis = TimeUnit.SECONDS.toMillis(seconds);
+        mTestableLooper.moveTimeForward(millis);
+        mTestableLooper.processAllMessages();
+        doReturn(SystemClock.elapsedRealtime() + millis).when(mNotificationMgr).getTimeStamp();
+    }
 }
diff --git a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
index b6d1087..4cc793d 100644
--- a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
+++ b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
@@ -21,6 +21,8 @@
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
@@ -42,6 +44,7 @@
 import com.android.TelephonyTestBase;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.RILConstants;
+import com.android.internal.telephony.IIntegerConsumer;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -57,6 +60,7 @@
 public class PhoneInterfaceManagerTest extends TelephonyTestBase {
     private PhoneInterfaceManager mPhoneInterfaceManager;
     private SharedPreferences mSharedPreferences;
+    private IIntegerConsumer mIIntegerConsumer;
 
     @Mock
     PhoneGlobals mPhoneGlobals;
@@ -74,6 +78,7 @@
         mPhoneInterfaceManager = spy(PhoneInterfaceManager.init(mPhoneGlobals));
         mSharedPreferences = mPhoneInterfaceManager.getSharedPreferences();
         mSharedPreferences.edit().remove(Phone.PREF_NULL_CIPHER_AND_INTEGRITY_ENABLED).commit();
+        mIIntegerConsumer = mock(IIntegerConsumer.class);
     }
 
     @Test
@@ -249,4 +254,27 @@
         doReturn(mPhone).when(
                 mPhoneInterfaceManager).getDefaultPhone();
     }
+
+    /**
+     * Verify getCarrierRestrictionStatus throws exception for invalid caller package name.
+     */
+    @Test
+    public void getCarrierRestrictionStatus_ReadPrivilegedException2() {
+        doThrow(SecurityException.class).when(
+                mPhoneInterfaceManager).enforceReadPrivilegedPermission(anyString());
+        assertThrows(SecurityException.class, () -> {
+            mPhoneInterfaceManager.getCarrierRestrictionStatus(mIIntegerConsumer, "");
+        });
+    }
+
+    /**
+     * Verify getCarrierRestrictionStatus doesn't throw any exception with valid package name
+     * and with READ_PHONE_STATE permission granted.
+     */
+    @Test
+    public void getCarrierRestrictionStatus() {
+        when(mPhoneInterfaceManager.validateCallerAndGetCarrierId(anyString())).thenReturn(1);
+        mPhoneInterfaceManager.getCarrierRestrictionStatus(mIIntegerConsumer,
+                "com.test.package");
+    }
 }
diff --git a/tests/src/com/android/phone/Telephony2gUpdaterTest.java b/tests/src/com/android/phone/Telephony2gUpdaterTest.java
deleted file mode 100644
index 3443767..0000000
--- a/tests/src/com/android/phone/Telephony2gUpdaterTest.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.phone;
-
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.os.UserManager;
-import android.telephony.SubscriptionInfo;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import com.android.TelephonyTestBase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-
-@RunWith(AndroidJUnit4.class)
-public class Telephony2gUpdaterTest extends TelephonyTestBase {
-    private Telephony2gUpdater mTelephony2gUpdater;
-    private Executor mExecutor;
-
-    private UserManager mMockUserManager;
-    private TelephonyManager mMockTelephonyManager;
-    private SubscriptionManager mMockSubscriptionManager;
-
-    // 2G Bitmask is 0b10000000_01001011
-    private static final long BASE_NETWORK = 0b11111111_11111111;
-    private static final long EXPECTED_DISABLED = 0b01111111_10110100;
-    private static final long EXPECTED_ENABLED = 0b11111111_11111111;
-
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-
-        mMockTelephonyManager = mContext.getSystemService(TelephonyManager.class);
-        mMockUserManager = mContext.getSystemService(UserManager.class);
-        mMockSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
-
-        mExecutor = Executors.newSingleThreadExecutor();
-        mTelephony2gUpdater = new Telephony2gUpdater(mExecutor,
-                getTestContext(), BASE_NETWORK);
-    }
-
-    @Test
-    public void handleUserRestrictionsChanged_noSubscriptions_noAllowedNetworksChanged() {
-        when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
-                new ArrayList<>());
-        mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
-        verify(mMockTelephonyManager, never()).setAllowedNetworkTypesForReason(anyInt(), anyInt());
-    }
-
-    @Test
-    public void handleUserRestrictionsChanged_nullSubscriptions_noAllowedNetworksChanged() {
-        when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(null);
-        mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
-        verify(mMockTelephonyManager, never()).setAllowedNetworkTypesForReason(anyInt(), anyInt());
-    }
-
-    @Test
-    public void handleUserRestrictionsChanged_oneSubscription_allowedNetworksUpdated() {
-        TelephonyManager tmSubscription1 = mock(TelephonyManager.class);
-        when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
-                Collections.singletonList(getSubInfo(1)));
-        when(mMockTelephonyManager.createForSubscriptionId(1)).thenReturn(tmSubscription1);
-        when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
-                true);
-
-        mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
-
-        System.out.println(TelephonyManager.convertNetworkTypeBitmaskToString(11L));
-        verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
-                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
-    }
-
-    @Test
-    public void handleUserRestrictionsChanged_manySubscriptionsDisallow2g_allowedNetworkUpdated() {
-
-        // Two subscriptions are available
-        when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
-                Arrays.asList(getSubInfo(1), getSubInfo(2)));
-        TelephonyManager tmSubscription1 = mock(TelephonyManager.class);
-        TelephonyManager tmSubscription2 = mock(TelephonyManager.class);
-        when(mMockTelephonyManager.createForSubscriptionId(1)).thenReturn(tmSubscription1);
-        when(mMockTelephonyManager.createForSubscriptionId(2)).thenReturn(tmSubscription2);
-        // 2g is disallowed
-        when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
-                true);
-
-        mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
-
-        verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
-                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
-        verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
-                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
-    }
-
-    @Test
-    public void handleUserRestrictionsChanged_manySubscriptionsAllow2g_allowedNetworkUpdated() {
-
-        // Two subscriptions are available
-        when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
-                Arrays.asList(getSubInfo(1), getSubInfo(2)));
-        TelephonyManager tmSubscription1 = mock(TelephonyManager.class);
-        TelephonyManager tmSubscription2 = mock(TelephonyManager.class);
-        when(mMockTelephonyManager.createForSubscriptionId(1)).thenReturn(tmSubscription1);
-        when(mMockTelephonyManager.createForSubscriptionId(2)).thenReturn(tmSubscription2);
-
-        // 2g is allowed
-        when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
-                false);
-
-        mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
-
-        verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
-                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
-        verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
-                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
-    }
-
-    private SubscriptionInfo getSubInfo(int id) {
-        return new SubscriptionInfo(id, "890126042XXXXXXXXXXX", 0, "T-mobile", "T-mobile", 0, 255,
-                "12345", 0, null, "310", "260", "156", false, null, null);
-    }
-}
diff --git a/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java b/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
index e2ebac0..921babb 100644
--- a/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
+++ b/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
@@ -70,7 +70,7 @@
 
 @RunWith(AndroidJUnit4.class)
 public class SlicePurchaseControllerTest extends TelephonyTestBase {
-    private static final String TAG = "SlicePurchaseControllerTest";
+    private static final String CARRIER = "Some Carrier";
     private static final String DAILY_NOTIFICATION_COUNT_KEY = "daily_notification_count0";
     private static final String MONTHLY_NOTIFICATION_COUNT_KEY = "monthly_notification_count0";
     private static final int YEAR = 2000;
@@ -148,6 +148,7 @@
         mSlicePurchaseController = spy(slicePurchaseController);
         doReturn(null).when(mSlicePurchaseController).createPendingIntent(
                 anyString(), anyInt(), anyBoolean());
+        doReturn(CARRIER).when(mSlicePurchaseController).getSimOperator();
         replaceInstance(SlicePurchaseController.class, "sInstances", mSlicePurchaseController,
                 Map.of(PHONE_ID, mSlicePurchaseController));
         replaceInstance(SlicePurchaseController.class, "mPremiumNetworkEntitlementApi",
@@ -272,8 +273,7 @@
     @Test
     public void testPurchasePremiumCapabilityResultFeatureNotSupported() {
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_FEATURE_NOT_SUPPORTED,
                 mResult);
@@ -283,8 +283,7 @@
                 .getCachedAllowedNetworkTypesBitmask();
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertNotEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_FEATURE_NOT_SUPPORTED,
                 mResult);
@@ -296,8 +295,7 @@
                 .getCachedAllowedNetworkTypesBitmask();
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED, mResult);
 
@@ -308,8 +306,7 @@
                 SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertNotEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED,
                 mResult);
@@ -325,8 +322,7 @@
                 SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(
                 TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION,
@@ -336,8 +332,7 @@
         doReturn(SubscriptionManager.getDefaultDataSubscriptionId()).when(mPhone).getSubId();
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertNotEquals(
                 TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION,
@@ -355,8 +350,7 @@
         doReturn(SubscriptionManager.getDefaultDataSubscriptionId()).when(mPhone).getSubId();
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE,
                 mResult);
@@ -365,8 +359,7 @@
         doReturn(TelephonyManager.NETWORK_TYPE_NR).when(mServiceState).getDataNetworkType();
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertNotEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE,
                 mResult);
@@ -385,8 +378,7 @@
         doReturn(null).when(mPremiumNetworkEntitlementApi).checkEntitlementStatus(anyInt());
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ENTITLEMENT_CHECK_FAILED,
                 mResult);
@@ -398,8 +390,7 @@
                 .checkEntitlementStatus(anyInt());
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED,
                 mResult);
@@ -409,8 +400,7 @@
                 PremiumNetworkEntitlementResponse.PREMIUM_NETWORK_PROVISION_STATUS_IN_PROGRESS;
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS,
                 mResult);
@@ -425,16 +415,14 @@
                 PURCHASE_CONDITION_TIMEOUT);
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ENTITLEMENT_CHECK_FAILED,
                 mResult);
 
         // retry to verify throttled
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
 
@@ -450,16 +438,14 @@
         sendValidPurchaseRequest();
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS,
                 mResult);
 
         // retry to verify same result
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS,
                 mResult);
@@ -487,8 +473,7 @@
         testPurchasePremiumCapabilityResultSuccess();
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP,
                 mResult);
@@ -507,16 +492,14 @@
         sendNetworkSlicingConfig(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, true);
 
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED,
                 mResult);
 
         // retry to verify same result
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED,
                 mResult);
@@ -537,8 +520,7 @@
 
         // retry to verify throttled
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
 
@@ -565,8 +547,7 @@
 
         // retry to verify throttled
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
 
@@ -596,8 +577,7 @@
 
         // retry to verify throttled
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
 
@@ -660,8 +640,7 @@
 
         // retry to verify throttled
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
 
@@ -678,8 +657,7 @@
 
         // retry to verify throttled
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
     }
@@ -741,8 +719,7 @@
 
         // send purchase request
         mSlicePurchaseController.purchasePremiumCapability(
-                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
-                mHandler.obtainMessage());
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
         mTestableLooper.processAllMessages();
 
         // verify that the purchase request was sent successfully
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index a1d7405..3d6a0aa 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -207,7 +207,6 @@
         mTestConnectionService.setDisconnectCauseFactory(mDisconnectCauseFactory);
         mTestConnectionService.onCreate();
         mTestConnectionService.setTelephonyManagerProxy(mTelephonyManagerProxy);
-        DomainSelectionResolver.setDomainSelectionResolver(mDomainSelectionResolver);
         replaceInstance(TelephonyConnectionService.class, "mDomainSelectionResolver",
                 mTestConnectionService, mDomainSelectionResolver);
         mEmergencyStateTracker = Mockito.mock(EmergencyStateTracker.class);
@@ -1518,6 +1517,40 @@
     }
 
     @Test
+    public void testDomainSelectionNormalRoutingEmergencyNumber() throws Exception {
+        setupForCallTest();
+        int selectedDomain = DOMAIN_PS;
+
+        EmergencyNumber emergencyNumber = new EmergencyNumber(TEST_EMERGENCY_NUMBER, "", "",
+                EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
+                Collections.emptyList(),
+                EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE,
+                EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL);
+
+        setupForDialForDomainSelection(mPhone0, selectedDomain, false);
+        doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
+        doReturn(emergencyNumber).when(mEmergencyNumberTracker).getEmergencyNumber(anyString());
+
+        mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
+                createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
+                        TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+
+        verify(mDomainSelectionResolver)
+                .getDomainSelectionConnection(eq(mPhone0), eq(SELECTOR_TYPE_CALLING), eq(false));
+        verify(mNormalCallDomainSelectionConnection).createNormalConnection(any(), any());
+
+        ArgumentCaptor<DialArgs> argsCaptor = ArgumentCaptor.forClass(DialArgs.class);
+
+        verify(mPhone0).dial(anyString(), argsCaptor.capture(), any());
+        DialArgs dialArgs = argsCaptor.getValue();
+        assertNotNull("DialArgs param is null", dialArgs);
+        assertNotNull("intentExtras is null", dialArgs.intentExtras);
+        assertTrue(dialArgs.intentExtras.containsKey(PhoneConstants.EXTRA_DIAL_DOMAIN));
+        assertEquals(
+                selectedDomain, dialArgs.intentExtras.getInt(PhoneConstants.EXTRA_DIAL_DOMAIN, -1));
+    }
+
+    @Test
     public void testDomainSelectionNormalToEmergencyCs() throws Exception {
         setupForCallTest();
 
@@ -1527,9 +1560,10 @@
         int selectedDomain = DOMAIN_CS;
 
         setupForDialForDomainSelection(mPhone0, selectedDomain, true);
+        doReturn(mPhone0).when(mImsPhone).getDefaultPhone();
 
         TestTelephonyConnection c = setupForReDialForDomainSelection(
-                mPhone0, selectedDomain, preciseDisconnectCause, disconnectCause, false);
+                mImsPhone, selectedDomain, preciseDisconnectCause, disconnectCause, false);
         c.setEmergencyServiceCategory(eccCategory);
         c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
 
@@ -1566,9 +1600,10 @@
         int selectedDomain = DOMAIN_PS;
 
         setupForDialForDomainSelection(mPhone0, selectedDomain, true);
+        doReturn(mPhone0).when(mImsPhone).getDefaultPhone();
 
         TestTelephonyConnection c = setupForReDialForDomainSelection(
-                mPhone0, selectedDomain, preciseDisconnectCause, disconnectCause, false);
+                mImsPhone, selectedDomain, preciseDisconnectCause, disconnectCause, false);
         c.setEmergencyServiceCategory(eccCategory);
         c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
 
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionTest.java
index 3c309ba..758ded7 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionTest.java
@@ -294,13 +294,16 @@
     public void testDomainSelectionDisconnected_Redial() {
         TestTelephonyConnection c = new TestTelephonyConnection();
         c.setOriginalConnection(mImsPhoneConnection);
+
         doReturn(Call.State.DISCONNECTED).when(mImsPhoneConnection)
                 .getState();
         c.setTelephonyConnectionService(mTelephonyConnectionService);
         doReturn(true).when(mTelephonyConnectionService)
                 .maybeReselectDomain(any(), anyInt(), any());
+        c.resetOriginalConnectionCleared();
         c.updateState();
 
         assertNotEquals(STATE_DISCONNECTED, c.getState());
+        assertTrue(c.isOriginalConnectionCleared());
     }
 }
diff --git a/tests/src/com/android/services/telephony/TelephonyManagerTest.java b/tests/src/com/android/services/telephony/TelephonyManagerTest.java
index eec38ce..20c062f 100644
--- a/tests/src/com/android/services/telephony/TelephonyManagerTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyManagerTest.java
@@ -56,6 +56,10 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
 
 /** Unit tests for {@link TelephonyManager}. */
 @RunWith(AndroidJUnit4.class)
@@ -271,4 +275,24 @@
         assertEquals("12345", mTelephonyManager.getPrimaryImei());
         verify(mMockITelephony, times(1)).getPrimaryImei(anyString(), anyString());
     }
-}
+
+    /**
+     * Verify calling getCarrierRestrictionStatus() with out exception
+     */
+    @Test
+    public void getCarrierRestrictionStatus() {
+        int TIMEOUT = 2 * 60; // 2 minutes
+        LinkedBlockingQueue<Integer> carrierRestrictionStatusResult = new LinkedBlockingQueue<>(1);
+        Executor executor = Executors.newSingleThreadExecutor();
+        mTelephonyManager.getCarrierRestrictionStatus(executor,
+                carrierRestrictionStatusResult::offer);
+        executor.execute(() -> {
+            try {
+                carrierRestrictionStatusResult.poll(TIMEOUT, TimeUnit.SECONDS);
+            } catch (InterruptedException e) {
+                fail();
+            }
+        });
+
+    }
+}
\ No newline at end of file
diff --git a/tests/src/com/android/services/telephony/TestTelephonyConnection.java b/tests/src/com/android/services/telephony/TestTelephonyConnection.java
index e149d3b..d91435c 100644
--- a/tests/src/com/android/services/telephony/TestTelephonyConnection.java
+++ b/tests/src/com/android/services/telephony/TestTelephonyConnection.java
@@ -50,8 +50,6 @@
 
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -107,6 +105,7 @@
     private List<Bundle> mLastConnectionEventExtras = new ArrayList<>();
     private Object mLock = new Object();
     private PersistableBundle mCarrierConfig = new PersistableBundle();
+    private boolean mOriginalConnectionCleared;
 
     @Override
     public com.android.internal.telephony.Connection getOriginalConnection() {
@@ -211,7 +210,15 @@
 
     @Override
     void clearOriginalConnection() {
-        // Do nothing since the original connection is mock object
+        mOriginalConnectionCleared = true;
+    }
+
+    boolean isOriginalConnectionCleared() {
+        return mOriginalConnectionCleared;
+    }
+
+    void resetOriginalConnectionCleared() {
+        mOriginalConnectionCleared = false;
     }
 
     @Override
diff --git a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
index e1de0ab..c50c6b5 100644
--- a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
@@ -35,9 +35,14 @@
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL;
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL;
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_SCAN_TIMER_SEC_INT;
+import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT;
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT;
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL;
 import static android.telephony.CarrierConfigManager.ImsEmergency.SCAN_TYPE_NO_PREFERENCE;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_NONE;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_SETTING_ENABLED;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_VALID_EID;
+import static android.telephony.CarrierConfigManager.ImsWfc.KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL;
 import static android.telephony.DomainSelectionService.SELECTOR_TYPE_CALLING;
 import static android.telephony.NetworkRegistrationInfo.DOMAIN_CS;
 import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS;
@@ -62,6 +67,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkRequest;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IPowerManager;
@@ -82,6 +89,7 @@
 import android.telephony.WwanSelectorCallback;
 import android.telephony.ims.ImsManager;
 import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ProvisioningManager;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.TestableLooper;
 import android.util.Log;
@@ -111,12 +119,14 @@
     private static final int SLOT_0_SUB_ID = 1;
 
     @Mock private CarrierConfigManager mCarrierConfigManager;
+    @Mock private ConnectivityManager mConnectivityManager;
     @Mock private TelephonyManager mTelephonyManager;
     @Mock private WwanSelectorCallback mWwanSelectorCallback;
     @Mock private TransportSelectorCallback mTransportSelectorCallback;
     @Mock private ImsMmTelManager mMmTelManager;
     @Mock private ImsStateTracker mImsStateTracker;
     @Mock private DomainSelectorBase.DestroyListener mDestroyListener;
+    @Mock private ProvisioningManager mProvisioningManager;
 
     private Context mContext;
 
@@ -126,6 +136,7 @@
     private SelectionAttributes mSelectionAttributes;
     private @AccessNetworkConstants.RadioAccessNetworkType List<Integer> mAccessNetwork;
     private PowerManager mPowerManager;
+    private ConnectivityManager.NetworkCallback mNetworkCallback;
 
     @Before
     public void setUp() throws Exception {
@@ -141,6 +152,8 @@
                     return Context.CARRIER_CONFIG_SERVICE;
                 } else if (serviceClass == PowerManager.class) {
                     return Context.POWER_SERVICE;
+                } else if (serviceClass == ConnectivityManager.class) {
+                    return Context.CONNECTIVITY_SERVICE;
                 }
                 return super.getSystemServiceName(serviceClass);
             }
@@ -151,6 +164,9 @@
                     case (Context.POWER_SERVICE) : {
                         return mPowerManager;
                     }
+                    case (Context.CONNECTIVITY_SERVICE) : {
+                        return mConnectivityManager;
+                    }
                 }
                 return super.getSystemService(name);
             }
@@ -183,6 +199,17 @@
         when(mCarrierConfigManager.getConfigForSubId(anyInt()))
             .thenReturn(getDefaultPersistableBundle());
 
+        mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                mNetworkCallback = (ConnectivityManager.NetworkCallback)
+                        invocation.getArguments()[1];
+                return null;
+            }
+        }).when(mConnectivityManager).registerNetworkCallback(
+                any(NetworkRequest.class), any(ConnectivityManager.NetworkCallback.class));
+
         IPowerManager powerManager = mock(IPowerManager.class);
         mPowerManager = new PowerManager(mContext, powerManager, mock(IThermalService.class),
                 new Handler(mHandlerThread.getLooper()));
@@ -190,6 +217,8 @@
         ImsManager imsManager = mContext.getSystemService(ImsManager.class);
         when(imsManager.getImsMmTelManager(anyInt())).thenReturn(mMmTelManager);
         when(mMmTelManager.isAdvancedCallingSettingEnabled()).thenReturn(true);
+        doReturn(mProvisioningManager).when(imsManager).getProvisioningManager(anyInt());
+        doReturn(null).when(mProvisioningManager).getProvisioningStringValue(anyInt());
 
         when(mTransportSelectorCallback.onWwanSelected()).thenReturn(mWwanSelectorCallback);
         doAnswer(new Answer<Void>() {
@@ -287,6 +316,28 @@
     }
 
     @Test
+    public void testNoCsCombinedImsNotRegisteredSelectPs() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putIntArray(KEY_EMERGENCY_OVER_CS_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY,
+                new int[0]);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(false);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_CS | NetworkRegistrationInfo.DOMAIN_PS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsServiceUnregistered();
+
+        verifyPsDialed();
+    }
+
+    @Test
     public void testDefaultCombinedImsNotRegisteredBarredSelectCs() throws Exception {
         createSelector(SLOT_0_SUB_ID);
         unsolBarringInfoChanged(true);
@@ -835,7 +886,7 @@
     }
 
     @Test
-    public void testVoLteOffEpsImsNotRegisteredSelectCs() throws Exception {
+    public void testVoLteOffEpsImsNotRegisteredScanCsPreferred() throws Exception {
         PersistableBundle bundle = getDefaultPersistableBundle();
         bundle.putBoolean(KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL, true);
         when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
@@ -856,7 +907,7 @@
         bindImsServiceUnregistered();
 
         // Requires VoLTE enabled but VoLTE is'nt enabled.
-        verifyCsDialed();
+        verifyScanCsPreferred();
     }
 
     @Test
@@ -882,6 +933,10 @@
 
     @Test
     public void testDefaultEpsImsRegisteredBarredScanTimeoutWifi() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
         createSelector(SLOT_0_SUB_ID);
         unsolBarringInfoChanged(true);
 
@@ -898,11 +953,159 @@
 
         assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
 
+        // Wi-Fi is not connected.
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // Wi-Fi is connected.
+        mNetworkCallback.onAvailable(null);
         mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
 
         verify(mTransportSelectorCallback, times(1)).onWlanSelected();
     }
 
+    @Test
+    public void testVoWifiSosPdnRequiresSettingEnabled() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
+        bundle.putInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT, VOWIFI_REQUIRES_SETTING_ENABLED);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(true);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_PS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        bindImsServiceUnregistered();
+        processAllMessages();
+
+        assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        // Wi-Fi is not connected.
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // Wi-Fi is connected. But Wi-Fi calling setting is disabled.
+        mNetworkCallback.onAvailable(null);
+        when(mMmTelManager.isVoWiFiRoamingSettingEnabled()).thenReturn(false);
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // Wi-Fi is connected and Wi-Fi calling setting is enabled.
+        when(mMmTelManager.isVoWiFiSettingEnabled()).thenReturn(true);
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+    }
+
+    @Test
+    public void testVoWifiSosPdnRequiresValidEid() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
+        bundle.putInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT, VOWIFI_REQUIRES_VALID_EID);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(true);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_PS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        bindImsServiceUnregistered();
+        processAllMessages();
+
+        assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        // Wi-Fi is not connected.
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // Wi-Fi is connected. But Wi-Fi calling s not activated.
+        mNetworkCallback.onAvailable(null);
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // Wi-Fi is connected and Wi-Fi calling is activated.
+        doReturn("1").when(mProvisioningManager).getProvisioningStringValue(anyInt());
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+    }
+
+    @Test
+    public void testVoWifiImsPdnRequiresNone() throws Exception {
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(true);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_PS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        bindImsServiceUnregistered();
+        processAllMessages();
+
+        assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        // Wi-Fi is not connected.
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // Wi-Fi is connected but IMS is not registered over Wi-Fi.
+        mNetworkCallback.onAvailable(null);
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // IMS is registered over Wi-Fi.
+        bindImsService(true);
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+    }
+
+    @Test
+    public void testIgnoreDuplicatedCallbacks() throws Exception {
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(true);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_PS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        processAllMessages();
+
+        bindImsService(true);
+
+        verify(mTransportSelectorCallback, times(1)).onWwanSelected(any());
+
+        // duplicated event
+        unsolBarringInfoChanged(true);
+
+        // ignore duplicated callback, no change in interaction
+        verify(mTransportSelectorCallback, times(1)).onWwanSelected(any());
+
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+
+        // duplicated event
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        // ignore duplicated callback, no change in interaction
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+    }
+
     private void createSelector(int subId) throws Exception {
         mDomainSelector = new EmergencyCallDomainSelector(
                 mContext, SLOT_0, subId, mHandlerThread.getLooper(),
@@ -913,10 +1116,12 @@
     }
 
     private void verifyCsDialed() {
+        processAllMessages();
         verify(mWwanSelectorCallback, times(1)).onDomainSelected(eq(DOMAIN_CS));
     }
 
     private void verifyPsDialed() {
+        processAllMessages();
         verify(mWwanSelectorCallback, times(1)).onDomainSelected(eq(DOMAIN_PS));
     }
 
@@ -929,6 +1134,7 @@
     }
 
     private void verifyScanPreferred(int scanType, int expectedPreferredAccessNetwork) {
+        processAllMessages();
         verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
                 any(), eq(scanType), any(), any());
         assertEquals(expectedPreferredAccessNetwork, (int) mAccessNetwork.get(0));
@@ -989,8 +1195,10 @@
                 CarrierConfigManager.ImsEmergency.DOMAIN_PS_NON_3GPP
                 };
         boolean imsWhenVoiceOnCs = false;
+        int voWifiRequiresCondition = VOWIFI_REQUIRES_NONE;
         int maxRetriesOverWiFi = 1;
         int cellularScanTimerSec = 10;
+        boolean voWifiOverEmergencyPdn = false;
         int scanType = SCAN_TYPE_NO_PREFERENCE;
         boolean requiresImsRegistration = false;
         boolean requiresVoLteEnabled = false;
@@ -998,17 +1206,19 @@
         String[] cdmaPreferredNumbers = new String[] {};
 
         return getPersistableBundle(imsRats, csRats, imsRoamRats, csRoamRats,
-                domainPreference, roamDomainPreference, imsWhenVoiceOnCs, maxRetriesOverWiFi,
-                cellularScanTimerSec, scanType, requiresImsRegistration, requiresVoLteEnabled,
-                ltePreferredAfterNrFailed, cdmaPreferredNumbers);
+                domainPreference, roamDomainPreference, imsWhenVoiceOnCs,
+                voWifiRequiresCondition, maxRetriesOverWiFi, cellularScanTimerSec,
+                scanType, voWifiOverEmergencyPdn, requiresImsRegistration,
+                requiresVoLteEnabled, ltePreferredAfterNrFailed, cdmaPreferredNumbers);
     }
 
     private static PersistableBundle getPersistableBundle(
             @Nullable int[] imsRats, @Nullable int[] csRats,
             @Nullable int[] imsRoamRats, @Nullable int[] csRoamRats,
             @Nullable int[] domainPreference, @Nullable int[] roamDomainPreference,
-            boolean imsWhenVoiceOnCs, int maxRetriesOverWiFi,
-            int cellularScanTimerSec, int scanType, boolean requiresImsRegistration,
+            boolean imsWhenVoiceOnCs, int voWifiRequiresCondition,
+            int maxRetriesOverWiFi, int cellularScanTimerSec, int scanType,
+            boolean voWifiOverEmergencyPdn, boolean requiresImsRegistration,
             boolean requiresVoLteEnabled, boolean ltePreferredAfterNrFailed,
             @Nullable String[] cdmaPreferredNumbers) {
 
@@ -1039,8 +1249,10 @@
                     roamDomainPreference);
         }
         bundle.putBoolean(KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL, imsWhenVoiceOnCs);
+        bundle.putInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT, voWifiRequiresCondition);
         bundle.putInt(KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT, maxRetriesOverWiFi);
         bundle.putInt(KEY_EMERGENCY_SCAN_TIMER_SEC_INT, cellularScanTimerSec);
+        bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, voWifiOverEmergencyPdn);
         bundle.putInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT, scanType);
         bundle.putBoolean(KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL, requiresImsRegistration);
         bundle.putBoolean(KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL, requiresVoLteEnabled);
diff --git a/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java b/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java
index b00926f..430adea 100644
--- a/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java
@@ -210,6 +210,23 @@
 
     @Test
     @SmallTest
+    public void testStartAfterUnavailableWithReasonSubscriptionInactive() throws ImsException {
+        ImsStateCallback callback = setUpImsStateCallback();
+        callback.onUnavailable(ImsStateCallback.REASON_SUBSCRIPTION_INACTIVE);
+
+        mImsStateTracker.start(SUB_1);
+
+        assertTrue(isImsStateInit());
+        // One is invoked in setUpImsStateCallback and the other is invoked in start(int).
+        verify(mMmTelManager, times(2)).registerImsStateCallback(
+                any(Executor.class), any(ImsStateCallback.class));
+        // ImsStateCallback has already been set to null when onUnavailable is called.
+        verify(mMmTelManager, never()).unregisterImsStateCallback(
+                any(ImsStateCallback.class));
+    }
+
+    @Test
+    @SmallTest
     public void testUpdateServiceStateBeforeAddingListener() {
         mImsStateTracker.updateServiceState(mServiceState);
         mImsStateTracker.addServiceStateListener(mServiceStateListener);
@@ -509,6 +526,7 @@
         assertFalse(mImsStateTracker.isImsStateReady());
         assertTrue(mImsStateTracker.isImsRegistered());
         assertFalse(mImsStateTracker.isImsRegisteredOverWlan());
+        assertFalse(mImsStateTracker.isImsRegisteredOverCrossSim());
         assertEquals(AccessNetworkType.EUTRAN, mImsStateTracker.getImsAccessNetworkType());
 
         callback.onRegistered(new ImsRegistrationAttributes.Builder(
@@ -517,6 +535,7 @@
         assertFalse(mImsStateTracker.isImsStateReady());
         assertTrue(mImsStateTracker.isImsRegistered());
         assertFalse(mImsStateTracker.isImsRegisteredOverWlan());
+        assertFalse(mImsStateTracker.isImsRegisteredOverCrossSim());
         assertEquals(AccessNetworkType.NGRAN, mImsStateTracker.getImsAccessNetworkType());
 
         callback.onRegistered(new ImsRegistrationAttributes.Builder(
@@ -525,6 +544,16 @@
         assertFalse(mImsStateTracker.isImsStateReady());
         assertTrue(mImsStateTracker.isImsRegistered());
         assertTrue(mImsStateTracker.isImsRegisteredOverWlan());
+        assertFalse(mImsStateTracker.isImsRegisteredOverCrossSim());
+        assertEquals(AccessNetworkType.IWLAN, mImsStateTracker.getImsAccessNetworkType());
+
+        callback.onRegistered(new ImsRegistrationAttributes.Builder(
+                ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM).build());
+
+        assertFalse(mImsStateTracker.isImsStateReady());
+        assertTrue(mImsStateTracker.isImsRegistered());
+        assertTrue(mImsStateTracker.isImsRegisteredOverWlan());
+        assertTrue(mImsStateTracker.isImsRegisteredOverCrossSim());
         assertEquals(AccessNetworkType.IWLAN, mImsStateTracker.getImsAccessNetworkType());
 
         callback.onRegistered(new ImsRegistrationAttributes.Builder(
@@ -533,9 +562,10 @@
         assertFalse(mImsStateTracker.isImsStateReady());
         assertTrue(mImsStateTracker.isImsRegistered());
         assertFalse(mImsStateTracker.isImsRegisteredOverWlan());
+        assertFalse(mImsStateTracker.isImsRegisteredOverCrossSim());
         assertEquals(AccessNetworkType.UNKNOWN, mImsStateTracker.getImsAccessNetworkType());
 
-        verify(mImsStateListener, times(4)).onImsRegistrationStateChanged();
+        verify(mImsStateListener, times(5)).onImsRegistrationStateChanged();
     }
 
     @Test
diff --git a/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java
index 890ca34..8780f1f 100644
--- a/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java
@@ -31,7 +31,10 @@
 import android.os.CancellationSignal;
 import android.os.HandlerThread;
 import android.os.Looper;
+import android.os.PersistableBundle;
+import android.telecom.TelecomManager;
 import android.telephony.AccessNetworkConstants;
+import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
 import android.telephony.DomainSelectionService;
 import android.telephony.DomainSelector;
@@ -75,18 +78,32 @@
     private NormalCallDomainSelector mNormalCallDomainSelector;
 
     @Mock private Context mMockContext;
+    @Mock private CarrierConfigManager mMockCarrierConfigMgr;
     @Mock private ImsManager mMockImsManager;
     @Mock private ImsMmTelManager mMockMmTelManager;
     @Mock private ImsStateTracker mMockImsStateTracker;
     @Mock private DomainSelectorBase.DestroyListener mMockDestroyListener;
+    @Mock private TelecomManager mMockTelecomManager;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+
         doReturn(Context.TELEPHONY_IMS_SERVICE).when(mMockContext)
                 .getSystemServiceName(ImsManager.class);
         doReturn(mMockImsManager).when(mMockContext)
                 .getSystemService(Context.TELEPHONY_IMS_SERVICE);
+
+        doReturn(Context.CARRIER_CONFIG_SERVICE).when(mMockContext)
+                .getSystemServiceName(CarrierConfigManager.class);
+        doReturn(mMockCarrierConfigMgr).when(mMockContext)
+                .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+
+        doReturn(Context.TELECOM_SERVICE).when(mMockContext)
+                .getSystemServiceName(TelecomManager.class);
+        doReturn(mMockTelecomManager).when(mMockContext)
+                .getSystemService(Context.TELECOM_SERVICE);
+
         doReturn(mMockMmTelManager).when(mMockImsManager).getImsMmTelManager(SUB_ID_1);
         doReturn(mMockMmTelManager).when(mMockImsManager).getImsMmTelManager(SUB_ID_2);
         doNothing().when(mMockImsStateTracker).removeServiceStateListener(any());
@@ -310,6 +327,90 @@
         assertTrue(transportSelectorCallback.verifyOnWlanSelected());
     }
 
+    @Test
+    public void testWPSCallDomainSelection() {
+        MockTransportSelectorCallback transportSelectorCallback =
+                new MockTransportSelectorCallback();
+        DomainSelectionService.SelectionAttributes attributes =
+                new DomainSelectionService.SelectionAttributes.Builder(
+                        SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
+                        .setNumber("*272121")
+                        .setCallId(TEST_CALLID)
+                        .setEmergency(false)
+                        .setVideoCall(false)
+                        .setExitedFromAirplaneMode(false)
+                        .build();
+
+        //Case 1: WPS not supported by IMS
+        PersistableBundle config = new PersistableBundle();
+        config.putBoolean(CarrierConfigManager.KEY_SUPPORT_WPS_OVER_IMS_BOOL, false);
+        doReturn(config).when(mMockCarrierConfigMgr).getConfigForSubId(SUB_ID_1);
+        ServiceState serviceState = new ServiceState();
+        serviceState.setState(ServiceState.STATE_IN_SERVICE);
+        initialize(serviceState, true, true, true, true);
+        mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
+        assertTrue(transportSelectorCallback.verifyOnWwanSelected());
+        assertTrue(transportSelectorCallback
+                .verifyOnDomainSelected(NetworkRegistrationInfo.DOMAIN_CS));
+
+        //Case 2: WPS supported by IMS and WLAN registered
+        config.putBoolean(CarrierConfigManager.KEY_SUPPORT_WPS_OVER_IMS_BOOL, true);
+        serviceState.setState(ServiceState.STATE_IN_SERVICE);
+        initialize(serviceState, true, true, true, true);
+        mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
+        assertTrue(transportSelectorCallback.verifyOnWlanSelected());
+
+        //Case 2: WPS supported by IMS and LTE registered
+        config.putBoolean(CarrierConfigManager.KEY_SUPPORT_WPS_OVER_IMS_BOOL, true);
+        serviceState.setState(ServiceState.STATE_IN_SERVICE);
+        initialize(serviceState, true, false, true, true);
+        mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
+        assertTrue(transportSelectorCallback.verifyOnWwanSelected());
+        assertTrue(transportSelectorCallback
+                .verifyOnDomainSelected(NetworkRegistrationInfo.DOMAIN_PS));
+    }
+
+    @Test
+    public void testTtyCallDomainSelection() {
+        MockTransportSelectorCallback transportSelectorCallback =
+                new MockTransportSelectorCallback();
+        DomainSelectionService.SelectionAttributes attributes =
+                new DomainSelectionService.SelectionAttributes.Builder(
+                        SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
+                        .setCallId(TEST_CALLID)
+                        .setEmergency(false)
+                        .setVideoCall(false)
+                        .setExitedFromAirplaneMode(false)
+                        .build();
+
+        //Case 1: TTY not supported by IMS and TTY enabled
+        doReturn(TelecomManager.TTY_MODE_FULL).when(mMockTelecomManager).getCurrentTtyMode();
+        PersistableBundle config = new PersistableBundle();
+        config.putBoolean(CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, false);
+        doReturn(config).when(mMockCarrierConfigMgr).getConfigForSubId(SUB_ID_1);
+        ServiceState serviceState = new ServiceState();
+        serviceState.setState(ServiceState.STATE_IN_SERVICE);
+        initialize(serviceState, true, false, true, true);
+        mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
+        assertTrue(transportSelectorCallback.verifyOnWwanSelected());
+        assertTrue(transportSelectorCallback
+                .verifyOnDomainSelected(NetworkRegistrationInfo.DOMAIN_CS));
+
+        //Case 2: TTY supported by IMS and TTY enabled
+        config.putBoolean(CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
+        mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
+        assertTrue(transportSelectorCallback.verifyOnWwanSelected());
+        assertTrue(transportSelectorCallback
+                .verifyOnDomainSelected(NetworkRegistrationInfo.DOMAIN_PS));
+
+        //Case 3: TTY supported by IMS and TTY disabled
+        doReturn(TelecomManager.TTY_MODE_OFF).when(mMockTelecomManager).getCurrentTtyMode();
+        mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
+        assertTrue(transportSelectorCallback.verifyOnWwanSelected());
+        assertTrue(transportSelectorCallback
+                .verifyOnDomainSelected(NetworkRegistrationInfo.DOMAIN_PS));
+    }
+
     static class MockTransportSelectorCallback implements TransportSelectorCallback,
             WwanSelectorCallback {
         public boolean mCreated;