Merge "Revert "Check UID in getUiccCardsInfoSecurity"" into rvc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9ee5bab..dbd7067 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -210,6 +210,7 @@
          ACTION_SIM_SLOT_STATUS_CHANGED broadcast to start activities
          from the background.  -->
     <uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
+    <uses-permission android:name="android.permission.NETWORK_STATS_PROVIDER" />
 
     <application android:name="PhoneApp"
             android:persistent="true"
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 765364a..ccef876 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -672,8 +672,8 @@
     <string name="voicemail_change_pin_dialog_title" msgid="4633077715231764435">"تغيير رقم التعريف الشخصي"</string>
     <string name="preference_category_ringtone" msgid="8787281191375434976">"نغمة الرنين والاهتزاز"</string>
     <string name="pstn_connection_service_label" msgid="9200102709997537069">"‏بطاقات SIM مدمجة"</string>
-    <string name="enable_video_calling_title" msgid="7246600931634161830">"تشغيل مكالمات الفيديو"</string>
-    <string name="enable_video_calling_dialog_msg" msgid="7141478720386203540">"‏لتشغيل مكالمات الفيديو، يجب عليك تفعيل وضع 4G LTE المحسّن في إعدادات الشبكة."</string>
+    <string name="enable_video_calling_title" msgid="7246600931634161830">"تفعيل مكالمات الفيديو"</string>
+    <string name="enable_video_calling_dialog_msg" msgid="7141478720386203540">"‏لتفعيل مكالمات الفيديو، يجب عليك تفعيل وضع 4G LTE المحسّن في إعدادات الشبكة."</string>
     <string name="enable_video_calling_dialog_settings" msgid="8697890611305307110">"إعدادات الشبكة"</string>
     <string name="enable_video_calling_dialog_close" msgid="4298929725917045270">"إغلاق"</string>
     <string name="sim_label_emergency_calls" msgid="9078241989421522310">"مكالمات الطوارئ"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index e6ba585..ba9e58f 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -525,7 +525,7 @@
     <string name="incall_error_power_off" product="watch" msgid="7191184639454113633">"Каб пазваніць, уключыце мабільную сетку, выключыце рэжым палёту або рэжым эканоміі зараду."</string>
     <string name="incall_error_power_off" product="default" msgid="8131672264311208673">"Адключыце рэжым палёту, каб зрабіць выклік."</string>
     <string name="incall_error_power_off_wfc" msgid="9125661184694727052">"Адключыце рэжым палёту або падлучыцеся да бесправадной сеткі, каб зрабіць выклік."</string>
-    <string name="incall_error_ecm_emergency_only" msgid="5622379058883722080">"Выйдзіце з рэжыму экстранных зваротных выклікаў, каб зрабіць няэкстранны выклік."</string>
+    <string name="incall_error_ecm_emergency_only" msgid="5622379058883722080">"Каб зрабіць звычайны выклік, выйдзіце з рэжыму экстранных зваротных выклікаў."</string>
     <string name="incall_error_emergency_only" msgid="8786127461027964653">"Не зарэгістраваны ў сетцы."</string>
     <string name="incall_error_out_of_service" msgid="1927265196942672791">"Мабільная сетка недаступная."</string>
     <string name="incall_error_out_of_service_wfc" msgid="4497663185857190885">"Мабільная сетка недаступная. Падлучыцеся да бесправадной сеткі, каб зрабіць выклік."</string>
@@ -620,24 +620,24 @@
     <string name="ota_try_again" msgid="6914781945599998550">"Паспрабаваць яшчэ раз"</string>
     <string name="ota_next" msgid="2041016619313475914">"Далей"</string>
     <string name="ecm_exit_dialog" msgid="4200691880721429078">"EcmExitDialog"</string>
-    <string name="phone_entered_ecm_text" msgid="8431238297843035842">"У рэжыме аварыйнага зваротнага выкліку"</string>
-    <string name="phone_in_ecm_notification_title" msgid="6825016389926367946">"Рэжым аварыйнага зваротнага выкліку"</string>
+    <string name="phone_entered_ecm_text" msgid="8431238297843035842">"У рэжыме экстранных зваротных выклікаў"</string>
+    <string name="phone_in_ecm_notification_title" msgid="6825016389926367946">"Рэжым экстранных зваротных выклікаў"</string>
     <string name="phone_in_ecm_call_notification_text" msgid="653972232922670335">"Падлучэнне для перадачы дадзеных адключана"</string>
     <string name="phone_in_ecm_notification_complete_time" msgid="7341624337163082759">"Няма злучэння для перадачы даных да <xliff:g id="COMPLETETIME">%s</xliff:g>"</string>
     <plurals name="alert_dialog_exit_ecm" formatted="false" msgid="5425906903766466743">
-      <item quantity="one">Тэлефон пяройдзе ў рэжым экстраннага зваротнага выкліку на <xliff:g id="COUNT_1">%s</xliff:g> хвіліну. У гэтым рэжыме немагчыма карыстацца праграмамі, якія выкарыстоўваюць злучэнне для перадачы даных. Жадаеце выйсці зараз?</item>
-      <item quantity="few">Тэлефон пяройдзе ў рэжым экстраннага зваротнага выкліку на <xliff:g id="COUNT_1">%s</xliff:g> хвіліны. У гэтым рэжыме немагчыма карыстацца праграмамі, якія выкарыстоўваюць злучэнне для перадачы даных. Жадаеце выйсці зараз?</item>
-      <item quantity="many">Тэлефон пяройдзе ў рэжым экстраннага зваротнага выкліку на <xliff:g id="COUNT_1">%s</xliff:g> хвілін. У гэтым рэжыме немагчыма карыстацца праграмамі, якія выкарыстоўваюць злучэнне для перадачы даных. Жадаеце выйсці зараз?</item>
-      <item quantity="other">Тэлефон пяройдзе ў рэжым экстраннага зваротнага выкліку на <xliff:g id="COUNT_1">%s</xliff:g> хвіліны. У гэтым рэжыме немагчыма карыстацца праграмамі, якія выкарыстоўваюць злучэнне для перадачы даных. Жадаеце выйсці зараз?</item>
+      <item quantity="one">Тэлефон будзе заставацца ў рэжыме экстранных зваротных выклікаў <xliff:g id="COUNT_1">%s</xliff:g> хвіліну. У гэтым рэжыме недаступныя праграмы, якія выкарыстоўваюць перадачу даных. Выйсці зараз?</item>
+      <item quantity="few">Тэлефон будзе заставацца ў рэжыме экстранных зваротных выклікаў <xliff:g id="COUNT_1">%s</xliff:g> хвіліны. У гэтым рэжыме недаступныя праграмы, якія выкарыстоўваюць перадачу даных. Выйсці зараз?</item>
+      <item quantity="many">Тэлефон будзе заставацца ў рэжыме экстранных зваротных выклікаў <xliff:g id="COUNT_1">%s</xliff:g> хвілін. У гэтым рэжыме недаступныя праграмы, якія выкарыстоўваюць перадачу даных. Выйсці зараз?</item>
+      <item quantity="other">Тэлефон будзе заставацца ў рэжыме экстранных зваротных выклікаў <xliff:g id="COUNT_1">%s</xliff:g> хвіліны. У гэтым рэжыме недаступныя праграмы, якія выкарыстоўваюць перадачу даных. Выйсці зараз?</item>
     </plurals>
     <plurals name="alert_dialog_not_avaialble_in_ecm" formatted="false" msgid="1152682528741457004">
-      <item quantity="one">Выбранае дзеянне недаступнае ў рэжыме экстраннага зваротнага выкліку. Тэлефон застанецца ў гэтым рэжыме на <xliff:g id="COUNT_1">%s</xliff:g> хвіліну. Жадаеце выйсці зараз?</item>
-      <item quantity="few">Выбранае дзеянне недаступнае ў рэжыме экстраннага зваротнага выкліку. Тэлефон застанецца ў гэтым рэжыме на <xliff:g id="COUNT_1">%s</xliff:g> хвіліны. Жадаеце выйсці зараз?</item>
-      <item quantity="many">Выбранае дзеянне недаступнае ў рэжыме экстраннага зваротнага выкліку. Тэлефон застанецца ў гэтым рэжыме на <xliff:g id="COUNT_1">%s</xliff:g> хвілін. Жадаеце выйсці зараз?</item>
-      <item quantity="other">Выбранае дзеянне недаступнае ў рэжыме экстраннага зваротнага выкліку. Тэлефон застанецца ў гэтым рэжыме на <xliff:g id="COUNT_1">%s</xliff:g> хвіліны. Жадаеце выйсці зараз?</item>
+      <item quantity="one">Выбранае дзеянне недаступнае ў рэжыме экстранных зваротных выклікаў. Тэлефон будзе заставацца ў гэтым рэжыме <xliff:g id="COUNT_1">%s</xliff:g> хвіліну. Выйсці зараз?</item>
+      <item quantity="few">Выбранае дзеянне недаступнае ў рэжыме экстранных зваротных выклікаў. Тэлефон будзе заставацца ў гэтым рэжыме <xliff:g id="COUNT_1">%s</xliff:g> хвіліны. Выйсці зараз?</item>
+      <item quantity="many">Выбранае дзеянне недаступнае ў рэжыме экстранных зваротных выклікаў. Тэлефон будзе заставацца ў гэтым рэжыме <xliff:g id="COUNT_1">%s</xliff:g> хвілін. Выйсці зараз?</item>
+      <item quantity="other">Выбранае дзеянне недаступнае ў рэжыме экстранных зваротных выклікаў. Тэлефон будзе заставацца ў гэтым рэжыме <xliff:g id="COUNT_1">%s</xliff:g> хвіліны. Выйсці зараз?</item>
     </plurals>
     <string name="alert_dialog_in_ecm_call" msgid="1207545603149771978">"Выбранае дзеянне недаступнае падчас экстранага выкліку."</string>
