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