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) {