-    <string name="progress_dialog_exiting_ecm" msgid="9159080081676927217">"Выхад з рэжыму экстранага выкліку"</string>
+    <string name="progress_dialog_exiting_ecm" msgid="9159080081676927217">"Выконваецца выхад з рэжыму экстранных зваротных выклікаў"</string>
     <string name="alert_dialog_yes" msgid="3532525979632841417">"Так"</string>
     <string name="alert_dialog_no" msgid="1075632654085988420">"Не"</string>
     <string name="alert_dialog_dismiss" msgid="1336356286354517054">"Адхіліць"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 97a0cf4..a9ddc42 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -100,7 +100,7 @@
     <string name="sum_cw_enabled" msgid="3977308526187139996">"Durante una llamada, notificarme sobre las llamadas entrantes"</string>
     <string name="sum_cw_disabled" msgid="3658094589461768637">"Durante una llamada, notificarme sobre las llamadas entrantes"</string>
     <string name="call_forwarding_settings" msgid="8937130467468257671">"Desvío de llamadas"</string>
-    <string name="call_forwarding_settings_with_label" msgid="2345432813399564272">"Configuración de desvío de llamada (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+    <string name="call_forwarding_settings_with_label" msgid="2345432813399564272">"Configuración de desvío de llamadas (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
     <string name="labelCF" msgid="3578719437928476078">"Desvío de llamadas"</string>
     <string name="labelCFU" msgid="8870170873036279706">"Desviar siempre"</string>
     <string name="messageCFU" msgid="1361806450979589744">"Usar siempre este número"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index d996e85..3c7d185 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -569,7 +569,7 @@
     <string name="onscreenShowDialpadText" msgid="658465753816164079">"Teclado"</string>
     <string name="onscreenMuteText" msgid="5470306116733843621">"Silenciar"</string>
     <string name="onscreenAddCallText" msgid="9075675082903611677">"Añadir llamada"</string>
-    <string name="onscreenMergeCallsText" msgid="3692389519611225407">"Llamada a tres"</string>
+    <string name="onscreenMergeCallsText" msgid="3692389519611225407">"Combinar llamadas"</string>
     <string name="onscreenSwapCallsText" msgid="2682542150803377991">"Cambiar"</string>
     <string name="onscreenManageCallsText" msgid="1162047856081836469">"Administrar llamadas"</string>
     <string name="onscreenManageConferenceText" msgid="4700574060601755137">"Gestionar llamada de conferencia"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index e10b265..a049b5d 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -621,27 +621,27 @@
     <string name="ota_next" msgid="2041016619313475914">"Berikutnya"</string>
     <string name="ecm_exit_dialog" msgid="4200691880721429078">"EcmExitDialog"</string>
     <string name="phone_entered_ecm_text" msgid="8431238297843035842">"Masukkan Mode Telepon Balik Darurat"</string>
-    <string name="phone_in_ecm_notification_title" msgid="6825016389926367946">"Mode Panggilan Balik Darurat"</string>
+    <string name="phone_in_ecm_notification_title" msgid="6825016389926367946">"Mode Telepon Balik Darurat"</string>
     <string name="phone_in_ecm_call_notification_text" msgid="653972232922670335">"Sambungan data dinonaktifkan"</string>
     <string name="phone_in_ecm_notification_complete_time" msgid="7341624337163082759">"Tidak ada koneksi data sampai <xliff:g id="COMPLETETIME">%s</xliff:g>"</string>
     <plurals name="alert_dialog_exit_ecm" formatted="false" msgid="5425906903766466743">
-      <item quantity="other">Ponsel ini akan berada dalam mode Panggilan Balik Darurat selama <xliff:g id="COUNT_1">%s</xliff:g> menit. Saat dalam mode ini, aplikasi yang menggunakan sambungan data tidak dapat digunakan. Ingin keluar sekarang?</item>
-      <item quantity="one">Ponsel ini akan berada dalam mode Panggilan Balik Darurat selama <xliff:g id="COUNT_0">%s</xliff:g> menit. Saat dalam mode ini, aplikasi yang menggunakan sambungan data tidak dapat digunakan. Ingin keluar sekarang?</item>
+      <item quantity="other">Ponsel ini akan berada dalam mode Telepon Balik Darurat selama <xliff:g id="COUNT_1">%s</xliff:g> menit. Saat dalam mode ini, aplikasi yang menggunakan sambungan data tidak dapat digunakan. Ingin keluar sekarang?</item>
+      <item quantity="one">Ponsel ini akan berada dalam mode Telepon Balik Darurat selama <xliff:g id="COUNT_0">%s</xliff:g> menit. Saat dalam mode ini, aplikasi yang menggunakan sambungan data tidak dapat digunakan. Ingin keluar sekarang?</item>
     </plurals>
     <plurals name="alert_dialog_not_avaialble_in_ecm" formatted="false" msgid="1152682528741457004">
-      <item quantity="other">Tindakan yang dipilih tidak tersedia saat dalam mode Panggilan Balik Darurat. Ponsel ini akan berada dalam mode ini selama <xliff:g id="COUNT_1">%s</xliff:g> menit. Ingin keluar sekarang?</item>
-      <item quantity="one">Tindakan yang dipilih tidak tersedia saat dalam mode Panggilan Balik Darurat. Ponsel ini akan berada dalam mode ini selama <xliff:g id="COUNT_0">%s</xliff:g> menit. Ingin keluar sekarang?</item>
+      <item quantity="other">Tindakan yang dipilih tidak tersedia saat dalam mode Telepon Balik Darurat. Ponsel ini akan berada dalam mode ini selama <xliff:g id="COUNT_1">%s</xliff:g> menit. Ingin keluar sekarang?</item>
+      <item quantity="one">Tindakan yang dipilih tidak tersedia saat dalam mode Telepon Balik Darurat. Ponsel ini akan berada dalam mode ini selama <xliff:g id="COUNT_0">%s</xliff:g> menit. Ingin keluar sekarang?</item>
     </plurals>
     <string name="alert_dialog_in_ecm_call" msgid="1207545603149771978">"Tindakan yang dipilih tidak tersedia ketika dalam panggilan darurat."</string>
     <string name="progress_dialog_exiting_ecm" msgid="9159080081676927217">"Keluar dari mode Telepon Balik Darurat"</string>
     <string name="alert_dialog_yes" msgid="3532525979632841417">"Ya"</string>
     <string name="alert_dialog_no" msgid="1075632654085988420">"Tidak"</string>
     <string name="alert_dialog_dismiss" msgid="1336356286354517054">"Tutup"</string>
-    <string name="phone_in_ecm_call_notification_text_without_data_restriction_hint" msgid="3747860785153531225">"Ponsel berada dalam mode panggilan balik darurat."</string>
+    <string name="phone_in_ecm_call_notification_text_without_data_restriction_hint" msgid="3747860785153531225">"Ponsel berada dalam mode telepon balik darurat."</string>
     <string name="phone_in_ecm_notification_complete_time_without_data_restriction_hint" msgid="3690292264812050858">"Sampai <xliff:g id="COMPLETETIME">%s</xliff:g>"</string>
     <plurals name="alert_dialog_exit_ecm_without_data_restriction_hint" formatted="false" msgid="6477733043040328640">
-      <item quantity="other">Ponsel akan berada dalam mode panggilan balik darurat selama <xliff:g id="COUNT_1">%s</xliff:g> menit.\nApakah Anda ingin keluar sekarang?</item>
-      <item quantity="one">Ponsel akan berada dalam mode panggilan balik darurat selama <xliff:g id="COUNT_0">%s</xliff:g> menit.\nApakah Anda ingin keluar sekarang?</item>
+      <item quantity="other">Ponsel akan berada dalam mode telepon balik darurat selama <xliff:g id="COUNT_1">%s</xliff:g> menit.\nApakah Anda ingin keluar sekarang?</item>
+      <item quantity="one">Ponsel akan berada dalam mode telepon balik darurat selama <xliff:g id="COUNT_0">%s</xliff:g> menit.\nApakah Anda ingin keluar sekarang?</item>
     </plurals>
     <string name="voicemail_provider" msgid="4158806657253745294">"Layanan"</string>
     <string name="voicemail_settings" msgid="4451045613238972776">"Penyiapan"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index bfd6047..338c253 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -288,7 +288,7 @@
     <string name="limited_sim_function_notification_message" msgid="5338638075496721160">"ଅନ୍ୟ SIM ବ୍ୟବହାର କରିବା ସମୟରେ <xliff:g id="CARRIER_NAME">%1$s</xliff:g> କଲ୍ ଏବଂ ଡାଟା ସେବାଗୁଡ଼ିକ ବ୍ଲକ୍ କରାଯାଇପାରେ।"</string>
     <string name="data_usage_title" msgid="8438592133893837464">"ଆପ୍‌ ଦ୍ୱାରା ଡାଟା ବ୍ୟବହାର"</string>
     <string name="data_usage_template" msgid="6287906680674061783">"<xliff:g id="ID_2">%2$s</xliff:g>ରେ <xliff:g id="ID_1">%1$s</xliff:g> ମୋବାଇଲ୍ ଡାଟା ବ୍ୟବହାର କରାଯାଇଛି"</string>
-    <string name="advanced_options_title" msgid="9208195294513520934">"ଆଧୁନିକ"</string>
+    <string name="advanced_options_title" msgid="9208195294513520934">"ଉନ୍ନତ"</string>
     <string name="carrier_settings_euicc" msgid="1190237227261337749">"ନେଟୱର୍କ କ୍ୟାରିଅର"</string>
     <string name="keywords_carrier_settings_euicc" msgid="8540160967922063745">"ମୋବାଇଲ୍ ଓ ଇଣ୍ଟରନେଟ୍ ସେବା ପ୍ରଦାନକାରୀ କମ୍ପାନୀ, ଇସିମ୍, ସିମ୍, euicc, ମୋବାଇଲ୍ ଓ ଇଣ୍ଟରନେଟ୍ ସେବା ପ୍ରଦାନକାରୀ କମ୍ପାନୀକୁ ସ୍ଵିଚ୍ କରନ୍ତୁ, ମୋବାଇଲ୍ ଓ ଇଣ୍ଟରନେଟ୍ ସେବା ପ୍ରଦାନକାରୀ କମ୍ପାନୀକୁ ଯୋଡ଼ନ୍ତୁ"</string>
     <string name="carrier_settings_euicc_summary" msgid="2027941166597330117">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g> — <xliff:g id="PHONE_NUMBER">%2$s</xliff:g>"</string>
@@ -879,7 +879,7 @@
     <string name="radio_info_current_network_label" msgid="3052098695239642450">"ବର୍ତ୍ତମାନର ନେଟ୍‌ୱାର୍କ:"</string>
     <string name="radio_info_ppp_received_label" msgid="5753592451640644889">"ଡାଟା ପ୍ରାପ୍ତ ହୋଇଛି:"</string>
     <string name="radio_info_gsm_service_label" msgid="6443348321714241328">"ଭଏସ୍ ସେବା:"</string>
-    <string name="radio_info_signal_strength_label" msgid="5545444702102543260">"ସିଗ୍‌ନାଲ୍ ଶକ୍ତି:"</string>
+    <string name="radio_info_signal_strength_label" msgid="5545444702102543260">"ସିଗ୍‌ନାଲ୍ ଦକ୍ଷତା:"</string>
     <string name="radio_info_call_status_label" msgid="7693575431923095487">"ଭଏସ୍ କଲ୍ ସ୍ଥିତି:"</string>
     <string name="radio_info_ppp_sent_label" msgid="6542208429356199695">"ଡାଟା ପଠାଯାଇଛି:"</string>
     <string name="radio_info_message_waiting_label" msgid="1886549432566952078">"ବାର୍ତ୍ତା ଅପକ୍ଷାରତ:"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index 423236d..2f0fcc6 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -263,7 +263,7 @@
 
     <!-- Array of countries that support sim-less emergency RTT calls. Values should be
          ISO3166 country codes in lowercase. -->
-    <string-array name="config_simless_emergency_rtt_supported_countries">
+    <string-array name="config_simless_emergency_rtt_supported_countries" translatable="false">
         <item>us</item>
     </string-array>
 
diff --git a/src/com/android/phone/CallNotifier.java b/src/com/android/phone/CallNotifier.java
index 5b14591..6c18623 100644
--- a/src/com/android/phone/CallNotifier.java
+++ b/src/com/android/phone/CallNotifier.java
@@ -560,7 +560,7 @@
     public void updatePhoneStateListeners(boolean isRefresh, int updateType, int subIdToUpdate) {
         List<SubscriptionInfo> subInfos = SubscriptionController.getInstance()
                 .getActiveSubscriptionInfoList(mApplication.getOpPackageName(),
-                        mApplication.getFeatureId());
+                        mApplication.getAttributionTag());
 
         // Sort sub id list based on slot id, so that CFI/MWI notifications will be updated for
         // slot 0 first then slot 1. This is needed to ensure that when CFI or MWI is enabled for
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 351aaa9..9699e1b 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -21,6 +21,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -37,6 +38,7 @@
 import android.os.IBinder;
 import android.os.Message;
 import android.os.PersistableBundle;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.UserHandle;
@@ -49,6 +51,7 @@
 import android.telephony.TelephonyFrameworkInitializer;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.LocalLog;
 import android.util.Log;
 
@@ -73,6 +76,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 
 /**
  * CarrierConfigLoader binds to privileged carrier apps to fetch carrier config overlays.
@@ -632,8 +636,14 @@
             }
         }
         intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, phoneId);
-        logd("Broadcast CARRIER_CONFIG_CHANGED for phone " + phoneId);
         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+        int[] subIds = SubscriptionManager.getSubId(phoneId);
+        if (subIds != null && subIds.length > 0) {
+            logd("Broadcast CARRIER_CONFIG_CHANGED for phone " + phoneId + ", subId=" + subIds[0]);
+        } else {
+            logd("Broadcast CARRIER_CONFIG_CHANGED for phone " + phoneId);
+        }
+
         mHasSentConfigChange[phoneId] = true;
     }
 
@@ -1101,8 +1111,18 @@
                     + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
             return;
         }
+        String requestingPackage = null;
+        int requestingPackageIndex = ArrayUtils.indexOf(args, DUMP_ARG_REQUESTING_PACKAGE);
+        if (requestingPackageIndex >= 0 && requestingPackageIndex < args.length - 1
+                && !TextUtils.isEmpty(args[requestingPackageIndex + 1])) {
+            requestingPackage = args[requestingPackageIndex + 1];
+            // Throws a SecurityException if the caller is impersonating another app in an effort to
+            // dump extra info (which may contain PII the caller doesn't have a right to).
+            enforceCallerIsSystemOrRequestingPackage(requestingPackage);
+        }
+
         indentPW.println("CarrierConfigLoader: " + this);
-        for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
+        for (int i = 0; i < TelephonyManager.from(mContext).getActiveModemCount(); i++) {
             indentPW.println("Phone Id = " + i);
             // display default values in CarrierConfigManager
             printConfig(CarrierConfigManager.getDefaultConfig(), indentPW,
@@ -1118,17 +1138,15 @@
         indentPW.println("CarrierConfigLoadingLog=");
         mCarrierConfigLoadingLog.dump(fd, indentPW, args);
 
-        int requestingPackageIndex = ArrayUtils.indexOf(args, DUMP_ARG_REQUESTING_PACKAGE);
-        if (requestingPackageIndex != -1 && requestingPackageIndex < args.length - 1
-                && !TextUtils.isEmpty(args[requestingPackageIndex + 1])) {
-            String requestingPackage = args[requestingPackageIndex + 1];
-            indentPW.println("");
+        if (requestingPackage != null) {
             logd("Including default and requesting package " + requestingPackage
                     + " carrier services in dump");
+            indentPW.println("");
             indentPW.println("Connected services");
             dumpCarrierServiceIfBound(fd, indentPW, "Default config package",
-                    mPlatformCarrierConfigPackage);
-            dumpCarrierServiceIfBound(fd, indentPW, "Requesting package", requestingPackage);
+                    mPlatformCarrierConfigPackage, false /* considerCarrierPrivileges */);
+            dumpCarrierServiceIfBound(fd, indentPW, "Requesting package", requestingPackage,
+                    true /* considerCarrierPrivileges */);
         }
     }
 
@@ -1162,63 +1180,126 @@
         indentPW.println("");
     }
 
+    /**
+     * Passes without problem when one of these conditions is true:
+     * - The caller is a privileged UID (e.g. for dumpstate.cpp generating a bug report, where the
+     * system knows the true caller plumbed in through the {@link android.os.BugreportManager} API).
+     * - The caller's UID matches the supplied package.
+     *
+     * @throws SecurityException if none of the above conditions are met.
+     */
+    private void enforceCallerIsSystemOrRequestingPackage(String requestingPackage)
+            throws SecurityException {
+        final int callingUid = Binder.getCallingUid();
+        if (callingUid == Process.ROOT_UID || callingUid == Process.SYSTEM_UID
+                || callingUid == Process.SHELL_UID || callingUid == Process.PHONE_UID) {
+            // Bug reports (dumpstate.cpp) run as SHELL, and let some other privileged UIDs through
+            // as well.
+            return;
+        }
+        // An app is trying to dump extra detail, block it if they aren't who they claim to be.
+        AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
+        if (appOps == null) {
+            throw new SecurityException("No AppOps");
+        }
+        // Will throw a SecurityException if the UID and package don't match.
+        appOps.checkPackage(callingUid, requestingPackage);
+    }
+
+    /**
+     * Searches for one or more appropriate {@link CarrierService} instances to dump based on the
+     * current connections.
+     *
+     * @param targetPkgName             the target package name to dump carrier services for
+     * @param considerCarrierPrivileges if true, allow a carrier service to be dumped if it shares
+     *                                  carrier privileges with {@code targetPkgName};
+     *                                  otherwise, only dump a carrier service if it is {@code
+     *                                  targetPkgName}
+     */
     private void dumpCarrierServiceIfBound(FileDescriptor fd, IndentingPrintWriter indentPW,
-            String prefix, String pkgName) {
+            String prefix, String targetPkgName, boolean considerCarrierPrivileges) {
         // Null package is possible if it's early in the boot process, there was a recent crash, we
         // loaded the config from XML most recently, or a SIM slot is empty. Carrier apps with
         // long-lived bindings should typically get dumped here regardless. Even if an app is being
         // used for multiple phoneIds, we assume that it's smart enough to handle that on its own,
         // and that in most cases we'd just be dumping duplicate information and bloating a report.
         indentPW.increaseIndent();
-        indentPW.println(prefix + " : " + pkgName);
+        indentPW.println(prefix + " : " + targetPkgName);
+        Set<String> dumpedPkgNames = new ArraySet<>(mServiceConnection.length);
         for (CarrierServiceConnection connection : mServiceConnection) {
-            try {
-                // We don't pay attention to mServiceBound[connection.phoneId] because typically
-                // carrier apps will request long-lived bindings, and even if we unbind the app, it
-                // may still be alive due to CarrierServiceBindHelper.
-                if (connection == null || connection.service == null || !TextUtils.equals(pkgName,
-                        connection.pkgName) || !connection.service.isBinderAlive()
-                        || !connection.service.pingBinder()) {
-                    continue;
-                }
-                // Flush before we let the app output anything to ensure correct ordering of output.
-                // Internally, Binder#dump calls flush on its printer after finishing so we don't
-                // need to after the call finishes.
-                indentPW.flush();
-                try {
-                    logd("Dumping " + pkgName);
-                    // We don't need to give the carrier service any args.
-                    connection.service.dump(fd, null /* args */);
-                    logd("Done with " + pkgName);
-                    indentPW.decreaseIndent();
-                    indentPW.println("");
-                    return;
-                } catch (RemoteException e) {
-                    indentPW.println("RemoteException");
-                    logd("RemoteException from " + pkgName, e);
-                    e.printStackTrace(indentPW);
-                    indentPW.decreaseIndent();
-                    indentPW.println("");
-                    return;
-                }
-            } catch (NullPointerException e) {
-                // Highly unlikely, but possible if the carrier app was just unbound right before we
-                // we tried to dump it so the binder was reset to null. Loop in case we have more
-                // candidates on other phoneIds.
-                logd("NullPointerException from " + pkgName, e);
+            if (connection == null || !SubscriptionManager.isValidPhoneId(connection.phoneId)
+                    || TextUtils.isEmpty(connection.pkgName)) {
+                continue;
             }
+            final String servicePkgName = connection.pkgName;
+            // Note: we intentionally ignore system components here because we should NOT match the
+            // shell caller that's typically used for bug reports via non-BugreportManager triggers.
+            final boolean exactPackageMatch = TextUtils.equals(targetPkgName, servicePkgName);
+            final boolean carrierPrivilegesMatch =
+                    considerCarrierPrivileges && hasCarrierPrivileges(targetPkgName,
+                            connection.phoneId);
+            if (!exactPackageMatch && !carrierPrivilegesMatch) continue;
+            // Make sure this service is actually alive before trying to dump it. We don't pay
+            // attention to mServiceBound[connection.phoneId] because typically carrier apps will
+            // request long-lived bindings, and even if we unbind the app, it may still be alive due
+            // to CarrierServiceBindHelper. Pull it out as a reference so even if it gets set to
+            // null within the ServiceConnection during unbinding we can avoid an NPE.
+            final IBinder service = connection.service;
+            if (service == null || !service.isBinderAlive() || !service.pingBinder()) continue;
+            // We've got a live service. Last check is just to make sure we don't dump a package
+            // multiple times.
+            if (!dumpedPkgNames.add(servicePkgName)) continue;
+            if (!exactPackageMatch) {
+                logd(targetPkgName + " has carrier privileges on phoneId " + connection.phoneId
+                        + ", service provided by " + servicePkgName);
+                indentPW.increaseIndent();
+                indentPW.println("Proxy : " + servicePkgName);
+                indentPW.decreaseIndent();
+            }
+            // Flush before we let the app output anything to ensure correct ordering of output.
+            // Internally, Binder#dump calls flush on its printer after finishing so we don't
+            // need to do anything after.
+            indentPW.flush();
+            try {
+                logd("Dumping " + servicePkgName);
+                // We don't need to give the carrier service any args.
+                connection.service.dump(fd, null /* args */);
+                logd("Done with " + servicePkgName);
+            } catch (RemoteException e) {
+                logd("RemoteException from " + servicePkgName, e);
+                indentPW.increaseIndent();
+                indentPW.println("RemoteException");
+                indentPW.increaseIndent();
+                e.printStackTrace(indentPW);
+                indentPW.decreaseIndent();
+                indentPW.decreaseIndent();
+                // We won't retry this package again because now it's in dumpedPkgNames.
+            }
+            indentPW.println("");
         }
-        indentPW.increaseIndent();
-        indentPW.println("Not bound");
+        if (dumpedPkgNames.isEmpty()) {
+            indentPW.increaseIndent();
+            indentPW.println("Not bound");
+            indentPW.decreaseIndent();
+            indentPW.println("");
+        }
         indentPW.decreaseIndent();
-        indentPW.decreaseIndent();
-        indentPW.println("");
+    }
+
+    private boolean hasCarrierPrivileges(String pkgName, int phoneId) {
+        int[] subIds = SubscriptionManager.getSubId(phoneId);
+        if (ArrayUtils.isEmpty(subIds)) {
+            return false;
+        }
+        return TelephonyManager.from(mContext).createForSubscriptionId(
+                subIds[0]).checkCarrierPrivilegesForPackage(pkgName)
+                == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
     }
 
     private class CarrierServiceConnection implements ServiceConnection {
-        int phoneId;
-        String pkgName;
-        int eventId;
+        final int phoneId;
+        final String pkgName;
+        final int eventId;
         IBinder service;
 
         CarrierServiceConnection(int phoneId, String pkgName, int eventId) {
diff --git a/src/com/android/phone/EmergencyCallbackModeExitDialog.java b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
index 6edc155..1210627 100644
--- a/src/com/android/phone/EmergencyCallbackModeExitDialog.java
+++ b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
@@ -35,6 +35,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 
 import com.android.internal.telephony.Phone;
@@ -330,7 +331,8 @@
             // Received exit Emergency Callback Mode notification close all dialogs
             if (intent.getAction().equals(
                     TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
-                if (intent.getBooleanExtra("phoneinECMState", false) == false) {
+                // Cancel if the sticky broadcast extra for whether or not we are in ECM is false.
+                if (!intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false)) {
                     if (mAlertDialog != null)
                         mAlertDialog.dismiss();
                     if (mProgressDialog != null)
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 19e0761..810ccdf 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -476,7 +476,8 @@
     }
 
     public PersistableBundle getCarrierConfigForSubId(int subId) {
-        return configLoader.getConfigForSubIdWithFeature(subId, getOpPackageName(), getFeatureId());
+        return configLoader.getConfigForSubIdWithFeature(subId, getOpPackageName(),
+                getAttributionTag());
     }
 
     private void registerSettingsObserver() {
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 0e909a6..ec6e0c6 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -1027,14 +1027,47 @@
                     onCompleted = obtainMessage(EVENT_GET_MODEM_ACTIVITY_INFO_DONE, request);
                     if (defaultPhone != null) {
                         defaultPhone.getModemActivityInfo(onCompleted, request.workSource);
+                    } else {
+                        ResultReceiver result = (ResultReceiver) request.argument;
+                        Bundle bundle = new Bundle();
+                        bundle.putParcelable(TelephonyManager.MODEM_ACTIVITY_RESULT_KEY,
+                                new ModemActivityInfo(0, 0, 0, new int[0], 0));
+                        result.send(0, bundle);
                     }
                     break;
 
                 case EVENT_GET_MODEM_ACTIVITY_INFO_DONE:
                     ar = (AsyncResult) msg.obj;
                     request = (MainThreadRequest) ar.userObj;
+                    ResultReceiver result = (ResultReceiver) request.argument;
+
+                    ModemActivityInfo ret = new ModemActivityInfo(0, 0, 0, new int[0], 0);
                     if (ar.exception == null && ar.result != null) {
-                        request.result = ar.result;
+                        // Update the last modem activity info and the result of the request.
+                        ModemActivityInfo info = (ModemActivityInfo) ar.result;
+                        if (isModemActivityInfoValid(info)) {
+                            int[] mergedTxTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
+                            int[] txTimeMs = info.getTransmitTimeMillis();
+                            int[] lastModemTxTimeMs = mLastModemActivityInfo
+                                    .getTransmitTimeMillis();
+                            for (int i = 0; i < mergedTxTimeMs.length; i++) {
+                                mergedTxTimeMs[i] = txTimeMs[i] + lastModemTxTimeMs[i];
+                            }
+                            mLastModemActivityInfo.setTimestamp(info.getTimestamp());
+                            mLastModemActivityInfo.setSleepTimeMillis(info.getSleepTimeMillis()
+                                    + mLastModemActivityInfo.getSleepTimeMillis());
+                            mLastModemActivityInfo.setIdleTimeMillis(info.getIdleTimeMillis()
+                                    + mLastModemActivityInfo.getIdleTimeMillis());
+                            mLastModemActivityInfo.setTransmitTimeMillis(mergedTxTimeMs);
+                            mLastModemActivityInfo.setReceiveTimeMillis(
+                                    info.getReceiveTimeMillis()
+                                            + mLastModemActivityInfo.getReceiveTimeMillis());
+                        }
+                        ret = new ModemActivityInfo(mLastModemActivityInfo.getTimestamp(),
+                                mLastModemActivityInfo.getSleepTimeMillis(),
+                                mLastModemActivityInfo.getIdleTimeMillis(),
+                                mLastModemActivityInfo.getTransmitTimeMillis(),
+                                mLastModemActivityInfo.getReceiveTimeMillis());
                     } else {
                         if (ar.result == null) {
                             loge("queryModemActivityInfo: Empty response");
@@ -1045,10 +1078,9 @@
                             loge("queryModemActivityInfo: Unknown exception");
                         }
                     }
-                    // Result cannot be null. Return ModemActivityInfo with all fields set to 0.
-                    if (request.result == null) {
-                        request.result = new ModemActivityInfo(0, 0, 0, new int[0], 0);
-                    }
+                    Bundle bundle = new Bundle();
+                    bundle.putParcelable(TelephonyManager.MODEM_ACTIVITY_RESULT_KEY, ret);
+                    result.send(0, bundle);
                     notifyRequester(request);
                     break;
 
@@ -2286,7 +2318,7 @@
             // is on IWLAN.
             if (TelephonyManager.NETWORK_TYPE_IWLAN
                     == getVoiceNetworkTypeForSubscriber(subId, mApp.getPackageName(),
-                    mApp.getFeatureId())) {
+                    mApp.getAttributionTag())) {
                 return "";
             }
             Phone phone = PhoneFactory.getPhone(phoneId);
@@ -3031,14 +3063,15 @@
     }
 
     @Override
-    public void sendVisualVoicemailSmsForSubscriber(String callingPackage, int subId,
-            String number, int port, String text, PendingIntent sentIntent) {
+    public void sendVisualVoicemailSmsForSubscriber(String callingPackage,
+            String callingAttributionTag, int subId, String number, int port, String text,
+            PendingIntent sentIntent) {
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
         enforceVisualVoicemailPackage(callingPackage, subId);
         enforceSendSmsPermission();
         SmsController smsController = PhoneFactory.getSmsController();
-        smsController.sendVisualVoicemailSmsForSubscriber(callingPackage, subId, number, port, text,
-                sentIntent);
+        smsController.sendVisualVoicemailSmsForSubscriber(callingPackage, callingAttributionTag,
+                subId, number, port, text, sentIntent);
     }
 
     /**
@@ -3422,6 +3455,9 @@
             Phone phone = getPhone(subId);
             if (phone == null) return false;
             return phone.isImsCapabilityAvailable(capability, regTech);
+        } catch (com.android.ims.ImsException e) {
+            Log.w(LOG_TAG, "IMS isAvailable - service unavailable: " + e.getMessage());
+            return false;
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -6132,7 +6168,7 @@
             final List<String> mergedSubscriberIds = new ArrayList<>();
             final List<SubscriptionInfo> groupInfos = SubscriptionController.getInstance()
                     .getSubscriptionsInGroup(groupUuid, mApp.getOpPackageName(),
-                            mApp.getFeatureId());
+                            mApp.getAttributionTag());
             for (SubscriptionInfo subInfo : groupInfos) {
                 subscriberId = telephonyManager.getSubscriberId(subInfo.getSubscriptionId());
                 if (subscriberId != null) {
@@ -6574,7 +6610,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             final SubscriptionInfo info = mSubscriptionController.getActiveSubscriptionInfo(subId,
-                    phone.getContext().getOpPackageName(), phone.getContext().getFeatureId());
+                    phone.getContext().getOpPackageName(), phone.getContext().getAttributionTag());
             if (info == null) {
                 log("getSimLocaleForSubscriber, inactive subId: " + subId);
                 return null;
@@ -6613,7 +6649,7 @@
 
     private List<SubscriptionInfo> getAllSubscriptionInfoList() {
         return mSubscriptionController.getAllSubInfoList(mApp.getOpPackageName(),
-                mApp.getFeatureId());
+                mApp.getAttributionTag());
     }
 
     /**
@@ -6621,7 +6657,7 @@
      */
     private List<SubscriptionInfo> getActiveSubscriptionInfoListPrivileged() {
         return mSubscriptionController.getActiveSubscriptionInfoList(mApp.getOpPackageName(),
-                mApp.getFeatureId());
+                mApp.getAttributionTag());
     }
 
     private final ModemActivityInfo mLastModemActivityInfo =
@@ -6642,38 +6678,7 @@
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            ModemActivityInfo ret = null;
-            synchronized (mLastModemActivityInfo) {
-                ModemActivityInfo info = (ModemActivityInfo) sendRequest(
-                        CMD_GET_MODEM_ACTIVITY_INFO,
-                        null, workSource);
-                if (isModemActivityInfoValid(info)) {
-                    int[] mergedTxTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
-                    int[] txTimeMs = info.getTransmitTimeMillis();
-                    int[] lastModemTxTimeMs = mLastModemActivityInfo.getTransmitTimeMillis();
-                    for (int i = 0; i < mergedTxTimeMs.length; i++) {
-                        mergedTxTimeMs[i] = txTimeMs[i] + lastModemTxTimeMs[i];
-                    }
-                    mLastModemActivityInfo.setTimestamp(info.getTimestamp());
-                    mLastModemActivityInfo.setSleepTimeMillis(info.getSleepTimeMillis()
-                            + mLastModemActivityInfo.getSleepTimeMillis());
-                    mLastModemActivityInfo.setIdleTimeMillis(
-                            info.getIdleTimeMillis() + mLastModemActivityInfo.getIdleTimeMillis());
-                    mLastModemActivityInfo.setTransmitTimeMillis(mergedTxTimeMs);
-                    mLastModemActivityInfo.setReceiveTimeMillis(
-                            info.getReceiveTimeMillis() + mLastModemActivityInfo
-                                .getReceiveTimeMillis());
-                }
-
-                ret = new ModemActivityInfo(mLastModemActivityInfo.getTimestamp(),
-                        mLastModemActivityInfo.getSleepTimeMillis(),
-                        mLastModemActivityInfo.getIdleTimeMillis(),
-                        mLastModemActivityInfo.getTransmitTimeMillis(),
-                        mLastModemActivityInfo.getReceiveTimeMillis());
-            }
-            Bundle bundle = new Bundle();
-            bundle.putParcelable(TelephonyManager.MODEM_ACTIVITY_RESULT_KEY, ret);
-            result.send(0, bundle);
+            sendRequestAsync(CMD_GET_MODEM_ACTIVITY_INFO, result, null, workSource);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -7873,7 +7878,7 @@
     }
 
     @Override
-    public void updateTestOtaEmergencyNumberDbFilePath(String otaFilePath) {
+    public void updateOtaEmergencyNumberDbFilePath(ParcelFileDescriptor otaParcelFileDescriptor) {
         enforceActiveEmergencySessionPermission();
 
         final long identity = Binder.clearCallingIdentity();
@@ -7881,7 +7886,24 @@
             for (Phone phone: PhoneFactory.getPhones()) {
                 EmergencyNumberTracker tracker = phone.getEmergencyNumberTracker();
                 if (tracker != null) {
-                    tracker.updateTestOtaEmergencyNumberDbFilePath(otaFilePath);
+                    tracker.updateOtaEmergencyNumberDbFilePath(otaParcelFileDescriptor);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void resetOtaEmergencyNumberDbFilePath() {
+        enforceActiveEmergencySessionPermission();
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            for (Phone phone: PhoneFactory.getPhones()) {
+                EmergencyNumberTracker tracker = phone.getEmergencyNumberTracker();
+                if (tracker != null) {
+                    tracker.resetOtaEmergencyNumberDbFilePath();
                 }
             }
         } finally {
@@ -8222,6 +8244,7 @@
 
     @Override
     public boolean isMvnoMatched(int subId, int mvnoType, @NonNull String mvnoMatchData) {
+        enforceReadPrivilegedPermission("isMvnoMatched");
         IccRecords iccRecords = UiccController.getInstance().getIccRecords(
                 SubscriptionManager.getPhoneId(subId), UiccController.APP_FAM_3GPP);
         if (iccRecords == null) {
@@ -8232,13 +8255,15 @@
     }
 
     @Override
-    public void enqueueSmsPickResult(String callingPackage, IIntegerConsumer pendingSubIdResult) {
+    public void enqueueSmsPickResult(String callingPackage, String callingAttributionTag,
+            IIntegerConsumer pendingSubIdResult) {
         if (callingPackage == null) {
             callingPackage = getCurrentPackageName();
         }
         SmsPermissions permissions = new SmsPermissions(getDefaultPhone(), mApp,
                 (AppOpsManager) mApp.getSystemService(Context.APP_OPS_SERVICE));
-        if (!permissions.checkCallingCanSendSms(callingPackage, "Sending message")) {
+        if (!permissions.checkCallingCanSendSms(callingPackage, callingAttributionTag,
+                "Sending message")) {
             throw new SecurityException("Requires SEND_SMS permission to perform this operation");
         }
         PickSmsSubscriptionActivity.addPendingResult(pendingSubIdResult);
diff --git a/src/com/android/phone/settings/RadioInfo.java b/src/com/android/phone/settings/RadioInfo.java
index a639637..31b7a9e 100644
--- a/src/com/android/phone/settings/RadioInfo.java
+++ b/src/com/android/phone/settings/RadioInfo.java
@@ -1449,8 +1449,18 @@
     OnCheckedChangeListener mRadioPowerOnChangeListener = new OnCheckedChangeListener() {
         @Override
         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-            log("toggle radio power: currently " + (isRadioOn() ? "on" : "off"));
-            mPhone.setRadioPower(isChecked);
+            // TODO: b/145681511. Within current design, radio power on all of the phones need
+            // to be controlled at the same time.
+            Phone[] phones = PhoneFactory.getPhones();
+            if (phones == null) {
+                return;
+            }
+            log("toggle radio power: phone*" + phones.length + " " + (isRadioOn() ? "on" : "off"));
+            for (int phoneIndex = 0; phoneIndex < phones.length; phoneIndex++) {
+                if (phones[phoneIndex] != null) {
+                    phones[phoneIndex].setRadioPower(isChecked);
+                }
+            }
         }
     };
 
diff --git a/src/com/android/services/telephony/RadioOnHelper.java b/src/com/android/services/telephony/RadioOnHelper.java
index 116c61d..25ac220 100644
--- a/src/com/android/services/telephony/RadioOnHelper.java
+++ b/src/com/android/services/telephony/RadioOnHelper.java
@@ -77,7 +77,8 @@
      * RadioOnHelper's handler (thus ensuring that the rest of the sequence is entirely
      * serialized, and runs on the main looper.)
      */
-    public void triggerRadioOnAndListen(RadioOnStateListener.Callback callback) {
+    public void triggerRadioOnAndListen(RadioOnStateListener.Callback callback,
+            boolean forEmergencyCall, Phone phoneForEmergencyCall) {
         setupListeners();
         mCallback = callback;
         mInProgressListeners.clear();
@@ -89,16 +90,17 @@
             }
 
             mInProgressListeners.add(mListeners.get(i));
-            mListeners.get(i).waitForRadioOn(phone, this);
+            mListeners.get(i).waitForRadioOn(phone, this, forEmergencyCall,
+                    forEmergencyCall && phone == phoneForEmergencyCall);
         }
 
-        powerOnRadio();
+        powerOnRadio(forEmergencyCall, phoneForEmergencyCall);
     }
     /**
      * Attempt to power on the radio (i.e. take the device out of airplane mode). We'll eventually
      * get an onServiceStateChanged() callback when the radio successfully comes up.
      */
-    private void powerOnRadio() {
+    private void powerOnRadio(boolean forEmergencyCall, Phone phoneForEmergencyCall) {
 
         // If airplane mode is on, we turn it off the same way that the Settings activity turns it
         // off.
@@ -112,7 +114,7 @@
 
             for (Phone phone : PhoneFactory.getPhones()) {
                 Log.d(this, "powerOnRadio, enabling Radio");
-                phone.setRadioPower(true);
+                phone.setRadioPower(true, forEmergencyCall, phone == phoneForEmergencyCall, false);
             }
 
             // Post the broadcast intend for change in airplane mode
diff --git a/src/com/android/services/telephony/RadioOnStateListener.java b/src/com/android/services/telephony/RadioOnStateListener.java
index 43269b4..93e1e3c 100644
--- a/src/com/android/services/telephony/RadioOnStateListener.java
+++ b/src/com/android/services/telephony/RadioOnStateListener.java
@@ -70,7 +70,10 @@
                         Phone phone = (Phone) args.arg1;
                         RadioOnStateListener.Callback callback =
                                 (RadioOnStateListener.Callback) args.arg2;
-                        startSequenceInternal(phone, callback);
+                        boolean forEmergencyCall = (boolean) args.arg3;
+                        boolean isSelectedPhoneForEmergencyCall = (boolean) args.arg4;
+                        startSequenceInternal(phone, callback, forEmergencyCall,
+                                isSelectedPhoneForEmergencyCall);
                     } finally {
                         args.recycle();
                     }
@@ -97,6 +100,10 @@
 
     private Callback mCallback;  // The callback to notify upon completion.
     private Phone mPhone;  // The phone that will attempt to place the call.
+    private boolean mForEmergencyCall; // Whether radio is being turned on for emergency call.
+    // Whether this phone is selected to place emergency call. Can be true only if
+    // mForEmergencyCall is true.
+    private boolean mSelectedPhoneForEmergencyCall;
     private int mNumRetriesSoFar;
 
     /**
@@ -113,7 +120,8 @@
      * RadioOnStateListener's handler (thus ensuring that the rest of the sequence is entirely
      * serialized, and runs only on the handler thread.)
      */
-    public void waitForRadioOn(Phone phone, Callback callback) {
+    public void waitForRadioOn(Phone phone, Callback callback,
+            boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall) {
         Log.d(this, "waitForRadioOn: Phone " + phone.getPhoneId());
 
         if (mPhone != null) {
@@ -124,6 +132,8 @@
         SomeArgs args = SomeArgs.obtain();
         args.arg1 = phone;
         args.arg2 = callback;
+        args.arg3 = forEmergencyCall;
+        args.arg4 = isSelectedPhoneForEmergencyCall;
         mHandler.obtainMessage(MSG_START_SEQUENCE, args).sendToTarget();
     }
 
@@ -132,7 +142,8 @@
      *
      * @see #waitForRadioOn
      */
-    private void startSequenceInternal(Phone phone, Callback callback) {
+    private void startSequenceInternal(Phone phone, Callback callback,
+            boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall) {
         Log.d(this, "startSequenceInternal: Phone " + phone.getPhoneId());
 
         // First of all, clean up any state left over from a prior RadioOn call sequence. This
@@ -142,6 +153,8 @@
 
         mPhone = phone;
         mCallback = callback;
+        mForEmergencyCall = forEmergencyCall;
+        mSelectedPhoneForEmergencyCall = isSelectedPhoneForEmergencyCall;
 
         registerForServiceStateChanged();
         // Register for RADIO_OFF to handle cases where emergency call is dialed before
@@ -159,6 +172,7 @@
      * call with {@link Callback#isOkToCall}
      */
     private void onServiceStateChanged(ServiceState state) {
+        if (mPhone == null) return;
         Log.d(this, "onServiceStateChanged(), new state = %s, Phone = %s", state,
                 mPhone.getPhoneId());
 
@@ -182,6 +196,7 @@
     }
 
     private void onRadioOn() {
+        if (mPhone == null) return;
         ServiceState state =  mPhone.getServiceState();
         Log.d(this, "onRadioOn, state = %s, Phone = %s", state,
                 mPhone.getPhoneId());
@@ -203,6 +218,7 @@
      * Handles the retry timer expiring.
      */
     private void onRetryTimeout() {
+        if (mPhone == null) return;
         int serviceState = mPhone.getServiceState().getState();
         Log.d(this, "onRetryTimeout():  phone state = %s, service state = %d, retries = %d.",
                 mPhone.getState(), serviceState, mNumRetriesSoFar);
@@ -231,7 +247,8 @@
                 cleanup();
             } else {
                 Log.d(this, "Trying (again) to turn on the radio.");
-                mPhone.setRadioPower(true);
+                mPhone.setRadioPower(true, mForEmergencyCall, mSelectedPhoneForEmergencyCall,
+                        false);
                 startRetryTimer();
             }
         }
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index b4b7405..79feb10 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -36,6 +36,7 @@
 import android.os.PersistableBundle;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.provider.Telephony;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
@@ -48,6 +49,7 @@
 import android.telephony.TelephonyManager;
 import android.telephony.ims.ImsException;
 import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ImsRcsManager;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.RegistrationManager;
 import android.telephony.ims.feature.MmTelFeature;
@@ -55,7 +57,6 @@
 import android.text.TextUtils;
 
 import com.android.ims.ImsManager;
-import com.android.internal.telephony.LocaleTracker;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.SubscriptionController;
@@ -542,16 +543,31 @@
         }
 
         /**
-         * Determines from carrier configuration whether RCS presence indication for video calls is
-         * supported.
+         * Determines from carrier configuration and user setting whether RCS presence indication
+         * for video calls is supported.
          *
          * @return {@code true} if RCS presence indication for video calls is supported.
          */
         private boolean isCarrierVideoPresenceSupported() {
             PersistableBundle b =
                     PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
-            return b != null &&
-                    b.getBoolean(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL);
+            boolean carrierConfigEnabled = b != null
+                    && b.getBoolean(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL);
+            return carrierConfigEnabled && isUserContactDiscoverySettingEnabled();
+        }
+
+        /**
+         * @return true if the user has enabled contact discovery for the subscription associated
+         * with this account entry, false otherwise.
+         */
+        private boolean isUserContactDiscoverySettingEnabled() {
+            try {
+                ImsRcsManager manager = mImsManager.getImsRcsManager(mPhone.getSubId());
+                return manager.getUceAdapter().isUceSettingEnabled();
+            } catch (Exception e) {
+                Log.w(LOG_TAG, "isUserContactDiscoverySettingEnabled caught exception: " + e);
+                return false;
+            }
         }
 
         /**
@@ -753,6 +769,25 @@
             }
         }
 
+        public void updateVideoPresenceCapability() {
+            synchronized (mAccountsLock) {
+                if (!mAccounts.contains(this)) {
+                    // Account has already been torn down, don't try to register it again.
+                    // This handles the case where teardown has already happened, and we got a Ims
+                    // registration update that lost the race for the mAccountsLock.  In such a
+                    // scenario by the time we get here, the original phone account could have been
+                    // torn down.
+                    return;
+                }
+                boolean isVideoPresenceSupported = isCarrierVideoPresenceSupported();
+                if (mIsVideoPresenceSupported != isVideoPresenceSupported) {
+                    Log.i(this, "updateVideoPresenceCapability for subId=" + mPhone.getSubId()
+                            + ", new value= " + isVideoPresenceSupported);
+                    mAccount = registerPstnPhoneAccount(mIsEmergency, mIsDummy);
+                }
+            }
+        }
+
         public void updateRttCapability() {
             boolean isRttEnabled = isRttCurrentlySupported();
             if (isRttEnabled != mIsRttCapable) {
@@ -985,6 +1020,7 @@
     private static TelecomAccountRegistry sInstance;
     private final Context mContext;
     private final TelecomManager mTelecomManager;
+    private final android.telephony.ims.ImsManager mImsManager;
     private final TelephonyManager mTelephonyManager;
     private final SubscriptionManager mSubscriptionManager;
     private List<AccountEntry> mAccounts = new LinkedList<AccountEntry>();
@@ -1000,6 +1036,7 @@
     TelecomAccountRegistry(Context context) {
         mContext = context;
         mTelecomManager = context.getSystemService(TelecomManager.class);
+        mImsManager = context.getSystemService(android.telephony.ims.ImsManager.class);
         mTelephonyManager = TelephonyManager.from(context);
         mSubscriptionManager = SubscriptionManager.from(context);
     }
@@ -1238,6 +1275,10 @@
         localeChangeFilter.addAction(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED);
         mContext.registerReceiver(mLocaleChangeReceiver, localeChangeFilter);
 
+        registerContentObservers();
+    }
+
+    private void registerContentObservers() {
         // Listen to the RTT system setting so that we update it when the user flips it.
         ContentObserver rttUiSettingObserver = new ContentObserver(
                 new Handler(Looper.getMainLooper())) {
@@ -1254,6 +1295,23 @@
         Uri rttSettingUri = Settings.Secure.getUriFor(Settings.Secure.RTT_CALLING_MODE);
         mContext.getContentResolver().registerContentObserver(
                 rttSettingUri, false, rttUiSettingObserver);
+
+        // Listen to the changes to the user's Contacts Discovery Setting.
+        ContentObserver contactDiscoveryObserver = new ContentObserver(
+                new Handler(Looper.getMainLooper())) {
+            @Override
+            public void onChange(boolean selfChange) {
+                synchronized (mAccountsLock) {
+                    for (AccountEntry account : mAccounts) {
+                        account.updateVideoPresenceCapability();
+                    }
+                }
+            }
+        };
+        Uri contactDiscUri = Uri.withAppendedPath(Telephony.SimInfo.CONTENT_URI,
+                Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED);
+        mContext.getContentResolver().registerContentObserver(
+                contactDiscUri, true /*notifyForDescendants*/, contactDiscoveryObserver);
     }
 
     /**
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index c7686be..0b60e37 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -421,6 +421,14 @@
     }
 
     /**
+     * Overrides radioOnHelper for testing.
+     */
+    @VisibleForTesting
+    public void setRadioOnHelper(RadioOnHelper radioOnHelper) {
+        mRadioOnHelper = radioOnHelper;
+    }
+
+    /**
      * Overrides PhoneSwitcher dependencies for testing.
      */
     @VisibleForTesting
@@ -763,13 +771,16 @@
         boolean needToTurnOnRadio = (isEmergencyNumber && (!isRadioOn() || isAirplaneModeOn))
                 || isRadioPowerDownOnBluetooth();
 
+        // Get the right phone object from the account data passed in.
+        final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber,
+                /* Note: when not an emergency, handle can be null for unknown callers */
+                handle == null ? null : handle.getSchemeSpecificPart());
+
         if (needToTurnOnRadio) {
             final Uri resultHandle = handle;
-            // By default, Connection based on the default Phone, since we need to return to Telecom
-            // now.
-            final int originalPhoneType = mPhoneFactoryProxy.getDefaultPhone().getPhoneType();
+            final int originalPhoneType = phone.getPhoneType();
             final Connection resultConnection = getTelephonyConnection(request, numberToDial,
-                    isEmergencyNumber, resultHandle, PhoneFactory.getDefaultPhone());
+                    isEmergencyNumber, resultHandle, phone);
             if (mRadioOnHelper == null) {
                 mRadioOnHelper = new RadioOnHelper(this);
             }
@@ -777,7 +788,7 @@
                 @Override
                 public void onComplete(RadioOnStateListener listener, boolean isRadioReady) {
                     handleOnComplete(isRadioReady, isEmergencyNumber, resultConnection, request,
-                            numberToDial, resultHandle, originalPhoneType);
+                            numberToDial, resultHandle, originalPhoneType, phone);
                 }
 
                 @Override
@@ -806,7 +817,7 @@
                                 || serviceState == ServiceState.STATE_IN_SERVICE;
                     }
                 }
-            });
+            }, isEmergencyNumber && !isTestEmergencyNumber, phone);
             // Return the still unconnected GsmConnection and wait for the Radios to boot before
             // connecting it to the underlying Phone.
             return resultConnection;
@@ -822,10 +833,6 @@
                                 "Add call restricted due to ongoing video call"));
             }
 
-            // Get the right phone object from the account data passed in.
-            final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber,
-                    /* Note: when not an emergency, handle can be null for unknown callers */
-                    handle == null ? null : handle.getSchemeSpecificPart());
             if (!isEmergencyNumber) {
                 final Connection resultConnection = getTelephonyConnection(request, numberToDial,
                         false, handle, phone);
@@ -902,18 +909,21 @@
      */
     private void handleOnComplete(boolean isRadioReady, boolean isEmergencyNumber,
             Connection originalConnection, ConnectionRequest request, String numberToDial,
-            Uri handle, int originalPhoneType) {
+            Uri handle, int originalPhoneType, Phone phone) {
         // Make sure the Call has not already been canceled by the user.
         if (originalConnection.getState() == Connection.STATE_DISCONNECTED) {
             Log.i(this, "Call disconnected before the outgoing call was placed. Skipping call "
                     + "placement.");
+            if (isEmergencyNumber) {
+                // If call is already canceled by the user, notify modem to exit emergency call
+                // mode by sending radio on with forEmergencyCall=false.
+                for (Phone curPhone : mPhoneFactoryProxy.getPhones()) {
+                    curPhone.setRadioPower(true, false, false, true);
+                }
+            }
             return;
         }
-        // Get the right phone object since the radio has been turned on successfully.
         if (isRadioReady) {
-            final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber,
-                    /* Note: when not an emergency, handle can be null for unknown callers */
-                    handle == null ? null : handle.getSchemeSpecificPart());
             if (!isEmergencyNumber) {
                 adjustAndPlaceOutgoingConnection(phone, originalConnection, request, numberToDial,
                         handle, originalPhoneType, false);
@@ -956,7 +966,7 @@
             // one and causing UI Jank.
             boolean noActiveSimCard = SubscriptionController.getInstance()
                     .getActiveSubInfoCount(phone.getContext().getOpPackageName(),
-                            phone.getContext().getFeatureId()) == 0;
+                            phone.getContext().getAttributionTag()) == 0;
             // If there's no active sim card and the device is in emergency mode, use E account.
             addExistingConnection(mPhoneUtilsProxy.makePstnPhoneAccountHandleWithPrefix(
                     phone, "", isEmergencyNumber && noActiveSimCard), repConnection);
diff --git a/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java b/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java
index d488dff..ac8f9bf 100644
--- a/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java
+++ b/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java
@@ -235,7 +235,7 @@
     private static int toUcePublishState(int publishState) {
         switch (publishState) {
             case PresenceBase.PUBLISH_STATE_200_OK:
-                return RcsUceAdapter.PUBLISH_STATE_200_OK;
+                return RcsUceAdapter.PUBLISH_STATE_OK;
             case PresenceBase.PUBLISH_STATE_NOT_PUBLISHED:
                 return RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED;
             case PresenceBase.PUBLISH_STATE_VOLTE_PROVISION_ERROR:
diff --git a/tests/src/com/android/TestContext.java b/tests/src/com/android/TestContext.java
index ff85b6d..c5b9b1e 100644
--- a/tests/src/com/android/TestContext.java
+++ b/tests/src/com/android/TestContext.java
@@ -67,7 +67,7 @@
     }
 
     @Override
-    public String getFeatureId() {
+    public String getAttributionTag() {
         return "";
     }
 
diff --git a/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java b/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
index afdfab5..25df848 100644
--- a/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
+++ b/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
@@ -69,9 +69,9 @@
     @Override
     @After
     public void tearDown() throws Exception {
+        mListener.getHandler().removeCallbacksAndMessages(null);
         // Wait for the queue to clear...
         waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS /*ms timeout*/);
-        mListener.getHandler().removeCallbacksAndMessages(null);
         mListener = null;
         super.tearDown();
     }
@@ -83,7 +83,7 @@
     @SmallTest
     public void testRegisterForCallback() {
         mMockPhone.mCi = mMockCi;
-        mListener.waitForRadioOn(mMockPhone, mCallback);
+        mListener.waitForRadioOn(mMockPhone, mCallback, false, false);
 
         waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
 
@@ -105,10 +105,11 @@
     public void testPhoneChangeState_OkToCallTrue() {
         ServiceState state = new ServiceState();
         state.setState(ServiceState.STATE_IN_SERVICE);
+        when(mMockPhone.getServiceState()).thenReturn(state);
         when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
         when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(true);
         mMockPhone.mCi = mMockCi;
-        mListener.waitForRadioOn(mMockPhone, mCallback);
+        mListener.waitForRadioOn(mMockPhone, mCallback, false, false);
         waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
 
         mListener.getHandler().obtainMessage(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED,
@@ -132,7 +133,7 @@
         when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(false);
         when(mMockPhone.getServiceState()).thenReturn(state);
         mMockPhone.mCi = mMockCi;
-        mListener.waitForRadioOn(mMockPhone, mCallback);
+        mListener.waitForRadioOn(mMockPhone, mCallback, false, false);
         waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
 
         mListener.getHandler().obtainMessage(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED,
@@ -161,10 +162,32 @@
 
         // Wait for the timer to expire and check state manually in onRetryTimeout
         mMockPhone.mCi = mMockCi;
-        mListener.waitForRadioOn(mMockPhone, mCallback);
+        mListener.waitForRadioOn(mMockPhone, mCallback, false, false);
         waitForHandlerActionDelayed(mListener.getHandler(), TIMEOUT_MS, TIMEOUT_MS /*delay*/);
 
         verify(mCallback).onComplete(eq(mListener), eq(false));
-        verify(mMockPhone, times(2)).setRadioPower(eq(true));
+        verify(mMockPhone, times(2)).setRadioPower(eq(true),
+                eq(false), eq(false), eq(false));
+    }
+
+    @Test
+    @SmallTest
+    public void testTimeout_RetryFailure_ForEmergency() {
+        ServiceState state = new ServiceState();
+        state.setState(ServiceState.STATE_POWER_OFF);
+        when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
+        when(mMockPhone.getServiceState()).thenReturn(state);
+        when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(false);
+        mListener.setTimeBetweenRetriesMillis(0/*ms*/);
+        mListener.setMaxNumRetries(2);
+
+        // Wait for the timer to expire and check state manually in onRetryTimeout
+        mMockPhone.mCi = mMockCi;
+        mListener.waitForRadioOn(mMockPhone, mCallback, true, true);
+        waitForHandlerActionDelayed(mListener.getHandler(), TIMEOUT_MS, TIMEOUT_MS /*delay*/);
+
+        verify(mCallback).onComplete(eq(mListener), eq(false));
+        verify(mMockPhone, times(2)).setRadioPower(eq(true),
+                eq(true), eq(true), eq(false));
     }
 }
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index 6e11e51..2060e6f 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -16,7 +16,10 @@
 
 package com.android.services.telephony;
 
+import static com.android.internal.telephony.RILConstants.GSM_PHONE;
+
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.Assert.fail;
@@ -26,6 +29,7 @@
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -58,6 +62,7 @@
 import com.android.internal.telephony.Connection;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneSwitcher;
+import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
 
@@ -93,6 +98,7 @@
     private static final PhoneAccountHandle PHONE_ACCOUNT_HANDLE_2 = new PhoneAccountHandle(
             TEST_COMPONENT_NAME, TEST_ACCOUNT_ID2);
     private static final Uri TEST_ADDRESS = Uri.parse("tel:+16505551212");
+    private android.telecom.Connection mConnection;
 
     @Mock TelephonyConnectionService.TelephonyManagerProxy mTelephonyManagerProxy;
     @Mock TelephonyConnectionService.SubscriptionManagerProxy mSubscriptionManagerProxy;
@@ -106,6 +112,8 @@
     @Mock Handler mMockHandler;
     @Mock EmergencyNumberTracker mEmergencyNumberTracker;
     @Mock PhoneSwitcher mPhoneSwitcher;
+    @Mock RadioOnHelper mRadioOnHelper;
+    @Mock ServiceStateTracker mSST;
 
     private static class TestTelephonyConnectionService extends TelephonyConnectionService {
 
@@ -135,6 +143,8 @@
         doReturn(false).when(mDeviceState).shouldCheckSimStateBeforeOutgoingCall(any());
         mTestConnectionService.setPhoneSwitcherProxy(mPhoneSwitcherProxy);
         doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher();
+        when(mPhoneNumberUtilsProxy.convertToEmergencyNumber(any(), anyString()))
+                .thenAnswer(invocation -> invocation.getArgument(1));
         mTestConnectionService.setPhoneNumberUtilsProxy(mPhoneNumberUtilsProxy);
         mTestConnectionService.setPhoneUtilsProxy(mPhoneUtilsProxy);
         HandlerThread mockHandlerThread = mock(HandlerThread.class);
@@ -143,6 +153,7 @@
         doReturn(mMockHandler).when(mHandlerFactory).createHandler(any());
         mTestConnectionService.setHandlerFactory(mHandlerFactory);
         mTestConnectionService.setDeviceState(mDeviceState);
+        mTestConnectionService.setRadioOnHelper(mRadioOnHelper);
         doReturn(new DisconnectCause(DisconnectCause.UNKNOWN)).when(mDisconnectCauseFactory)
                 .toTelecomDisconnectCause(anyInt(), any());
         doReturn(new DisconnectCause(DisconnectCause.UNKNOWN)).when(mDisconnectCauseFactory)
@@ -941,6 +952,64 @@
     }
 
     /**
+     * Test that the TelephonyConnectionService successfully turns radio on before placing the
+     * emergency call.
+     */
+    @Test
+    @SmallTest
+    public void testCreateOutgoingEmerge_exitingApm_disconnected() {
+        when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
+        Phone testPhone = setupConnectionServiceInApm();
+
+        ArgumentCaptor<RadioOnStateListener.Callback> callback =
+                ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
+        verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
+                eq(testPhone));
+
+        assertFalse(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+        when(mSST.isRadioOn()).thenReturn(true);
+        assertTrue(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+
+        mConnection.setDisconnected(null);
+        callback.getValue().onComplete(null, true);
+        for (Phone phone : mPhoneFactoryProxy.getPhones()) {
+            verify(phone).setRadioPower(true, false, false, true);
+        }
+    }
+
+    /**
+     * Test that the TelephonyConnectionService successfully turns radio on before placing the
+     * emergency call.
+     */
+    @Test
+    @SmallTest
+    public void testCreateOutgoingEmergencyConnection_exitingApm_placeCall() {
+        when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
+        Phone testPhone = setupConnectionServiceInApm();
+
+        ArgumentCaptor<RadioOnStateListener.Callback> callback =
+                ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
+        verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
+                eq(testPhone));
+
+        assertFalse(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+        when(mSST.isRadioOn()).thenReturn(true);
+        assertTrue(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+
+        callback.getValue().onComplete(null, true);
+        Runnable delayDialRunnable = verifyRunnablePosted();
+
+        try {
+            doAnswer(invocation -> null).when(mContext).startActivity(any());
+            delayDialRunnable.run();
+            verify(testPhone).dial(anyString(), any());
+        } catch (CallStateException e) {
+            // This shouldn't happen
+            fail();
+        }
+    }
+
+    /**
      * Test that the TelephonyConnectionService does not perform a DDS switch when the carrier
      * supports control-plane fallback.
      */
@@ -1115,9 +1184,49 @@
         doReturn(emergencyNumbers).when(mTelephonyManagerProxy).getCurrentEmergencyNumberList();
         doReturn(2).when(mTelephonyManagerProxy).getPhoneCount();
 
-        android.telecom.Connection testConnection = mTestConnectionService
-                .onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1, connectionRequest);
-        assertNotNull("test connection was not set up correctly.", testConnection);
+        mConnection = mTestConnectionService.onCreateOutgoingConnection(
+                PHONE_ACCOUNT_HANDLE_1, connectionRequest);
+        assertNotNull("test connection was not set up correctly.", mConnection);
+
+        return testPhone0;
+    }
+
+
+    /**
+     * Set up a mock MSIM device with TEST_ADDRESS set as an emergency number in airplane mode.
+     * @return the Phone associated with slot 0.
+     */
+    private Phone setupConnectionServiceInApm() {
+        ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
+                .setAccountHandle(PHONE_ACCOUNT_HANDLE_1)
+                .setAddress(TEST_ADDRESS)
+                .build();
+        Phone testPhone0 = makeTestPhone(0 /*phoneId*/, ServiceState.STATE_POWER_OFF,
+                false /*isEmergencyOnly*/);
+        Phone testPhone1 = makeTestPhone(1 /*phoneId*/, ServiceState.STATE_POWER_OFF,
+                false /*isEmergencyOnly*/);
+        doReturn(GSM_PHONE).when(testPhone0).getPhoneType();
+        doReturn(GSM_PHONE).when(testPhone1).getPhoneType();
+        List<Phone> phones = new ArrayList<>(2);
+        doReturn(false).when(testPhone0).isRadioOn();
+        doReturn(false).when(testPhone1).isRadioOn();
+        phones.add(testPhone0);
+        phones.add(testPhone1);
+        setPhones(phones);
+        setupHandleToPhoneMap(PHONE_ACCOUNT_HANDLE_1, testPhone0);
+        setupDeviceConfig(testPhone0, testPhone1, 0);
+        doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(
+                TEST_ADDRESS.getSchemeSpecificPart());
+        HashMap<Integer, List<EmergencyNumber>> emergencyNumbers = new HashMap<>(1);
+        List<EmergencyNumber> numbers = new ArrayList<>();
+        numbers.add(setupEmergencyNumber(TEST_ADDRESS));
+        emergencyNumbers.put(0 /*subId*/, numbers);
+        doReturn(emergencyNumbers).when(mTelephonyManagerProxy).getCurrentEmergencyNumberList();
+        doReturn(2).when(mTelephonyManagerProxy).getPhoneCount();
+
+        mConnection = mTestConnectionService.onCreateOutgoingConnection(
+                PHONE_ACCOUNT_HANDLE_1, connectionRequest);
+        assertNotNull("test connection was not set up correctly.", mConnection);
 
         return testPhone0;
     }
@@ -1163,6 +1272,7 @@
         when(phone.getPhoneId()).thenReturn(phoneId);
         when(phone.getDefaultPhone()).thenReturn(phone);
         when(phone.getEmergencyNumberTracker()).thenReturn(mEmergencyNumberTracker);
+        when(phone.getServiceStateTracker()).thenReturn(mSST);
         when(mEmergencyNumberTracker.getEmergencyNumber(anyString())).thenReturn(null);
         return phone;
     }
@@ -1193,6 +1303,7 @@
 
     private void setPhones(List<Phone> phones) {
         when(mPhoneFactoryProxy.getPhones()).thenReturn(phones.toArray(new Phone[phones.size()]));
+        when(mPhoneFactoryProxy.getDefaultPhone()).thenReturn(phones.get(0));
     }
 
     private void setPhonesDialConnection(Phone phone, Connection c) {