[automerger skipped] Merge "Import translations. DO NOT MERGE ANYWHERE" into tm-mainline-prod am: c79992e2b1 -s ours
am skip reason: subject contains skip directive
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/services/Telephony/+/19693605
Change-Id: Ifb06cb47396fb1f402e072eb79d75137c8f9b65f
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 7d8ba9d..e11daad 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="phoneAppLabel" product="tablet" msgid="1916019789885839910">"Dati cellulare"</string>
- <string name="phoneAppLabel" product="default" msgid="130465039375347763">"Servizi telefonici"</string>
+ <string name="phoneAppLabel" product="default" msgid="130465039375347763">"Phone Services"</string>
<string name="emergencyDialerIconLabel" msgid="8668005772339436680">"Chiamata di emergenza"</string>
<string name="phoneIconLabel" msgid="3015941229249651419">"Telefono"</string>
<string name="fdnListLabel" msgid="4119121875004244097">"Elenco numeri consentiti"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index a5050d2..af5a8ea 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -545,7 +545,7 @@
<string name="incall_error_no_phone_number_supplied" msgid="8680831089508851894">"कॉल करण्यासाठी, एक वैध नंबर एंटर करा."</string>
<string name="incall_error_call_failed" msgid="393508653582682539">"कॉल अयशस्वी झाला."</string>
<string name="incall_error_cannot_add_call" msgid="5425764862628655443">"या वेळी कॉल जोडू शकत नाही. तुम्ही मेसेज पाठवून संपर्क करण्याचा प्रयत्न करू शकता."</string>
- <string name="incall_error_supp_service_unknown" msgid="8751177117194592623">"सेवेला सपोर्ट नाही"</string>
+ <string name="incall_error_supp_service_unknown" msgid="8751177117194592623">"सेवा समर्थित नाही"</string>
<string name="incall_error_supp_service_switch" msgid="5272822448189448479">"कॉल स्विच करू शकत नाही."</string>
<string name="incall_error_supp_service_resume" msgid="1276861499306817035">"कॉल पुन्हा सुरू करू शकत नाही."</string>
<string name="incall_error_supp_service_separate" msgid="8932660028965274353">"कॉल विभक्त करू शकत नाही."</string>
@@ -655,7 +655,7 @@
<string name="contactPhoto" msgid="7885089213135154834">"संपर्क फोटो"</string>
<string name="goPrivate" msgid="4645108311382209551">"खाजगी जा"</string>
<string name="selectContact" msgid="1527612842599767382">"संपर्क निवडा"</string>
- <string name="not_voice_capable" msgid="2819996734252084253">"व्हॉइस कॉलिंंग याला सपोर्ट नाही"</string>
+ <string name="not_voice_capable" msgid="2819996734252084253">"व्हॉइस कॉलिंंग समर्थित नाही"</string>
<string name="description_dial_button" msgid="8614631902795087259">"डायल करा"</string>
<string name="description_dialpad_button" msgid="7395114120463883623">"डायलपॅड दाखवा"</string>
<string name="pane_title_emergency_dialpad" msgid="3627372514638694401">"आणीबाणी डायलपॅड"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 36fd00f..e4a7099 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -156,8 +156,8 @@
<item msgid="9150034130629852635">"ସଂଖ୍ୟାକୁ ଦେଖାନ୍ତୁ"</item>
</string-array>
<string name="vm_changed" msgid="4739599044379692505">"ଭଏସମେଲ୍ ନମ୍ବର୍ ବଦଳିଗଲା।"</string>
- <string name="vm_change_failed" msgid="7877733929455763566">"ଭଏସମେଲ ନମ୍ବର ବଦଳାଯାଇପାରିଲା ନାହିଁ। \nଯଦି ଏହି ସମସ୍ୟା ଜାରି ରୁହେ ତେବେ ନିଜର କ୍ଯାରିଅରଙ୍କ ସହ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ।"</string>
- <string name="fw_change_failed" msgid="9179241823460192148">"ଫରୱାର୍ଡିଙ୍ଗ ନମ୍ବରକୁ ବଦଳାଯାଇପାରିଲା ନାହିଁ। \n ଯଦି ଏହି ସମସ୍ୟା ଜାରି ରୁହେ ତେବେ ନିଜର କ୍ଯାରିଅରଙ୍କ ସହ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ।"</string>
+ <string name="vm_change_failed" msgid="7877733929455763566">"ଭଏସମେଲ୍ ନମ୍ବର୍ ବଦଳାଯାଇପାରିଲା ନାହିଁ। \nଯଦି ଏହି ସମସ୍ୟା ଜାରିରୁହେ ତେବେ ନିଜର କେରିଅର୍ଙ୍କ ସହ ସମ୍ପର୍କ କରନ୍ତୁ।"</string>
+ <string name="fw_change_failed" msgid="9179241823460192148">"ଫଏୱାର୍ଡିଙ୍ଗ ନମ୍ବର୍କୁ ବଦଳାଇହେଲା ନାହିଁ। \n ଯଦି ଏହି ସମସ୍ୟା ଜାରିରୁହେ ତେବେ ନିଜର କେରିଅର୍ଙ୍କ ସହ ସମ୍ପର୍କ କରନ୍ତୁ।"</string>
<string name="fw_get_in_vm_failed" msgid="2432678237218183844">"ବର୍ତ୍ତମାନର ଫରୱାର୍ଡିଂ ନମ୍ବର ସେଟିଂସକୁ ପୁନରୁଦ୍ଧାର ଓ ସେଭ କରାଯାଇପାରିଲା ନାହିଁ। \nନୂଆ ପ୍ରଦାନକାରୀକୁ ଯେ କୌଣସି ମତେ ସ୍ଵିଚ କରିବେ?"</string>
<string name="no_change" msgid="3737264882821031892">"କୌଣସି ପରିବର୍ତ୍ତନ କରାଯାଇନାହିଁ|"</string>
<string name="sum_voicemail_choose_provider" msgid="6750824719081403773">"ଭଏସ୍ମେଲ୍ ସେବାକୁ ଚୟନ କରନ୍ତୁ"</string>
@@ -419,7 +419,7 @@
<string name="cdma_system_select_summary" msgid="3840420390242060407">"CDMAର ରୋମିଙ୍ଗ ମୋଡ୍କୁ ବଦଳାନ୍ତୁ"</string>
<string name="cdma_system_select_dialogtitle" msgid="5524639510676501802">"ସିଷ୍ଟମ୍ ଚୟନ କରନ୍ତୁ"</string>
<string-array name="cdma_system_select_choices">
- <item msgid="462340042928284921">"କେବଳ ହୋମ"</item>
+ <item msgid="462340042928284921">"କେବଳ ହୋମ୍"</item>
<item msgid="6058010046783562674">"ସ୍ଵଚାଳିତ"</item>
</string-array>
<string name="cdma_subscription_title" msgid="3449527179325589434">"CDMA ସବସ୍କ୍ରିପଶନ୍"</string>
@@ -458,10 +458,10 @@
<string name="auto_retry_mode_title" msgid="2985801935424422340">"ଅଟୋ-ରିଟ୍ରାଏ କରନ୍ତୁ"</string>
<string name="auto_retry_mode_summary" msgid="2863919925349511402">"ଅଟୋ-ରିଟ୍ରାଏ ମୋଡ୍କୁ ସକ୍ଷମ କରନ୍ତୁ"</string>
<string name="tty_mode_not_allowed_video_call" msgid="6551976083652752815">"ଭିଡିଓ କଲ୍ କରିବା ସମୟରେ TTY ମୋଡ୍କୁ ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ ଅନୁମତି ନାହିଁ"</string>
- <string name="menu_add" msgid="5616487894975773141">"କଣ୍ଟାକ୍ଟ ଯୋଗ କରନ୍ତୁ"</string>
+ <string name="menu_add" msgid="5616487894975773141">"ଯୋଗାଯୋଗକୁ ଯୋଗ କରନ୍ତୁ"</string>
<string name="menu_edit" msgid="3593856941552460706">"କଣ୍ଟାକ୍ଟ ଏଡିଟ କରନ୍ତୁ"</string>
- <string name="menu_delete" msgid="6326861853830546488">"କଣ୍ଟାକ୍ଟ ଡିଲିଟ କରନ୍ତୁ"</string>
- <string name="menu_dial" msgid="4178537318419450012">"କଣ୍ଟାକ୍ଟ ଡାଏଲ କରନ୍ତୁ"</string>
+ <string name="menu_delete" msgid="6326861853830546488">"ଯୋଗାଯୋଗକୁ ଡିଲିଟ୍ କରନ୍ତୁ"</string>
+ <string name="menu_dial" msgid="4178537318419450012">"ଯୋଗାଯୋଗକୁ ଡାଏଲ୍ କରନ୍ତୁ"</string>
<string name="get_pin2" msgid="4221654606863196332">"PIN2 ଟାଇପ୍ କରନ୍ତୁ"</string>
<string name="name" msgid="1347432469852527784">"ନାମ"</string>
<string name="number" msgid="1564053487748491000">"ନମ୍ବର୍"</string>
@@ -515,7 +515,7 @@
<string name="puk2_requested" msgid="6992374450720307514">"ଭୁଲ୍ ପାସ୍ୱର୍ଡ। ବର୍ତ୍ତମାନ SIM ଲକ୍ ହୋଇଗଲା। PUK2କୁ ପ୍ରବେଶ କରନ୍ତୁ।"</string>
<string name="puk2_blocked" msgid="3131139031779319911">"PUK2କୁ ସ୍ଥାୟୀରୂପେ ଅବରୋଧ କରାଯାଇଛି।"</string>
<string name="pin2_attempts" msgid="5625178102026453023">\n"ଆପଣଙ୍କର <xliff:g id="NUMBER">%d</xliff:g>ଟି ସୁଯୋଗ ବଳକା ଅଛି।"</string>
- <string name="puk2_locked" msgid="6497760825455461057">"PUK2 ଲକ କରାଯାଇଛି। ଅନଲକ କରିବାକୁ ସେବା ପ୍ରଦାନକାରୀ ସହ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ।"</string>
+ <string name="puk2_locked" msgid="6497760825455461057">"PUK2 ଲକ୍ କରାଯାଇଛି। ଅନଲକ୍ କରିବାକୁ ସେବା ପ୍ରଦାନକାରୀ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
<string name="pin2_unblocked" msgid="4481107908727789303">"PIN2କୁ ଆଉ ଅବରୋଧ କରାଯାଇନାହିଁ"</string>
<string name="pin2_error_exception" msgid="8116103864600823641">"ନେଟ୍ୱର୍କ କିମ୍ବା SIM କାର୍ଡ ତ୍ରୁଟି"</string>
<string name="doneButton" msgid="7371209609238460207">"ହୋଇଗଲା"</string>
@@ -590,8 +590,8 @@
<string name="importAllSimEntries" msgid="2628391505643564007">"ସମସ୍ତ ଇମ୍ପୋର୍ଟ କରନ୍ତୁ"</string>
<string name="importingSimContacts" msgid="4995457122107888932">"SIMରେ ଥିବା ଯୋଗାଯୋଗକୁ ଇମ୍ପୋର୍ଟ କରାଯାଉଛି"</string>
<string name="importToFDNfromContacts" msgid="5068664870738407341">"ଯୋଗଯୋଗରୁ ଇମ୍ପୋର୍ଟ କରନ୍ତୁ"</string>
- <string name="singleContactImportedMsg" msgid="3619804066300998934">"ଇମ୍ପୋର୍ଟ କରାଯାଇଥିବା କଣ୍ଟାକ୍ଟ"</string>
- <string name="failedToImportSingleContactMsg" msgid="228095510489830266">"କଣ୍ଟାକ୍ଟକୁ ଇମ୍ପୋର୍ଟ କରିବାରେ ବିଫଳ ହୋଇଛି"</string>
+ <string name="singleContactImportedMsg" msgid="3619804066300998934">"ଇମ୍ପୋର୍ଟ କରାଯାଇଥିବା ଯୋଗାଯୋଗ"</string>
+ <string name="failedToImportSingleContactMsg" msgid="228095510489830266">"ଯୋଗଯୋଗକୁ ଇମ୍ପୋର୍ଟ କରିବାରେ ବିଫଳ ହେଲା"</string>
<string name="hac_mode_title" msgid="4127986689621125468">"ଶ୍ରବଣ ଯନ୍ତ୍ର"</string>
<string name="hac_mode_summary" msgid="7774989500136009881">"ଶ୍ରବଣ ଯନ୍ତ୍ର କମ୍ପ୍ୟାଟିବିଲିଟୀକୁ ଚାଲୁ କରନ୍ତୁ"</string>
<string name="rtt_mode_title" msgid="3075948111362818043">"ରିଅଲ୍-ଟାଇମ୍ ଟେକ୍ସଟ୍ (RTT) କଲ୍"</string>
@@ -652,9 +652,9 @@
<string name="voicemail_number_not_set" msgid="8831561283386938155">"<ସେଟ୍ ହୋଇନାହିଁ>"</string>
<string name="other_settings" msgid="8895088007393598447">"ଅନ୍ୟାନ୍ୟ କଲ୍ ସେଟିଙ୍ଗ"</string>
<string name="calling_via_template" msgid="1791323450703751750">"<xliff:g id="PROVIDER_NAME">%s</xliff:g> ମାଧ୍ୟମରେ କଲ୍ କରନ୍ତୁ"</string>
- <string name="contactPhoto" msgid="7885089213135154834">"କଣ୍ଟାକ୍ଟ ଫଟୋ"</string>
+ <string name="contactPhoto" msgid="7885089213135154834">"ଯୋଗାଯୋଗ ଫଟୋ"</string>
<string name="goPrivate" msgid="4645108311382209551">"ବ୍ୟକ୍ତିଗତ ହୁଅନ୍ତୁ"</string>
- <string name="selectContact" msgid="1527612842599767382">"କଣ୍ଟାକ୍ଟ ଚୟନ କରନ୍ତୁ"</string>
+ <string name="selectContact" msgid="1527612842599767382">"ଯୋଗାଯୋଗକୁ ଚୟନ କରନ୍ତୁ"</string>
<string name="not_voice_capable" msgid="2819996734252084253">"ଭଏସ୍ କଲ୍ ସପୋର୍ଟ କରୁନାହିଁ"</string>
<string name="description_dial_button" msgid="8614631902795087259">"ଡାଏଲ୍ କରନ୍ତୁ"</string>
<string name="description_dialpad_button" msgid="7395114120463883623">"ଡାୟଲ୍ପ୍ୟାଡ୍ ଦେଖାନ୍ତୁ"</string>
@@ -795,7 +795,7 @@
<string name="messageCallBarring" msgid="5537730400652466912">"ପାସ୍ୱର୍ଡ ପ୍ରବେଶ କରନ୍ତୁ"</string>
<string name="call_barring_settings" msgid="4616607285790258919">"କଲ୍ ରୋକିବା ସେଟିଙ୍ଗ"</string>
<string name="callFailed_NetworkBusy" msgid="5437103975842913681">"ନେଟ୍ୱର୍କ ବ୍ୟସ୍ତ ଅଛି। ଦୟାକରି ଆପଣ ପରେ ପୁଣି କଲ୍ ଚେଷ୍ଟା କରିବା ପାଇଁ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
- <string name="callFailed_NetworkCongested" msgid="6801283142342775380">"ନେଟୱାର୍କ ବ୍ୟସ୍ତ ଅଛି। ସହାୟତା ପାଇଁ ଆପଣଙ୍କର ମୋବାଇଲ ଅପରେଟରଙ୍କୁ କଣ୍ଟାକ୍ଟ କରନ୍ତୁ।"</string>
+ <string name="callFailed_NetworkCongested" msgid="6801283142342775380">"ନେଟ୍ୱର୍କ ବ୍ୟସ୍ତ ଅଛି। ସହାୟତା ପାଇଁ ଆପଣଙ୍କର ମୋବାଇଲ୍ ଅପରେଟର୍ଙ୍କୁ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
<string name="supp_service_notification_call_deflected" msgid="4980942818105909813">"କଲ୍ ଅନ୍ୟ ପାଖକୁ ଯିବା ବଦଳରେ ନିଜ ପାଖକୁ ଆସିଯାଇଛି।"</string>
<string name="supp_service_notification_call_forwarded" msgid="7102930311735433088">"କଲ୍କୁ ଫରୱାର୍ଡ କରାଯାଇଛି।"</string>
<string name="supp_service_notification_call_waiting" msgid="4577403881609445324">"କଲ୍ ଅପେକ୍ଷାରେ ଅଛି।"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 581b586..2e2bf46 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -105,23 +105,23 @@
<string name="labelCF" msgid="3578719437928476078">"కాల్ ఫార్వార్డింగ్"</string>
<string name="labelCFU" msgid="8870170873036279706">"ఎల్లప్పుడూ ఫార్వర్డ్ చేయి"</string>
<string name="messageCFU" msgid="1361806450979589744">"ఎల్లప్పుడూ ఈ నంబర్ను ఉపయోగించు"</string>
- <string name="sum_cfu_enabled_indicator" msgid="9030139213402432776">"అన్ని కాల్స్ను ఫార్వర్డ్ చేస్తోంది"</string>
- <string name="sum_cfu_enabled" msgid="5806923046528144526">"అన్ని కాల్స్ను <xliff:g id="PHONENUMBER">{0}</xliff:g>కి ఫార్వర్డ్ చేస్తోంది"</string>
+ <string name="sum_cfu_enabled_indicator" msgid="9030139213402432776">"అన్ని కాల్స్ను ఫార్వార్డ్ చేస్తోంది"</string>
+ <string name="sum_cfu_enabled" msgid="5806923046528144526">"అన్ని కాల్స్ను <xliff:g id="PHONENUMBER">{0}</xliff:g>కి ఫార్వార్డ్ చేస్తోంది"</string>
<string name="sum_cfu_enabled_no_number" msgid="7287752761743377930">"నంబర్ అందుబాటులో లేదు"</string>
<string name="sum_cfu_disabled" msgid="5010617134210809853">"ఆఫ్లో ఉంది"</string>
<string name="labelCFB" msgid="615265213360512768">"బిజీగా ఉన్నప్పుడు"</string>
<string name="messageCFB" msgid="1958017270393563388">"బిజీగా ఉన్నప్పుడు ఫార్వర్డ్ చేయాల్సిన నంబర్"</string>
- <string name="sum_cfb_enabled" msgid="332037613072049492">"<xliff:g id="PHONENUMBER">{0}</xliff:g>కి ఫార్వర్డ్ చేస్తోంది"</string>
+ <string name="sum_cfb_enabled" msgid="332037613072049492">"<xliff:g id="PHONENUMBER">{0}</xliff:g>కి ఫార్వార్డ్ చేస్తోంది"</string>
<string name="sum_cfb_disabled" msgid="3589913334164866035">"ఆఫ్లో ఉంది"</string>
<string name="disable_cfb_forbidden" msgid="4831494744351633961">"మీ ఫోన్ బిజీగా ఉన్నప్పుడు కాల్ ఫార్వర్డింగ్ను నిలిపివేయడానికి మీ ఆపరేటర్ మద్దతు ఇవ్వరు."</string>
<string name="labelCFNRy" msgid="3403533792248457946">"సమాధానం ఇవ్వనప్పుడు"</string>
<string name="messageCFNRy" msgid="7644434155765359009">"సమాధానం ఇవ్వనప్పుడు నంబర్"</string>
- <string name="sum_cfnry_enabled" msgid="3000500837493854799">"<xliff:g id="PHONENUMBER">{0}</xliff:g>కి ఫార్వర్డ్ చేస్తోంది"</string>
+ <string name="sum_cfnry_enabled" msgid="3000500837493854799">"<xliff:g id="PHONENUMBER">{0}</xliff:g>కి ఫార్వార్డ్ చేస్తోంది"</string>
<string name="sum_cfnry_disabled" msgid="1990563512406017880">"ఆఫ్లో ఉంది"</string>
<string name="disable_cfnry_forbidden" msgid="3174731413216550689">"మీ ఫోన్ సమాధానం ఇవ్వలేనప్పుడు కాల్ ఫార్వర్డింగ్ను నిలిపివేయడానికి మీ ఆపరేటర్ మద్దతు ఇవ్వరు."</string>
<string name="labelCFNRc" msgid="4163399350778066013">"చేరుకోలేనప్పుడు"</string>
<string name="messageCFNRc" msgid="6980340731313007250">"చేరుకోవడం సాధ్యపడనప్పుడు నంబర్"</string>
- <string name="sum_cfnrc_enabled" msgid="1799069234006073477">"<xliff:g id="PHONENUMBER">{0}</xliff:g>కి ఫార్వర్డ్ చేస్తోంది"</string>
+ <string name="sum_cfnrc_enabled" msgid="1799069234006073477">"<xliff:g id="PHONENUMBER">{0}</xliff:g>కి ఫార్వార్డ్ చేస్తోంది"</string>
<string name="sum_cfnrc_disabled" msgid="739289696796917683">"ఆఫ్లో ఉంది"</string>
<string name="disable_cfnrc_forbidden" msgid="775348748084726890">"మీ ఫోన్ను చేరుకోవడం సాధ్యపడనప్పుడు కాల్ ఫార్వర్డింగ్ను నిలిపివేయడానికి మీ క్యారియర్ మద్దతు ఇవ్వదు."</string>
<string name="registration_cf_forbidden" msgid="4386482610771190420">"కాల్ ఫార్వర్డింగ్ను మీ క్యారియర్ సపోర్ట్ చేయదు."</string>
@@ -797,20 +797,20 @@
<string name="callFailed_NetworkBusy" msgid="5437103975842913681">"నెట్వర్క్ బిజీగా ఉంది. దయచేసి తిరిగి తర్వాత కాల్ చేయండి."</string>
<string name="callFailed_NetworkCongested" msgid="6801283142342775380">"నెట్వర్క్లో అంతరాయం ఏర్పడింది. సహాయం కోసం మీ మొబైల్ ఆపరేటర్ను సంప్రదించండి."</string>
<string name="supp_service_notification_call_deflected" msgid="4980942818105909813">"కాల్ మళ్లించబడింది."</string>
- <string name="supp_service_notification_call_forwarded" msgid="7102930311735433088">"కాల్ ఫార్వర్డ్ చేయబడింది."</string>
+ <string name="supp_service_notification_call_forwarded" msgid="7102930311735433088">"కాల్ ఫార్వార్డ్ చేయబడింది."</string>
<string name="supp_service_notification_call_waiting" msgid="4577403881609445324">"కాల్ నిరీక్షణలో ఉంది."</string>
<string name="supp_service_clir_suppression_rejected" msgid="6105737020194776121">"నంబర్ బ్లాకింగ్ తిరస్కరించబడింది."</string>
<string name="supp_service_closed_user_group_call" msgid="2811636666505250689">"దగ్గరి వినియోగదారు సమూహ కాల్."</string>
<string name="supp_service_incoming_calls_barred" msgid="2034627421274447674">"ఇన్కమింగ్ కాల్స్ నిరోధించబడ్డాయి"</string>
<string name="supp_service_outgoing_calls_barred" msgid="5205725332394087112">"అవుట్గోయింగ్ కాల్స్ నిరోధించబడ్డాయి."</string>
<string name="supp_service_call_forwarding_active" msgid="7910162960395132464">"కాల్ ఫార్వర్డింగ్ యాక్టివ్గా ఉంది."</string>
- <string name="supp_service_additional_call_forwarded" msgid="8772753260008398632">"అదనపు కాల్ ఫార్వర్డ్ చేయబడింది."</string>
+ <string name="supp_service_additional_call_forwarded" msgid="8772753260008398632">"అదనపు కాల్ ఫార్వార్డ్ చేయబడింది."</string>
<string name="supp_service_additional_ect_connected" msgid="8525934162945220237">"అభ్యంతరకరమైన కాల్ బదిలీ పూర్తయింది."</string>
<string name="supp_service_additional_ect_connecting" msgid="7046240728781222753">"అభ్యంతరకరమైన కాల్ బదిలీ ప్రోగ్రెస్లో ఉంది."</string>
<string name="supp_service_call_on_hold" msgid="2836811319594503059">"కాల్ హోల్డ్లో ఉంది."</string>
<string name="supp_service_call_resumed" msgid="3786864005920743546">"కాల్ మళ్లీ ప్రారంభించబడింది."</string>
<string name="supp_service_deflected_call" msgid="7565979024562921707">"కాల్ మళ్లించబడింది."</string>
- <string name="supp_service_forwarded_call" msgid="6475776013771821457">"కాల్ ఫార్వర్డ్ చేయబడింది."</string>
+ <string name="supp_service_forwarded_call" msgid="6475776013771821457">"కాల్ ఫార్వార్డ్ చేయబడింది."</string>
<string name="supp_service_conference_call" msgid="4004193534408317148">"కాన్ఫరెన్స్ కాల్లో చేరుతున్నారు"</string>
<string name="supp_service_held_call_released" msgid="2847835124639112410">"హోల్డ్లో ఉంచిన కాల్ ప్రారంభించబడింది."</string>
<string name="callFailed_otasp_provisioning_in_process" msgid="3345666183602879326">"వినియోగదారుకు ప్రస్తుతం ఏ సేవలు అందుబాటులో ఉన్నాయనే విచారణ పనిలో పరికరం ఉన్నందున కాల్ చేయడం సాధ్యం కాదు."</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 8218a84..d0f427c 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -207,8 +207,6 @@
<style name="DialerAlertDialogTheme"
parent="@android:style/Theme.Material.Light.Dialog">
<item name="android:forceDarkAllowed">true</item>
- <item name="android:colorAccent">@color/dialer_theme_color</item>
- <item name="android:textColor">?android:attr/textColorPrimaryInverseDisableOnly</item>
</style>
<style name="Empty" parent="@android:style/Theme.Material.Light">
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 307170a..cb774c7 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -1321,7 +1321,6 @@
boolean persistent) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MODIFY_PHONE_STATE, null);
- //TODO: Also check for SHELL UID to restrict this method to testing only (b/131326259)
int phoneId = SubscriptionManager.getPhoneId(subscriptionId);
if (!SubscriptionManager.isValidPhoneId(phoneId)) {
logd("Ignore invalid phoneId: " + phoneId + " for subId: " + subscriptionId);
diff --git a/src/com/android/phone/ImsRcsController.java b/src/com/android/phone/ImsRcsController.java
index bf55764..d4a0f1e 100644
--- a/src/com/android/phone/ImsRcsController.java
+++ b/src/com/android/phone/ImsRcsController.java
@@ -252,7 +252,7 @@
} catch (ImsException e) {
Log.e(TAG, "isCapable: sudId=" + subId
+ ", capability=" + capability + ", " + e.getMessage());
- return false;
+ throw new ServiceSpecificException(e.getCode(), e.getMessage());
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -278,7 +278,7 @@
} catch (ImsException e) {
Log.e(TAG, "isAvailable: sudId=" + subId
+ ", capability=" + capability + ", " + e.getMessage());
- return false;
+ throw new ServiceSpecificException(e.getCode(), e.getMessage());
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -786,16 +786,43 @@
int slotId = phone.getPhoneId();
if (!skipVerifyingConfig) {
verifyImsRcsConfiguredOrThrow(slotId);
+ verifyRcsSubIdActiveOrThrow(slotId, subId);
}
RcsFeatureController c = mRcsService.getFeatureController(slotId);
if (c == null) {
+ // If we hit this case, we have verified that TelephonyRcsService has processed any
+ // subId changes for the associated slot and applied configs. In this case, the configs
+ // do not have the RCS feature enabled.
throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
"The requested operation is not supported for subId " + subId);
}
+ if (!skipVerifyingConfig && c.getAssociatedSubId() != subId) {
+ // If we hit this case, the ImsFeature has not finished setting up the RCS feature yet
+ // or the RCS feature has crashed and is being set up again.
+ Log.w(TAG, "getRcsFeatureController: service unavailable on slot " + slotId
+ + " for subId " + subId);
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
+ "The ImsService is not currently available for subid " + subId
+ + ", please try again");
+ }
return c;
}
/**
+ * Ensure the TelephonyRcsService is tracking the supplied subId for the supplied slotId and has
+ * set up the stack.
+ */
+ private void verifyRcsSubIdActiveOrThrow(int slotId, int subId) {
+ if (mRcsService.verifyActiveSubId(slotId, subId)) return;
+
+ Log.w(TAG, "verifyRcsSubIdActiveOrThrow: verify failed, service not set up yet on "
+ + "slot " + slotId + " for subId " + subId);
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
+ "ImsService set up in progress for subId " + subId
+ + ", please try again");
+ }
+
+ /**
* Throw an ImsException if the IMS resolver does not have an ImsService configured for RCS
* for the given slot ID or no ImsResolver instance has been created.
* @param slotId The slot ID that the IMS service is created for.
diff --git a/src/com/android/phone/ImsStateCallbackController.java b/src/com/android/phone/ImsStateCallbackController.java
index 57c1787..edad754 100644
--- a/src/com/android/phone/ImsStateCallbackController.java
+++ b/src/com/android/phone/ImsStateCallbackController.java
@@ -68,6 +68,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
/**
@@ -143,6 +144,10 @@
private final SparseArray<MmTelFeatureListener> mMmTelFeatureListeners = new SparseArray<>();
private final SparseArray<RcsFeatureListener> mRcsFeatureListeners = new SparseArray<>();
+ // Container to store ImsManager instance by subId
+ private final ConcurrentHashMap<Integer, ImsManager> mSubIdToImsManagerCache =
+ new ConcurrentHashMap<>();
+
private final SubscriptionManager mSubscriptionManager;
private final TelephonyRegistryManager mTelephonyRegistryManager;
private MmTelFeatureConnectorFactory mMmTelFeatureFactory;
@@ -282,6 +287,13 @@
if (mSubId == subId) return;
logd(mLogPrefix + "setSubId changed subId=" + subId);
+ // subId changed from valid to invalid
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ if (VDBG) logv(mLogPrefix + "setSubId remove ImsManager " + mSubId);
+ // remove ImsManager reference associated with subId
+ mSubIdToImsManagerCache.remove(mSubId);
+ }
+
mSubId = subId;
}
@@ -298,6 +310,12 @@
mSubId = subId;
if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return;
+ // store ImsManager reference associated with subId
+ if (manager != null) {
+ if (VDBG) logv(mLogPrefix + "connectionReady add ImsManager " + subId);
+ mSubIdToImsManagerCache.put(subId, manager);
+ }
+
mState = STATE_READY;
mReason = AVAILABLE;
mHasConfig = true;
@@ -311,6 +329,10 @@
reason = convertReasonType(reason);
if (mReason == reason) return;
+ // remove ImsManager reference associated with subId
+ if (VDBG) logv(mLogPrefix + "connectionUnavailable remove ImsManager " + mSubId);
+ mSubIdToImsManagerCache.remove(mSubId);
+
connectionUnavailableInternal(reason);
}
@@ -319,7 +341,7 @@
mReason = reason;
/* If having no IMS package for MMTEL,
- * dicard the reason except REASON_NO_IMS_SERVICE_CONFIGURED. */
+ * discard the reason except REASON_NO_IMS_SERVICE_CONFIGURED. */
if (!mHasConfig && reason != REASON_NO_IMS_SERVICE_CONFIGURED) return;
onFeatureStateChange(mSubId, FEATURE_MMTEL, mState, mReason);
@@ -973,6 +995,19 @@
mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_CALLBACK, cb));
}
+ /**
+ * Get ImsManager reference associated with subId
+ *
+ * @param subId subscribe ID
+ * @return instance of ImsManager associated with subId, but if ImsService is not
+ * available return null
+ */
+ public ImsManager getImsManager(int subId) {
+ if (VDBG) logv("getImsManager subId = " + subId);
+
+ return mSubIdToImsManagerCache.get(subId);
+ }
+
private void removeInactiveCallbacks(
ArrayList<IBinder> inactiveCallbacks, String message) {
if (inactiveCallbacks == null || inactiveCallbacks.size() == 0) return;
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index f2641a1..27e1606 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.READ_PHONE_STATE;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.BroadcastOptions;
import android.app.Notification;
@@ -47,6 +48,7 @@
import android.telecom.TelecomManager;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
+import android.telephony.RadioAccessFamily;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -57,8 +59,10 @@
import android.util.SparseArray;
import android.widget.Toast;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.TelephonyCapabilities;
import com.android.internal.telephony.util.NotificationChannelController;
import com.android.phone.settings.VoicemailSettingsActivity;
@@ -163,7 +167,8 @@
* Private constructor (this is a singleton).
* @see #init(PhoneGlobals)
*/
- private NotificationMgr(PhoneGlobals app) {
+ @VisibleForTesting
+ /* package */ NotificationMgr(PhoneGlobals app) {
mApp = app;
mContext = app;
mStatusBarManager =
@@ -895,15 +900,22 @@
Log.i(LOG_TAG, msg);
}
- /**
- * In case network selection notification shows up repeatedly under
- * unstable network condition. The logic is to check whether or not
- * the service state keeps in no service condition for at least
- * {@link #NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIME_IN_MS}.
- * And checking {@link #NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIMES} times.
- * To avoid the notification showing up for the momentary state.
- */
private void shouldShowNotification(int serviceState, int subId) {
+ // "Network selection unavailable" notification should only show when network selection is
+ // visible to the end user. Some CC items e.g. KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL
+ // can be overridden to hide the network selection to the end user. In this case, the
+ // notification is not shown to avoid confusion to the end user.
+ if (!shouldDisplayNetworkSelectOptions(subId)) {
+ logi("Carrier configs refuse to show network selection not available notification");
+ return;
+ }
+
+ // In case network selection notification shows up repeatedly under
+ // unstable network condition. The logic is to check whether or not
+ // the service state keeps in no service condition for at least
+ // {@link #NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIME_IN_MS}.
+ // And checking {@link #NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIMES} times.
+ // To avoid the notification showing up for the momentary state.
if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) {
if (mPreviousServiceState.get(subId, STATE_UNKNOWN_SERVICE)
!= ServiceState.STATE_OUT_OF_SERVICE) {
@@ -930,6 +942,113 @@
}
}
+ // TODO(b/243010310): merge methods below with Settings#MobileNetworkUtils and optimize them.
+ // The methods below are copied from com.android.settings.network.telephony.MobileNetworkUtils
+ // to make sure the network selection unavailable notification should not show when Network
+ // Selection menu is not present in Settings app.
+ private boolean shouldDisplayNetworkSelectOptions(int subId) {
+ final TelephonyManager telephonyManager = mTelephonyManager.createForSubscriptionId(subId);
+ final CarrierConfigManager carrierConfigManager = mContext.getSystemService(
+ CarrierConfigManager.class);
+ final PersistableBundle carrierConfig = carrierConfigManager.getConfigForSubId(subId);
+
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID
+ || carrierConfig == null
+ || !carrierConfig.getBoolean(
+ CarrierConfigManager.KEY_OPERATOR_SELECTION_EXPAND_BOOL)
+ || carrierConfig.getBoolean(
+ CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL)
+ || (carrierConfig.getBoolean(CarrierConfigManager.KEY_CSP_ENABLED_BOOL)
+ && !telephonyManager.isManualNetworkSelectionAllowed())) {
+ return false;
+ }
+
+ if (isWorldMode(carrierConfig)) {
+ final int networkMode = RadioAccessFamily.getNetworkTypeFromRaf(
+ (int) telephonyManager.getAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER));
+ if (networkMode == RILConstants.NETWORK_MODE_LTE_CDMA_EVDO) {
+ return false;
+ }
+ if (shouldSpeciallyUpdateGsmCdma(telephonyManager, carrierConfig)) {
+ return false;
+ }
+ if (networkMode == RILConstants.NETWORK_MODE_LTE_GSM_WCDMA) {
+ return true;
+ }
+ }
+
+ return isGsmBasicOptions(telephonyManager, carrierConfig);
+ }
+
+ private static boolean isWorldMode(@NonNull PersistableBundle carrierConfig) {
+ return carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_MODE_ENABLED_BOOL);
+ }
+
+ private static boolean shouldSpeciallyUpdateGsmCdma(@NonNull TelephonyManager telephonyManager,
+ @NonNull PersistableBundle carrierConfig) {
+ if (!isWorldMode(carrierConfig)) {
+ return false;
+ }
+
+ final int networkMode = RadioAccessFamily.getNetworkTypeFromRaf(
+ (int) telephonyManager.getAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER));
+ if (networkMode == RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM
+ || networkMode == RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA
+ || networkMode == RILConstants.NETWORK_MODE_LTE_TDSCDMA
+ || networkMode == RILConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA
+ || networkMode
+ == RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA
+ || networkMode == RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA) {
+ if (!isTdscdmaSupported(telephonyManager, carrierConfig)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean isTdscdmaSupported(@NonNull TelephonyManager telephonyManager,
+ @NonNull PersistableBundle carrierConfig) {
+ if (carrierConfig.getBoolean(CarrierConfigManager.KEY_SUPPORT_TDSCDMA_BOOL)) {
+ return true;
+ }
+ final String[] numericArray = carrierConfig.getStringArray(
+ CarrierConfigManager.KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY);
+ if (numericArray == null) {
+ return false;
+ }
+ final ServiceState serviceState = telephonyManager.getServiceState();
+ final String operatorNumeric =
+ (serviceState != null) ? serviceState.getOperatorNumeric() : null;
+ if (operatorNumeric == null) {
+ return false;
+ }
+ for (String numeric : numericArray) {
+ if (operatorNumeric.equals(numeric)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean isGsmBasicOptions(@NonNull TelephonyManager telephonyManager,
+ @NonNull PersistableBundle carrierConfig) {
+ if (!carrierConfig.getBoolean(
+ CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL)
+ && carrierConfig.getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL)) {
+ return true;
+ }
+
+ if (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) {
+ return true;
+ }
+
+ return false;
+ }
+ // END of TODO:(b/243010310): merge methods above with Settings#MobileNetworkUtils and optimize.
+
private void startPendingNetworkSelectionNotification(int subId) {
if (!mHandler.hasMessages(EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION, subId)) {
if (DBG) {
diff --git a/src/com/android/phone/PhoneDisplayMessage.java b/src/com/android/phone/PhoneDisplayMessage.java
index be7fc7f..c487cba 100644
--- a/src/com/android/phone/PhoneDisplayMessage.java
+++ b/src/com/android/phone/PhoneDisplayMessage.java
@@ -80,7 +80,8 @@
sDisplayMessageDialog.getWindow().addFlags(
WindowManager.LayoutParams.FLAG_DIM_BEHIND
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
- | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
sDisplayMessageDialog.show();
}
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 99e73ff..f6ec75d 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -549,15 +549,15 @@
mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED, null);
mTelephonyCallbacks = new PhoneAppCallback[tm.getSupportedModemCount()];
-
- for (Phone phone : PhoneFactory.getPhones()) {
- int subId = phone.getSubId();
- PhoneAppCallback callback = new PhoneAppCallback(subId);
- tm.createForSubscriptionId(subId).registerTelephonyCallback(
- TelephonyManager.INCLUDE_LOCATION_DATA_NONE, mHandler::post, callback);
- mTelephonyCallbacks[phone.getPhoneId()] = callback;
+ if (tm.getSupportedModemCount() > 0) {
+ for (Phone phone : PhoneFactory.getPhones()) {
+ int subId = phone.getSubId();
+ PhoneAppCallback callback = new PhoneAppCallback(subId);
+ tm.createForSubscriptionId(subId).registerTelephonyCallback(
+ TelephonyManager.INCLUDE_LOCATION_DATA_NONE, mHandler::post, callback);
+ mTelephonyCallbacks[phone.getPhoneId()] = callback;
+ }
}
-
mCarrierVvmPackageInstalledReceiver.register(this);
//set the default values for the preferences in the phone.
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 66cef64..7ed5eea 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -2851,6 +2851,95 @@
}
}
+ /**
+ * Vote on powering off the radio for a reason. The radio will be turned on only when there is
+ * no reason to power it off. When any of the voters want to power it off, it will be turned
+ * off. In case of emergency, the radio will be turned on even if there are some reasons for
+ * powering it off, and these radio off votes will be cleared.
+ * Multiple apps can vote for the same reason and the last vote will take effect. Each app is
+ * responsible for its vote. A powering-off vote of a reason will be maintained until it is
+ * cleared by calling {@link clearRadioPowerOffForReason} for that reason, or an emergency call
+ * is made, or the device is rebooted. When an app comes backup from a crash, it needs to make
+ * sure if its vote is as expected. An app can use the API {@link getRadioPowerOffReasons} to
+ * check its vote.
+ *
+ * @param subId The subscription ID.
+ * @param reason The reason for powering off radio.
+ * @return true on success and false on failure.
+ */
+ public boolean requestRadioPowerOffForReason(int subId,
+ @TelephonyManager.RadioPowerReason int reason) {
+ enforceModifyPermission();
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final Phone phone = getPhone(subId);
+ if (phone != null) {
+ phone.setRadioPowerForReason(false, reason);
+ return true;
+ } else {
+ return false;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Remove the vote on powering off the radio for a reason, as requested by
+ * {@link requestRadioPowerOffForReason}.
+ *
+ * @param subId The subscription ID.
+ * @param reason The reason for powering off radio.
+ * @return true on success and false on failure.
+ */
+ public boolean clearRadioPowerOffForReason(int subId,
+ @TelephonyManager.RadioPowerReason int reason) {
+ enforceModifyPermission();
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final Phone phone = getPhone(subId);
+ if (phone != null) {
+ phone.setRadioPowerForReason(true, reason);
+ return true;
+ } else {
+ return false;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Get reasons for powering off radio, as requested by {@link requestRadioPowerOffForReason}.
+ *
+ * @param subId The subscription ID.
+ * @param callingPackage The package making the call.
+ * @param callingFeatureId The feature in the package.
+ * @return List of reasons for powering off radio.
+ */
+ public List getRadioPowerOffReasons(int subId, String callingPackage, String callingFeatureId) {
+ enforceReadPrivilegedPermission("getRadioPowerOffReasons");
+
+ final long identity = Binder.clearCallingIdentity();
+ List result = new ArrayList();
+ try {
+ if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, subId,
+ callingPackage, callingFeatureId, "getRadioPowerOffReasons")) {
+ return result;
+ }
+
+ final Phone phone = getPhone(subId);
+ if (phone != null) {
+ result.addAll(phone.getRadioPowerOffReasons());
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ return result;
+ }
+
// FIXME: subId version needed
@Override
public boolean enableDataConnectivity(String callingPackage) {
@@ -4046,7 +4135,18 @@
try {
int slotId = getSlotIndexOrException(subId);
verifyImsMmTelConfiguredOrThrow(slotId);
- ImsManager.getInstance(mApp, slotId).addRegistrationCallbackForSubscription(c, subId);
+
+ ImsStateCallbackController controller = ImsStateCallbackController.getInstance();
+ if (controller != null) {
+ ImsManager imsManager = controller.getImsManager(subId);
+ if (imsManager != null) {
+ imsManager.addRegistrationCallbackForSubscription(c, subId);
+ } else {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ } else {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
+ }
} catch (ImsException e) {
throw new ServiceSpecificException(e.getCode());
} finally {
@@ -4067,14 +4167,20 @@
throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
}
final long token = Binder.clearCallingIdentity();
+
try {
- ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
- .removeRegistrationCallbackForSubscription(c, subId);
- } catch (ImsException e) {
- Log.i(LOG_TAG, "unregisterImsRegistrationCallback: " + subId
- + "is inactive, ignoring unregister.");
- // If the subscription is no longer active, just return, since the callback
- // will already have been removed internally.
+ ImsStateCallbackController controller = ImsStateCallbackController.getInstance();
+ if (controller != null) {
+ ImsManager imsManager = controller.getImsManager(subId);
+ if (imsManager != null) {
+ imsManager.removeRegistrationCallbackForSubscription(c, subId);
+ } else {
+ Log.i(LOG_TAG, "unregisterImsRegistrationCallback: " + subId
+ + "is inactive, ignoring unregister.");
+ // If the ImsManager is not valid, just return, since the callback
+ // will already have been removed internally.
+ }
+ }
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -8095,8 +8201,7 @@
}
String vvmPackage = componentName.getPackageName();
if (!callingPackage.equals(vvmPackage)) {
- throw new SecurityException("Caller not current active visual voicemail package["
- + vvmPackage + "]");
+ throw new SecurityException("Caller not current active visual voicemail package");
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -10150,7 +10255,7 @@
for (int i = 0; i < TelephonyManager.getDefault().getActiveModemCount(); i++) {
Phone phone = PhoneFactory.getPhone(i);
if (phone != null) {
- phone.setRadioPowerForReason(enable, Phone.RADIO_POWER_REASON_THERMAL);
+ phone.setRadioPowerForReason(enable, TelephonyManager.RADIO_POWER_REASON_THERMAL);
isPhoneAvailable = true;
}
}
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index 695a4a4..d0aad4a 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -469,7 +469,7 @@
// build the dialog
final AlertDialog newDialog =
- FrameworksUtils.makeAlertDialogBuilder(contextThemeWrapper)
+ new AlertDialog.Builder(contextThemeWrapper)
.setMessage(text)
.setView(dialogView)
.setPositiveButton(R.string.send_button, mUSSDDialogListener)
diff --git a/src/com/android/phone/RcsProvisioningMonitor.java b/src/com/android/phone/RcsProvisioningMonitor.java
index 1ed0d72..a948d08 100644
--- a/src/com/android/phone/RcsProvisioningMonitor.java
+++ b/src/com/android/phone/RcsProvisioningMonitor.java
@@ -828,7 +828,7 @@
private void onConfigReceived(int subId, byte[] config, boolean isCompressed) {
logv("onConfigReceived, subId:" + subId + ", config:"
- + config + ", isCompressed:" + isCompressed);
+ + Arrays.toString(config) + ", isCompressed:" + isCompressed);
RcsProvisioningInfo info = mRcsProvisioningInfos.get(subId);
if (info == null) {
logd("sub[" + subId + "] has been removed");
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index 669e830..2c13060 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -63,6 +63,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
@@ -167,6 +168,13 @@
private static final String ALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND = "allow-package";
private static final String DISALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND = "disallow-package";
+ private static final String INVALID_ENTRY_ERROR = "An emergency number (only allow '0'-'9', "
+ + "'*', '#' or '+') needs to be specified after -a in the command ";
+
+ private static final int[] ROUTING_TYPES = {EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN,
+ EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY,
+ EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL};
+
private static final String GET_ALLOWED_NETWORK_TYPES_FOR_USER =
"get-allowed-network-types-for-users";
private static final String SET_ALLOWED_NETWORK_TYPES_FOR_USER =
@@ -789,6 +797,24 @@
return 0;
}
+ private void removeEmergencyNumberTestMode(String emergencyNumber) {
+ PrintWriter errPw = getErrPrintWriter();
+ for (int routingType : ROUTING_TYPES) {
+ try {
+ mInterface.updateEmergencyNumberListTestMode(
+ EmergencyNumberTracker.REMOVE_EMERGENCY_NUMBER_TEST_MODE,
+ new EmergencyNumber(emergencyNumber, "", "",
+ EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
+ new ArrayList<String>(),
+ EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
+ routingType));
+ } catch (RemoteException ex) {
+ Log.w(LOG_TAG, "emergency-number-test-mode " + "error " + ex.getMessage());
+ errPw.println("Exception: " + ex.getMessage());
+ }
+ }
+ }
+
private int handleEmergencyNumberTestModeCommand() {
PrintWriter errPw = getErrPrintWriter();
String opt = getNextOption();
@@ -796,26 +822,52 @@
onHelpEmergencyNumber();
return 0;
}
-
switch (opt) {
case "-a": {
String emergencyNumberCmd = getNextArgRequired();
- if (emergencyNumberCmd == null
- || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
- errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
- + " to be specified after -a in the command ");
+ if (emergencyNumberCmd == null){
+ errPw.println(INVALID_ENTRY_ERROR);
return -1;
}
+ String[] params = emergencyNumberCmd.split(":");
+ String emergencyNumber;
+ if (params[0] == null ||
+ !EmergencyNumber.validateEmergencyNumberAddress(params[0])){
+ errPw.println(INVALID_ENTRY_ERROR);
+ return -1;
+ } else {
+ emergencyNumber = params[0];
+ }
+ removeEmergencyNumberTestMode(emergencyNumber);
+ int emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN;
+ if (params.length > 1) {
+ switch (params[1].toLowerCase(Locale.ROOT)) {
+ case "emergency":
+ emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY;
+ break;
+ case "normal":
+ emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL;
+ break;
+ case "unknown":
+ break;
+ default:
+ errPw.println("\"" + params[1] + "\" is not a valid specification for "
+ + "emergency call routing. Please enter either \"normal\", "
+ + "\"unknown\", or \"emergency\" for call routing. "
+ + "(-a 1234:normal)");
+ return -1;
+ }
+ }
try {
mInterface.updateEmergencyNumberListTestMode(
EmergencyNumberTracker.ADD_EMERGENCY_NUMBER_TEST_MODE,
- new EmergencyNumber(emergencyNumberCmd, "", "",
+ new EmergencyNumber(emergencyNumber, "", "",
EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
new ArrayList<String>(),
EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
- EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
+ emergencyCallRouting));
} catch (RemoteException ex) {
- Log.w(LOG_TAG, "emergency-number-test-mode -a " + emergencyNumberCmd
+ Log.w(LOG_TAG, "emergency-number-test-mode -a " + emergencyNumber
+ ", error " + ex.getMessage());
errPw.println("Exception: " + ex.getMessage());
return -1;
@@ -841,20 +893,7 @@
+ " to be specified after -r in the command ");
return -1;
}
- try {
- mInterface.updateEmergencyNumberListTestMode(
- EmergencyNumberTracker.REMOVE_EMERGENCY_NUMBER_TEST_MODE,
- new EmergencyNumber(emergencyNumberCmd, "", "",
- EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
- new ArrayList<String>(),
- EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
- EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
- } catch (RemoteException ex) {
- Log.w(LOG_TAG, "emergency-number-test-mode -r " + emergencyNumberCmd
- + ", error " + ex.getMessage());
- errPw.println("Exception: " + ex.getMessage());
- return -1;
- }
+ removeEmergencyNumberTestMode(emergencyNumberCmd);
break;
}
case "-p": {
@@ -1646,7 +1685,7 @@
String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUES_FROM_XML + ": ";
// Parse all options
- CcOptionParseResult options = parseCcOptions(tag, false);
+ CcOptionParseResult options = parseCcOptions(tag, true);
if (options == null) {
return -1;
}
diff --git a/src/com/android/phone/settings/RadioInfo.java b/src/com/android/phone/settings/RadioInfo.java
index 2058d2d..d4367ca 100644
--- a/src/com/android/phone/settings/RadioInfo.java
+++ b/src/com/android/phone/settings/RadioInfo.java
@@ -72,6 +72,13 @@
import android.telephony.TelephonyDisplayInfo;
import android.telephony.TelephonyManager;
import android.telephony.data.NetworkSlicingConfig;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.ImsManager;
+import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ImsRcsManager;
+import android.telephony.ims.ProvisioningManager;
+import android.telephony.ims.feature.MmTelFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
@@ -92,9 +99,6 @@
import androidx.appcompat.app.AlertDialog.Builder;
import androidx.appcompat.app.AppCompatActivity;
-import com.android.ims.ImsConfig;
-import com.android.ims.ImsException;
-import com.android.ims.ImsManager;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.euicc.EuiccConnector;
@@ -176,18 +180,6 @@
*/
private static final int ALWAYS_ON_DSDS_MODE = 1;
- private static final int IMS_VOLTE_PROVISIONED_CONFIG_ID =
- ImsConfig.ConfigConstants.VLT_SETTING_ENABLED;
-
- private static final int IMS_VT_PROVISIONED_CONFIG_ID =
- ImsConfig.ConfigConstants.LVC_SETTING_ENABLED;
-
- private static final int IMS_WFC_PROVISIONED_CONFIG_ID =
- ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED;
-
- private static final int EAB_PROVISIONED_CONFIG_ID =
- ImsConfig.ConfigConstants.EAB_SETTING_ENABLED;
-
//Values in must match CELL_INFO_REFRESH_RATES
private static final String[] CELL_INFO_REFRESH_RATE_LABELS = {
"Disabled",
@@ -291,6 +283,7 @@
private TelephonyManager mTelephonyManager;
private ImsManager mImsManager = null;
private Phone mPhone = null;
+ private ProvisioningManager mProvisioningManager = null;
private String mPingHostnameResultV4;
private String mPingHostnameResultV6;
@@ -423,8 +416,9 @@
mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId);
// update the phoneId
- mImsManager = ImsManager.getInstance(getApplicationContext(), phoneIndex);
mPhone = PhoneFactory.getPhone(phoneIndex);
+ mImsManager = new ImsManager(mPhone.getContext());
+ mProvisioningManager = ProvisioningManager.createForSubscriptionId(mPhone.getSubId());
updateAllFields();
}
@@ -484,7 +478,8 @@
mTelephonyManager = ((TelephonyManager) getSystemService(TELEPHONY_SERVICE))
.createForSubscriptionId(mPhone.getSubId());
- mImsManager = ImsManager.getInstance(getApplicationContext(), mPhone.getPhoneId());
+ mImsManager = new ImsManager(mPhone.getContext());
+ mProvisioningManager = ProvisioningManager.createForSubscriptionId(mPhone.getSubId());
sPhoneIndexLabels = getPhoneIndexLabels(mTelephonyManager);
@@ -552,7 +547,7 @@
mImsWfcProvisionedSwitch = (Switch) findViewById(R.id.wfc_provisioned_switch);
mEabProvisionedSwitch = (Switch) findViewById(R.id.eab_provisioned_switch);
- if (!ImsManager.isImsSupportedOnDevice(mPhone.getContext())) {
+ if (!isImsSupportedOnDevice(mPhone.getContext())) {
mImsVolteProvisionedSwitch.setVisibility(View.GONE);
mImsVtProvisionedSwitch.setVisibility(View.GONE);
mImsWfcProvisionedSwitch.setVisibility(View.GONE);
@@ -774,7 +769,8 @@
R.string.radioInfo_menu_viewFDN).setOnMenuItemClickListener(mViewFDNCallback);
menu.add(1, MENU_ITEM_VIEW_SDN, 0,
R.string.radioInfo_menu_viewSDN).setOnMenuItemClickListener(mViewSDNCallback);
- if (ImsManager.isImsSupportedOnDevice(mPhone.getContext())) {
+
+ if (isImsSupportedOnDevice(mPhone.getContext())) {
menu.add(1, MENU_ITEM_GET_IMS_STATUS,
0, R.string.radioInfo_menu_getIMS).setOnMenuItemClickListener(mGetImsStatus);
}
@@ -1502,34 +1498,38 @@
mRadioPowerOnSwitch.setOnCheckedChangeListener(mRadioPowerOnChangeListener);
}
- void setImsVolteProvisionedState(boolean state) {
+ private void setImsVolteProvisionedState(boolean state) {
Log.d(TAG, "setImsVolteProvisioned state: " + ((state) ? "on" : "off"));
- setImsConfigProvisionedState(IMS_VOLTE_PROVISIONED_CONFIG_ID, state);
+ setImsConfigProvisionedState(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE, state);
}
- void setImsVtProvisionedState(boolean state) {
+ private void setImsVtProvisionedState(boolean state) {
Log.d(TAG, "setImsVtProvisioned() state: " + ((state) ? "on" : "off"));
- setImsConfigProvisionedState(IMS_VT_PROVISIONED_CONFIG_ID, state);
+ setImsConfigProvisionedState(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE, state);
}
- void setImsWfcProvisionedState(boolean state) {
+ private void setImsWfcProvisionedState(boolean state) {
Log.d(TAG, "setImsWfcProvisioned() state: " + ((state) ? "on" : "off"));
- setImsConfigProvisionedState(IMS_WFC_PROVISIONED_CONFIG_ID, state);
+ setImsConfigProvisionedState(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN, state);
}
- void setEabProvisionedState(boolean state) {
+ private void setEabProvisionedState(boolean state) {
Log.d(TAG, "setEabProvisioned() state: " + ((state) ? "on" : "off"));
- setImsConfigProvisionedState(EAB_PROVISIONED_CONFIG_ID, state);
+ setRcsConfigProvisionedState(ImsRcsManager.CAPABILITY_TYPE_PRESENCE_UCE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE, state);
}
- void setImsConfigProvisionedState(int configItem, boolean state) {
- if (mPhone != null && mImsManager != null) {
+ private void setImsConfigProvisionedState(int capability, int tech, boolean state) {
+ if (mProvisioningManager != null) {
mQueuedWork.execute(new Runnable() {
public void run() {
try {
- mImsManager.getConfigInterface().setProvisionedValue(
- configItem, state ? 1 : 0);
- } catch (ImsException e) {
+ mProvisioningManager.setProvisioningStatusForCapability(
+ capability, tech, state);
+ } catch (RuntimeException e) {
Log.e(TAG, "setImsConfigProvisioned() exception:", e);
}
}
@@ -1537,6 +1537,71 @@
}
}
+ private void setRcsConfigProvisionedState(int capability, int tech, boolean state) {
+ if (mProvisioningManager != null) {
+ mQueuedWork.execute(new Runnable() {
+ public void run() {
+ try {
+ mProvisioningManager.setRcsProvisioningStatusForCapability(
+ capability, tech, state);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "setRcsConfigProvisioned() exception:", e);
+ }
+ }
+ });
+ }
+ }
+
+ private boolean isImsVolteProvisioningRequired() {
+ return isImsConfigProvisioningRequired(
+ MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+ }
+
+ private boolean isImsVtProvisioningRequired() {
+ return isImsConfigProvisioningRequired(
+ MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+ }
+
+ private boolean isImsWfcProvisioningRequired() {
+ return isImsConfigProvisioningRequired(
+ MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN);
+ }
+
+ private boolean isEabProvisioningRequired() {
+ return isRcsConfigProvisioningRequired(
+ ImsRcsManager.CAPABILITY_TYPE_PRESENCE_UCE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+ }
+
+ private boolean isImsConfigProvisioningRequired(int capability, int tech) {
+ if (mProvisioningManager != null) {
+ try {
+ return mProvisioningManager.isProvisioningRequiredForCapability(
+ capability, tech);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "isImsConfigProvisioningRequired() exception:", e);
+ }
+ }
+
+ return false;
+ }
+
+ private boolean isRcsConfigProvisioningRequired(int capability, int tech) {
+ if (mProvisioningManager != null) {
+ try {
+ return mProvisioningManager.isRcsProvisioningRequiredForCapability(
+ capability, tech);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "isRcsConfigProvisioningRequired() exception:", e);
+ }
+ }
+
+ return false;
+ }
+
OnCheckedChangeListener mRadioPowerOnChangeListener = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
@@ -1556,11 +1621,8 @@
};
private boolean isImsVolteProvisioned() {
- if (mImsManager != null) {
- return mImsManager.isVolteEnabledByPlatform()
- && mImsManager.isVolteProvisionedOnDevice();
- }
- return false;
+ return getImsConfigProvisionedState(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
}
OnCheckedChangeListener mImsVolteCheckedChangeListener = new OnCheckedChangeListener() {
@@ -1571,11 +1633,8 @@
};
private boolean isImsVtProvisioned() {
- if (mImsManager != null) {
- return mImsManager.isVtEnabledByPlatform()
- && mImsManager.isVtProvisionedOnDevice();
- }
- return false;
+ return getImsConfigProvisionedState(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
}
OnCheckedChangeListener mImsVtCheckedChangeListener = new OnCheckedChangeListener() {
@@ -1586,11 +1645,8 @@
};
private boolean isImsWfcProvisioned() {
- if (mImsManager != null) {
- return mImsManager.isWfcEnabledByPlatform()
- && mImsManager.isWfcProvisionedOnDevice();
- }
- return false;
+ return getImsConfigProvisionedState(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN);
}
OnCheckedChangeListener mImsWfcCheckedChangeListener = new OnCheckedChangeListener() {
@@ -1601,7 +1657,8 @@
};
private boolean isEabProvisioned() {
- return isFeatureProvisioned(EAB_PROVISIONED_CONFIG_ID, false);
+ return getRcsConfigProvisionedState(ImsRcsManager.CAPABILITY_TYPE_PRESENCE_UCE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
}
OnCheckedChangeListener mEabCheckedChangeListener = new OnCheckedChangeListener() {
@@ -1611,23 +1668,30 @@
}
};
- private boolean isFeatureProvisioned(int featureId, boolean defaultValue) {
- boolean provisioned = defaultValue;
- if (mImsManager != null) {
+ private boolean getImsConfigProvisionedState(int capability, int tech) {
+ if (mProvisioningManager != null) {
try {
- ImsConfig imsConfig = mImsManager.getConfigInterface();
- if (imsConfig != null) {
- provisioned =
- (imsConfig.getProvisionedValue(featureId)
- == ImsConfig.FeatureValueConstants.ON);
- }
- } catch (ImsException ex) {
- Log.e(TAG, "isFeatureProvisioned() exception:", ex);
+ return mProvisioningManager.getProvisioningStatusForCapability(
+ capability, tech);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "getImsConfigProvisionedState() exception:", e);
}
}
- log("isFeatureProvisioned() featureId=" + featureId + " provisioned=" + provisioned);
- return provisioned;
+ return false;
+ }
+
+ private boolean getRcsConfigProvisionedState(int capability, int tech) {
+ if (mProvisioningManager != null) {
+ try {
+ return mProvisioningManager.getRcsProvisioningStatusForCapability(
+ capability, tech);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "getRcsConfigProvisionedState() exception:", e);
+ }
+ }
+
+ return false;
}
private boolean isEabEnabledByPlatform() {
@@ -1646,35 +1710,56 @@
}
private void updateImsProvisionedState() {
- if (!ImsManager.isImsSupportedOnDevice(mPhone.getContext())) {
+ if (!isImsSupportedOnDevice(mPhone.getContext())) {
return;
}
- log("updateImsProvisionedState isImsVolteProvisioned()=" + isImsVolteProvisioned());
- //delightful hack to prevent on-checked-changed calls from
- //actually forcing the ims provisioning to its transient/current value.
+
+ updateServiceEnabledByPlatform();
+
+ updateEabProvisionedSwitch(isEabEnabledByPlatform());
+ }
+
+ private void updateVolteProvisionedSwitch(boolean isEnabledByPlatform) {
+ boolean isProvisioned = isEnabledByPlatform && isImsVolteProvisioned();
+ log("updateImsProvisionedState isProvisioned" + isProvisioned);
+
mImsVolteProvisionedSwitch.setOnCheckedChangeListener(null);
- mImsVolteProvisionedSwitch.setChecked(isImsVolteProvisioned());
+ mImsVolteProvisionedSwitch.setChecked(isProvisioned);
mImsVolteProvisionedSwitch.setOnCheckedChangeListener(mImsVolteCheckedChangeListener);
mImsVolteProvisionedSwitch.setEnabled(!IS_USER_BUILD
- && mImsManager.isVolteEnabledByPlatform());
+ && isEnabledByPlatform && isImsVolteProvisioningRequired());
+ }
+
+ private void updateVtProvisionedSwitch(boolean isEnabledByPlatform) {
+ boolean isProvisioned = isEnabledByPlatform && isImsVtProvisioned();
+ log("updateVtProvisionedSwitch isProvisioned" + isProvisioned);
mImsVtProvisionedSwitch.setOnCheckedChangeListener(null);
- mImsVtProvisionedSwitch.setChecked(isImsVtProvisioned());
+ mImsVtProvisionedSwitch.setChecked(isProvisioned);
mImsVtProvisionedSwitch.setOnCheckedChangeListener(mImsVtCheckedChangeListener);
mImsVtProvisionedSwitch.setEnabled(!IS_USER_BUILD
- && mImsManager.isVtEnabledByPlatform());
+ && isEnabledByPlatform && isImsVtProvisioningRequired());
+ }
+
+ private void updateWfcProvisionedSwitch(boolean isEnabledByPlatform) {
+ boolean isProvisioned = isEnabledByPlatform && isImsWfcProvisioned();
+ log("updateWfcProvisionedSwitch isProvisioned" + isProvisioned);
mImsWfcProvisionedSwitch.setOnCheckedChangeListener(null);
- mImsWfcProvisionedSwitch.setChecked(isImsWfcProvisioned());
+ mImsWfcProvisionedSwitch.setChecked(isProvisioned);
mImsWfcProvisionedSwitch.setOnCheckedChangeListener(mImsWfcCheckedChangeListener);
mImsWfcProvisionedSwitch.setEnabled(!IS_USER_BUILD
- && mImsManager.isWfcEnabledByPlatform());
+ && isEnabledByPlatform && isImsWfcProvisioningRequired());
+ }
+
+ private void updateEabProvisionedSwitch(boolean isEnabledByPlatform) {
+ log("updateEabProvisionedSwitch isEabWfcProvisioned()=" + isEabProvisioned());
mEabProvisionedSwitch.setOnCheckedChangeListener(null);
mEabProvisionedSwitch.setChecked(isEabProvisioned());
mEabProvisionedSwitch.setOnCheckedChangeListener(mEabCheckedChangeListener);
mEabProvisionedSwitch.setEnabled(!IS_USER_BUILD
- && isEabEnabledByPlatform());
+ && isEnabledByPlatform && isEabProvisioningRequired());
}
OnClickListener mDnsCheckButtonHandler = new OnClickListener() {
@@ -1913,4 +1998,28 @@
intent.putExtra("isDefault", isChecked);
sendBroadcast(intent);
}
+
+ private boolean isImsSupportedOnDevice(Context context) {
+ return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS);
+ }
+
+ private void updateServiceEnabledByPlatform() {
+ ImsMmTelManager imsMmTelManager = mImsManager.getImsMmTelManager(mPhone.getSubId());
+ try {
+ imsMmTelManager.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN, getMainExecutor(), (result) -> {
+ updateVolteProvisionedSwitch(result);
+ });
+ imsMmTelManager.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN, getMainExecutor(), (result) -> {
+ updateVtProvisionedSwitch(result);
+ });
+ imsMmTelManager.isSupported(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN, getMainExecutor(), (result) -> {
+ updateWfcProvisionedSwitch(result);
+ });
+ } catch (ImsException e) {
+ e.printStackTrace();
+ }
+ }
}
diff --git a/src/com/android/phone/settings/VoicemailProviderSettings.java b/src/com/android/phone/settings/VoicemailProviderSettings.java
index fc2e7f8..10f0ddb 100644
--- a/src/com/android/phone/settings/VoicemailProviderSettings.java
+++ b/src/com/android/phone/settings/VoicemailProviderSettings.java
@@ -21,6 +21,8 @@
import com.android.internal.telephony.CallForwardInfo;
import com.android.internal.telephony.CommandsInterface;
+import java.util.Arrays;
+
/**
* Settings for a voicemail provider, including any conditional forwarding information.
*/
@@ -88,7 +90,7 @@
@Override
public String toString() {
return mVoicemailNumber + ((mForwardingSettings == null) ? ""
- : ", " + mForwardingSettings.toString());
+ : ", " + Arrays.toString(mForwardingSettings));
}
public String getVoicemailNumber() {
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index 9321e1e..587ac43 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -25,6 +25,7 @@
import android.telephony.SubscriptionManager;
import android.telephony.ims.ImsReasonInfo;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.CallFailCause;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
@@ -101,14 +102,29 @@
public static DisconnectCause toTelecomDisconnectCause(
int telephonyDisconnectCause, int telephonyPreciseDisconnectCause, String reason,
int phoneId, ImsReasonInfo imsReasonInfo) {
+ return toTelecomDisconnectCause(telephonyDisconnectCause, telephonyPreciseDisconnectCause,
+ reason, phoneId, imsReasonInfo, getCarrierConfigBundle(phoneId));
+ }
+
+ /**
+ * Final pre-processing method in creating a DisconnectCause. This method should NOT be called
+ * from another class directly. It only has private-package visibility for testing.
+ *
+ * @param carrierConfig
+ */
+ @VisibleForTesting
+ static DisconnectCause toTelecomDisconnectCause(
+ int telephonyDisconnectCause, int telephonyPreciseDisconnectCause, String reason,
+ int phoneId, ImsReasonInfo imsReasonInfo, PersistableBundle carrierConfig) {
Context context = PhoneGlobals.getInstance();
+
return new DisconnectCause(
- toTelecomDisconnectCauseCode(telephonyDisconnectCause),
+ toTelecomDisconnectCauseCode(telephonyDisconnectCause, carrierConfig),
toTelecomDisconnectCauseLabel(context, telephonyDisconnectCause,
- telephonyPreciseDisconnectCause),
+ telephonyPreciseDisconnectCause, carrierConfig),
toTelecomDisconnectCauseDescription(context, telephonyDisconnectCause, phoneId),
- toTelecomDisconnectReason(context,telephonyDisconnectCause, reason, phoneId),
- toTelecomDisconnectCauseTone(telephonyDisconnectCause, phoneId),
+ toTelecomDisconnectReason(context, telephonyDisconnectCause, reason, phoneId),
+ toTelecomDisconnectCauseTone(telephonyDisconnectCause, carrierConfig),
telephonyDisconnectCause,
telephonyPreciseDisconnectCause,
imsReasonInfo);
@@ -119,7 +135,16 @@
* {@link android.telecom.DisconnectCause} disconnect code.
* @return The disconnect code as defined in {@link android.telecom.DisconnectCause}.
*/
- private static int toTelecomDisconnectCauseCode(int telephonyDisconnectCause) {
+ private static int toTelecomDisconnectCauseCode(int telephonyDisconnectCause,
+ PersistableBundle carrierConfig) {
+
+ // special case: some carriers determine what disconnect causes play the BUSY tone.
+ // hence, must adjust the disconnectCause CODE to match the tone.
+ if (doesCarrierClassifyDisconnectCauseAsBusyCause(telephonyDisconnectCause,
+ carrierConfig)) {
+ return DisconnectCause.BUSY;
+ }
+
switch (telephonyDisconnectCause) {
case android.telephony.DisconnectCause.LOCAL:
// The call was still disconnected locally, so this is not an error condition.
@@ -237,8 +262,17 @@
* Returns a label for to the disconnect cause to be shown to the user.
*/
private static CharSequence toTelecomDisconnectCauseLabel(
- Context context, int telephonyDisconnectCause, int telephonyPreciseDisconnectCause) {
+ Context context, int telephonyDisconnectCause, int telephonyPreciseDisconnectCause,
+ PersistableBundle carrierConfig) {
CharSequence label;
+
+ // special case: some carriers determine what disconnect causes play the BUSY tone.
+ // hence, must adjust the disconnectCause LABEL to match the tone.
+ if (doesCarrierClassifyDisconnectCauseAsBusyCause(telephonyDisconnectCause,
+ carrierConfig)) {
+ return context.getResources().getString(R.string.callFailed_userBusy);
+ }
+
if (telephonyPreciseDisconnectCause != CallFailCause.NOT_VALID) {
label = getLabelFromPreciseDisconnectCause(context, telephonyPreciseDisconnectCause,
telephonyDisconnectCause);
@@ -695,6 +729,10 @@
resourceId = R.string.incall_error_emergency_only;
break;
+ case android.telephony.DisconnectCause.ICC_ERROR:
+ resourceId = R.string.callFailed_simError;
+ break;
+
case android.telephony.DisconnectCause.OUT_OF_SERVICE:
// No network connection.
if (ImsUtil.shouldPromoteWfc(context, phoneId)) {
@@ -840,21 +878,15 @@
/**
* Returns the tone to play for the disconnect cause, or UNKNOWN if none should be played.
*/
- private static int toTelecomDisconnectCauseTone(int telephonyDisconnectCause, int phoneId) {
- Phone phone = PhoneFactory.getPhone(phoneId);
- PersistableBundle config;
- if (phone != null) {
- config = PhoneGlobals.getInstance().getCarrierConfigForSubId(phone.getSubId());
- } else {
- config = PhoneGlobals.getInstance().getCarrierConfig();
+ private static int toTelecomDisconnectCauseTone(int telephonyDisconnectCause,
+ PersistableBundle carrierConfig) {
+
+ // special case: some carriers determine what disconnect causes play the BUSY tone.
+ if (doesCarrierClassifyDisconnectCauseAsBusyCause(telephonyDisconnectCause,
+ carrierConfig)) {
+ return ToneGenerator.TONE_SUP_BUSY;
}
- int[] busyToneArray = config.getIntArray(
- CarrierConfigManager.KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY);
- for (int busyTone : busyToneArray) {
- if (busyTone == telephonyDisconnectCause) {
- return ToneGenerator.TONE_SUP_BUSY;
- }
- }
+
switch (telephonyDisconnectCause) {
case android.telephony.DisconnectCause.CONGESTION:
return ToneGenerator.TONE_SUP_CONGESTION;
@@ -886,4 +918,37 @@
return ToneGenerator.TONE_PROP_PROMPT;
}
}
+
+ /**
+ * Helper method that examines the carrierConfig KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY
+ * containing the DisconnectCauses that are classified as DisconnectCause.BUSY
+ * @param telephonyDisconnectCause
+ * @param carrierConfig object that holds all the carrier specific settings
+ * @return whether the cause is in the carrier config busy tone array
+ */
+ private static boolean doesCarrierClassifyDisconnectCauseAsBusyCause(
+ int telephonyDisconnectCause, PersistableBundle carrierConfig) {
+ int[] busyToneArray = carrierConfig.getIntArray(
+ CarrierConfigManager.KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY);
+ for (int busyTone : busyToneArray) {
+ if (busyTone == telephonyDisconnectCause) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static PersistableBundle getCarrierConfigBundle(int phoneId) {
+ Phone phone = PhoneFactory.getPhone(phoneId);
+ PersistableBundle config;
+
+ if (phone != null) {
+ config = PhoneGlobals.getInstance().getCarrierConfigForSubId(phone.getSubId());
+ } else {
+ config = PhoneGlobals.getInstance().getCarrierConfig();
+ }
+
+ return config;
+ }
+
}
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index ed07726..684e03a 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -2016,32 +2016,47 @@
}
@VisibleForTesting
- public PersistableBundle getCarrierConfig() {
+ public @NonNull PersistableBundle getCarrierConfig() {
Phone phone = getPhone();
if (phone == null) {
- return null;
+ Log.w(this,
+ "getCarrierConfig: phone is null. Returning CarrierConfigManager"
+ + ".getDefaultConfig()");
+ return CarrierConfigManager.getDefaultConfig();
}
- return PhoneGlobals.getInstance().getCarrierConfigForSubId(phone.getSubId());
+
+ // potential null returned from .getCarrierConfigForSubId() and method guarantees non-null.
+ // hence, need for try/finally block
+ PersistableBundle pb = null;
+ try {
+ pb = PhoneGlobals.getInstance().getCarrierConfigForSubId(phone.getSubId());
+ } catch (Exception e) {
+ Log.e(this, e,
+ "getCarrierConfig: caught Exception when calling "
+ + "PhoneGlobals.getCarrierConfigForSubId(phone.getSubId()). Returning "
+ + "CarrierConfigManager.getDefaultConfig()");
+ } finally {
+ if (pb == null) {
+ pb = CarrierConfigManager.getDefaultConfig();
+ }
+ }
+ return pb;
+ }
+
+ @VisibleForTesting
+ public boolean isRttMergeSupported(@NonNull PersistableBundle pb) {
+ return pb.getBoolean(CarrierConfigManager.KEY_ALLOW_MERGING_RTT_CALLS_BOOL);
}
private boolean canDeflectImsCalls() {
- PersistableBundle b = getCarrierConfig();
- // Return false if the CarrierConfig is unavailable
- if (b != null) {
- return b.getBoolean(
- CarrierConfigManager.KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL) &&
- isValidRingingCall();
- }
- return false;
+ return getCarrierConfig().getBoolean(
+ CarrierConfigManager.KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL)
+ && isValidRingingCall();
}
private boolean isCallTransferSupported() {
- PersistableBundle b = getCarrierConfig();
- // Return false if the CarrierConfig is unavailable
- if (b != null) {
- return b.getBoolean(CarrierConfigManager.KEY_CARRIER_ALLOW_TRANSFER_IMS_CALL_BOOL);
- }
- return false;
+ return getCarrierConfig().getBoolean(
+ CarrierConfigManager.KEY_CARRIER_ALLOW_TRANSFER_IMS_CALL_BOOL);
}
private boolean canTransfer(TelephonyConnection c) {
@@ -3038,8 +3053,6 @@
if (isIms) {
isVoWifiEnabled = isWfcEnabled(phone);
}
- boolean isRttMergeSupported = getCarrierConfig()
- .getBoolean(CarrierConfigManager.KEY_ALLOW_MERGING_RTT_CALLS_BOOL);
PhoneAccountHandle phoneAccountHandle = isIms ? PhoneUtils
.makePstnPhoneAccountHandle(phone.getDefaultPhone())
: PhoneUtils.makePstnPhoneAccountHandle(phone);
@@ -3077,7 +3090,7 @@
if (mTreatAsEmergencyCall) {
isConferenceSupported = false;
Log.d(this, "refreshConferenceSupported = false; emergency call");
- } else if (isRtt() && !isRttMergeSupported) {
+ } else if (isRtt() && !isRttMergeSupported(getCarrierConfig())) {
isConferenceSupported = false;
Log.d(this, "refreshConferenceSupported = false; rtt call");
} else if (!isConferencingSupported || isIms && !isImsConferencingSupported) {
@@ -3134,12 +3147,9 @@
Phone phone = getPhone();
if (phone != null && (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA)
&& !mOriginalConnection.isIncoming()) {
- PersistableBundle pb = getCarrierConfig();
- if (pb != null) {
- showOrigDialString = pb.getBoolean(CarrierConfigManager
- .KEY_CONFIG_SHOW_ORIG_DIAL_STRING_FOR_CDMA_BOOL);
- Log.d(this, "showOrigDialString: " + showOrigDialString);
- }
+ showOrigDialString = getCarrierConfig().getBoolean(CarrierConfigManager
+ .KEY_CONFIG_SHOW_ORIG_DIAL_STRING_FOR_CDMA_BOOL);
+ Log.d(this, "showOrigDialString: " + showOrigDialString);
}
return showOrigDialString;
}
@@ -3716,8 +3726,7 @@
if (mOriginalConnection.isIncoming()
&& !TextUtils.isEmpty(mOriginalConnection.getAddress())
&& mOriginalConnection.getAddress().startsWith(JAPAN_COUNTRY_CODE_WITH_PLUS_SIGN)) {
- PersistableBundle b = getCarrierConfig();
- return b != null && b.getBoolean(
+ return getCarrierConfig().getBoolean(
CarrierConfigManager.KEY_FORMAT_INCOMING_NUMBER_TO_NATIONAL_FOR_JP_BOOL);
}
return false;
@@ -3742,8 +3751,7 @@
* otherwise.
*/
private boolean supportsD2DUsingRtp() {
- PersistableBundle b = getCarrierConfig();
- return b != null && b.getBoolean(
+ return getCarrierConfig().getBoolean(
CarrierConfigManager.KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL);
}
@@ -3751,8 +3759,7 @@
* @return {@code true} if the carrier supports D2D using DTMF digits, {@code false} otherwise.
*/
private boolean supportsD2DUsingDtmf() {
- PersistableBundle b = getCarrierConfig();
- return b != null && b.getBoolean(
+ return getCarrierConfig().getBoolean(
CarrierConfigManager.KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_DTMF_BOOL);
}
@@ -3761,8 +3768,7 @@
* extensions used in D2D comms, {@code false} otherwise.
*/
private boolean supportsSdpNegotiationOfRtpHeaderExtensions() {
- PersistableBundle b = getCarrierConfig();
- return b != null && b.getBoolean(
+ return getCarrierConfig().getBoolean(
CarrierConfigManager
.KEY_SUPPORTS_SDP_NEGOTIATION_OF_D2D_RTP_HEADER_EXTENSIONS_BOOL);
}
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 071376d..f1c0383 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -181,18 +181,27 @@
*/
private static class SlotStatus {
public int slotId;
+ public int activeSubId;
// RAT capabilities
public int capabilities;
// By default, we will assume that the slots are not locked.
public boolean isLocked = false;
// Is the emergency number associated with the slot
public boolean hasDialedEmergencyNumber = false;
- //SimState
+ //SimState.
public int simState;
- public SlotStatus(int slotId, int capabilities) {
+ //helper to check if sim is really 'present' in the traditional sense.
+ // since eSIM always reports SIM_STATE_READY
+ public boolean isSubActiveAndSimPresent() {
+ return (simState != TelephonyManager.SIM_STATE_ABSENT
+ && activeSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ }
+
+ public SlotStatus(int slotId, int capabilities, int activeSubId) {
this.slotId = slotId;
this.capabilities = capabilities;
+ this.activeSubId = activeSubId;
}
}
@@ -221,6 +230,7 @@
public int getPhoneId(int subId) {
return SubscriptionManager.getPhoneId(subId);
}
+
};
/**
@@ -229,9 +239,9 @@
@VisibleForTesting
public interface TelephonyManagerProxy {
int getPhoneCount();
- boolean hasIccCard(int slotId);
boolean isCurrentEmergencyNumber(String number);
Map<Integer, List<EmergencyNumber>> getCurrentEmergencyNumberList();
+ boolean isConcurrentCallsPossible();
}
private TelephonyManagerProxy mTelephonyManagerProxy;
@@ -250,11 +260,6 @@
}
@Override
- public boolean hasIccCard(int slotId) {
- return mTelephonyManager.hasIccCard(slotId);
- }
-
- @Override
public boolean isCurrentEmergencyNumber(String number) {
try {
return mTelephonyManager.isEmergencyNumber(number);
@@ -271,6 +276,12 @@
return new HashMap<>();
}
}
+
+ @Override
+ public boolean isConcurrentCallsPossible() {
+ // Under DSDA, need to be determined by voice capabilities
+ return mTelephonyManager.getMaxNumberOfSimultaneouslyActiveSims() > 1;
+ }
}
/**
@@ -1636,7 +1647,13 @@
Bundle connExtras = c.getExtras();
Log.i(this, "retryOutgoingOriginalConnection, redialing on Phone Id: " + newPhoneToUse);
c.clearOriginalConnection();
- if (phoneId != newPhoneToUse.getPhoneId()) updatePhoneAccount(c, newPhoneToUse);
+ if (phoneId != newPhoneToUse.getPhoneId()) {
+ if (!mTelephonyManagerProxy.isConcurrentCallsPossible()) {
+ disconnectAllCallsOnOtherSubs(
+ mPhoneUtilsProxy.makePstnPhoneAccountHandle(newPhoneToUse));
+ }
+ updatePhoneAccount(c, newPhoneToUse);
+ }
placeOutgoingConnection(c, newPhoneToUse, videoState, connExtras);
} else {
// We have run out of Phones to use. Disconnect the call and destroy the connection.
@@ -1834,6 +1851,9 @@
case CallStateException.ERROR_OTASP_PROVISIONING_IN_PROCESS:
cause = android.telephony.DisconnectCause.OTASP_PROVISIONING_IN_PROCESS;
break;
+ case CallStateException.ERROR_FDN_BLOCKED:
+ cause = android.telephony.DisconnectCause.FDN_BLOCKED;
+ break;
}
connection.setTelephonyConnectionDisconnected(
DisconnectCauseUtil.toTelecomDisconnectCause(cause, e.getMessage(),
@@ -2161,10 +2181,11 @@
// 5)
// Store the RAF Capabilities for sorting later.
int radioAccessFamily = phone.getRadioAccessFamily();
- SlotStatus status = new SlotStatus(i, radioAccessFamily);
+ SlotStatus status = new SlotStatus(i, radioAccessFamily, phone.getSubId());
phoneSlotStatus.add(status);
Log.i(this, "getFirstPhoneForEmergencyCall, RAF:" +
- Integer.toHexString(radioAccessFamily) + " saved for Phone Id:" + i);
+ Integer.toHexString(radioAccessFamily) + " saved for Phone Id:" + i + " subId:"
+ + phone.getSubId());
// 4)
// Report Slot's PIN/PUK lock status for sorting later.
int simState = mSubscriptionManagerProxy.getSimStateForSlotIdx(i);
@@ -2174,6 +2195,7 @@
simState == TelephonyManager.SIM_STATE_PUK_REQUIRED) {
status.isLocked = true;
}
+
// 3) Store if the Phone has the corresponding emergency number
if (phonesWithEmergencyNumber != null) {
for (Phone phoneWithEmergencyNumber : phonesWithEmergencyNumber) {
@@ -2184,13 +2206,15 @@
}
}
// 6)
- if (firstPhoneWithSim == null && mTelephonyManagerProxy.hasIccCard(i)) {
- // The slot has a SIM card inserted, but is not in service, so keep track of this
- // Phone. Do not return because we want to make sure that none of the other Phones
+ if (firstPhoneWithSim == null &&
+ (phone.getSubId() != SubscriptionManager.INVALID_SIM_SLOT_INDEX)) {
+ // The slot has a SIM card inserted (and an active subscription), but is not in
+ // service, so keep track of this Phone.
+ // Do not return because we want to make sure that none of the other Phones
// are in service (because that is always faster).
firstPhoneWithSim = phone;
- Log.i(this, "getFirstPhoneForEmergencyCall, SIM card inserted, Phone Id:" +
- firstPhoneWithSim.getPhoneId());
+ Log.i(this, "getFirstPhoneForEmergencyCall, SIM with active sub, Phone Id:" +
+ firstPhoneWithSim.getPhoneId());
}
}
// 7)
@@ -2206,18 +2230,19 @@
final int defaultPhoneId = mPhoneFactoryProxy.getDefaultPhone().getPhoneId();
final Phone firstOccupiedSlot = firstPhoneWithSim;
if (!phoneSlotStatus.isEmpty()) {
+ Log.i(this, "getFirstPhoneForEmergencyCall, list size: " + phoneSlotStatus.size()
+ + " defaultPhoneId: " + defaultPhoneId + " firstOccupiedSlot: "
+ + firstOccupiedSlot);
// Only sort if there are enough elements to do so.
if (phoneSlotStatus.size() > 1) {
Collections.sort(phoneSlotStatus, (o1, o2) -> {
- // Sort by non-absent SIM.
- if (o1.simState == TelephonyManager.SIM_STATE_ABSENT
- && o2.simState != TelephonyManager.SIM_STATE_ABSENT) {
- return -1;
- }
- if (o2.simState == TelephonyManager.SIM_STATE_ABSENT
- && o1.simState != TelephonyManager.SIM_STATE_ABSENT) {
+ // Sort by non-absent SIM (SIM without active sub is considered absent).
+ if (o1.isSubActiveAndSimPresent() && !o2.isSubActiveAndSimPresent()) {
return 1;
}
+ if (o2.isSubActiveAndSimPresent() && !o1.isSubActiveAndSimPresent()) {
+ return -1;
+ }
// First start by seeing if either of the phone slots are locked. If they
// are, then sort by non-locked SIM first. If they are both locked, sort
// by capability instead.
@@ -2645,4 +2670,23 @@
}
});
}
+
+ private void disconnectAllCallsOnOtherSubs (@NonNull PhoneAccountHandle handle) {
+ Collection<Connection>connections = getAllConnections();
+ connections.stream()
+ .filter(c ->
+ (c.getState() == Connection.STATE_ACTIVE
+ || c.getState() == Connection.STATE_HOLDING)
+ // Include any calls not on same sub as current connection.
+ && !Objects.equals(c.getPhoneAccountHandle(), handle))
+ .forEach(c -> {
+ if (c instanceof TelephonyConnection) {
+ TelephonyConnection tc = (TelephonyConnection) c;
+ Log.i(LOG_TAG, "disconnectAllCallsOnOtherSubs: disconnect" +
+ " %s due to redial happened on other sub.",
+ tc.getTelecomCallId());
+ tc.hangup(android.telephony.DisconnectCause.LOCAL);
+ }
+ });
+ }
}
diff --git a/src/com/android/services/telephony/rcs/RcsFeatureController.java b/src/com/android/services/telephony/rcs/RcsFeatureController.java
index 0e1cb4b..48c84b1 100644
--- a/src/com/android/services/telephony/rcs/RcsFeatureController.java
+++ b/src/com/android/services/telephony/rcs/RcsFeatureController.java
@@ -19,6 +19,7 @@
import android.annotation.AnyThread;
import android.content.Context;
import android.net.Uri;
+import android.telephony.SubscriptionManager;
import android.telephony.ims.ImsException;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.aidl.IImsCapabilityCallback;
@@ -402,6 +403,17 @@
callback.accept(mImsRcsRegistrationHelper.getImsRegistrationState());
}
+ /**
+ * @return the subscription ID that is currently associated with this RCS feature.
+ */
+ public int getAssociatedSubId() {
+ RcsFeatureManager manager = getFeatureManager();
+ if (manager != null) {
+ return manager.getSubId();
+ }
+ return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ }
+
private void updateCapabilities() {
RcsFeatureManager manager = getFeatureManager();
if (manager != null) {
diff --git a/src/com/android/services/telephony/rcs/TelephonyRcsService.java b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
index dfcea74..13b3a7d 100644
--- a/src/com/android/services/telephony/rcs/TelephonyRcsService.java
+++ b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
@@ -244,6 +244,22 @@
}
/**
+ * Verifies the subId supplied is the active subId for the slotId specified.
+ * If we have not processed a CARRIER_CONFIG_CHANGED indication for this subscription yet,
+ * either the subscription is not active or we have not finished setting up the feature yet.
+ * @param slotId The slotId we are verifying
+ * @param subId The subId we are verifying
+ * @return true if the subId is the active subId we are tracking for the slotId specified.
+ */
+ public boolean verifyActiveSubId(int slotId, int subId) {
+ synchronized (mLock) {
+ int currId = mSlotToAssociatedSubIds.get(slotId,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ return subId == currId;
+ }
+ }
+
+ /**
* ACTION_CARRIER_CONFIG_CHANGED was received by this service for a specific slot.
* @param slotId The slotId associated with the event.
* @param subId The subId associated with the event. May cause the subId associated with the
diff --git a/testapps/TelephonyManagerTestApp/AndroidManifest.xml b/testapps/TelephonyManagerTestApp/AndroidManifest.xml
index 40fc549..6392c26 100644
--- a/testapps/TelephonyManagerTestApp/AndroidManifest.xml
+++ b/testapps/TelephonyManagerTestApp/AndroidManifest.xml
@@ -26,7 +26,6 @@
<uses-permission android:name="android.permission.CALL_PRIVILEGED"/>
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
- android.Manifest.permission.ACCESS_FINE_LOCATION
<application android:label="TelephonyManagerTestApp">
<activity android:name=".TelephonyManagerTestApp"
android:label="TelephonyManagerTestApp"
diff --git a/testapps/TestSliceApp/.idea/.gitignore b/testapps/TestSliceApp/.idea/.gitignore
deleted file mode 100644
index 26d3352..0000000
--- a/testapps/TestSliceApp/.idea/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
diff --git a/testapps/TestSliceApp/.idea/compiler.xml b/testapps/TestSliceApp/.idea/compiler.xml
deleted file mode 100644
index fb7f4a8..0000000
--- a/testapps/TestSliceApp/.idea/compiler.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
- <component name="CompilerConfiguration">
- <bytecodeTargetLevel target="11" />
- </component>
-</project>
\ No newline at end of file
diff --git a/testapps/TestSliceApp/.idea/gradle.xml b/testapps/TestSliceApp/.idea/gradle.xml
deleted file mode 100644
index 526b4c2..0000000
--- a/testapps/TestSliceApp/.idea/gradle.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
- <component name="GradleMigrationSettings" migrationVersion="1" />
- <component name="GradleSettings">
- <option name="linkedExternalProjectsSettings">
- <GradleProjectSettings>
- <option name="testRunner" value="GRADLE" />
- <option name="distributionType" value="DEFAULT_WRAPPED" />
- <option name="externalProjectPath" value="$PROJECT_DIR$" />
- <option name="modules">
- <set>
- <option value="$PROJECT_DIR$" />
- <option value="$PROJECT_DIR$/app" />
- </set>
- </option>
- <option name="resolveModulePerSourceSet" value="false" />
- </GradleProjectSettings>
- </option>
- </component>
-</project>
\ No newline at end of file
diff --git a/testapps/TestSliceApp/.idea/misc.xml b/testapps/TestSliceApp/.idea/misc.xml
deleted file mode 100644
index a329266..0000000
--- a/testapps/TestSliceApp/.idea/misc.xml
+++ /dev/null
@@ -1,76 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
- <component name="DesignSurface">
- <option name="filePathToZoomLevelMap">
- <map>
- <entry key="app/src/main/res/drawable/ic_launcher_background.xml" value="0.38177083333333334" />
- <entry key="app/src/main/res/layout/_copy.xml" value="0.365625" />
- <entry key="app/src/main/res/layout/activity_main.xml" value="0.4891304347826087" />
- <entry key="app/src/main/res/layout/copy.xml" value="0.37135416666666665" />
- <entry key="app/src/main/res/layout/fragment_c_b_s.xml" value="0.473731884057971" />
- <entry key="app/src/main/res/layout/fragment_c_b_s_copy.xml" value="0.365625" />
- <entry key="app/src/main/res/layout/fragment_main.xml" value="0.46693840579710144" />
- <entry key="app/src/main/res/layout/fragment_prioritize_bandwidth.xml" value="0.473731884057971" />
- <entry key="app/src/main/res/layout/fragment_prioritize_bandwidth2.xml" value="0.365625" />
- <entry key="app/src/main/res/layout/fragment_prioritize_latency.xml" value="0.473731884057971" />
- <entry key="app/src/main/res/layout/fragment_prioritize_latency2.xml" value="0.365625" />
- </map>
- </option>
- </component>
- <component name="NullableNotNullManager">
- <option name="myDefaultNullable" value="androidx.annotation.Nullable" />
- <option name="myDefaultNotNull" value="androidx.annotation.NonNull" />
- <option name="myNullables">
- <value>
- <list size="17">
- <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
- <item index="1" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
- <item index="2" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
- <item index="3" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
- <item index="4" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
- <item index="5" class="java.lang.String" itemvalue="com.android.annotations.Nullable" />
- <item index="6" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
- <item index="7" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
- <item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
- <item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
- <item index="10" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
- <item index="11" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.Nullable" />
- <item index="12" class="java.lang.String" itemvalue="io.reactivex.annotations.Nullable" />
- <item index="13" class="java.lang.String" itemvalue="io.reactivex.rxjava3.annotations.Nullable" />
- <item index="14" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
- <item index="15" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
- <item index="16" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
- </list>
- </value>
- </option>
- <option name="myNotNulls">
- <value>
- <list size="17">
- <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
- <item index="1" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
- <item index="2" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
- <item index="3" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
- <item index="4" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
- <item index="5" class="java.lang.String" itemvalue="com.android.annotations.NonNull" />
- <item index="6" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
- <item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
- <item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
- <item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
- <item index="10" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.NonNull" />
- <item index="11" class="java.lang.String" itemvalue="io.reactivex.annotations.NonNull" />
- <item index="12" class="java.lang.String" itemvalue="io.reactivex.rxjava3.annotations.NonNull" />
- <item index="13" class="java.lang.String" itemvalue="lombok.NonNull" />
- <item index="14" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
- <item index="15" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
- <item index="16" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
- </list>
- </value>
- </option>
- </component>
- <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="JDK" project-jdk-type="JavaSDK">
- <output url="file://$PROJECT_DIR$/build/classes" />
- </component>
- <component name="ProjectType">
- <option name="id" value="Android" />
- </component>
-</project>
\ No newline at end of file
diff --git a/testapps/TestSliceApp/.idea/vcs.xml b/testapps/TestSliceApp/.idea/vcs.xml
deleted file mode 100644
index 498ba99..0000000
--- a/testapps/TestSliceApp/.idea/vcs.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
- <component name="IssueNavigationConfiguration">
- <option name="links">
- <list>
- <IssueNavigationLink>
- <option name="issueRegexp" value="\bb/(\d+)(#\w+)?\b" />
- <option name="linkRegexp" value="https://buganizer.corp.google.com/issues/$1$2" />
- </IssueNavigationLink>
- <IssueNavigationLink>
- <option name="issueRegexp" value="\b(?:BUG=|FIXED=)(\d+)\b" />
- <option name="linkRegexp" value="https://buganizer.corp.google.com/issues/$1" />
- </IssueNavigationLink>
- <IssueNavigationLink>
- <option name="issueRegexp" value="\b(?:cl/|cr/|OCL=|DIFFBASE=|ROLLBACK_OF=)(\d+)\b" />
- <option name="linkRegexp" value="https://critique.corp.google.com/$1" />
- </IssueNavigationLink>
- <IssueNavigationLink>
- <option name="issueRegexp" value="\bomg/(\d+)\b" />
- <option name="linkRegexp" value="https://omg.corp.google.com/$1" />
- </IssueNavigationLink>
- <IssueNavigationLink>
- <option name="issueRegexp" value="\b(?:go/|goto/)([^,.<>()"\s]+(?:[.,][^,.<>()"\s]+)*)" />
- <option name="linkRegexp" value="https://goto.google.com/$1" />
- </IssueNavigationLink>
- <IssueNavigationLink>
- <option name="issueRegexp" value="\bcs/([^\s]+[\w$])" />
- <option name="linkRegexp" value="https://cs.corp.google.com/search/?q=$1" />
- </IssueNavigationLink>
- <IssueNavigationLink>
- <option name="issueRegexp" value="(LINT\.IfChange)|(LINT\.ThenChange)" />
- <option name="linkRegexp" value="https://goto.google.com/ifthisthenthatlint" />
- </IssueNavigationLink>
- </list>
- </option>
- </component>
- <component name="VcsDirectoryMappings">
- <mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
- </component>
-</project>
\ No newline at end of file
diff --git a/testapps/TestSliceApp/app/src/main/AndroidManifest.xml b/testapps/TestSliceApp/app/src/main/AndroidManifest.xml
index d28bbb0..a34c254 100644
--- a/testapps/TestSliceApp/app/src/main/AndroidManifest.xml
+++ b/testapps/TestSliceApp/app/src/main/AndroidManifest.xml
@@ -3,6 +3,8 @@
package="com.google.android.sample.testsliceapp">
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+ <uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
@@ -10,7 +12,8 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat"
- android:versionCode="34">
+ android:versionCode="34"
+ android:usesCleartextTraffic="true">
<activity
android:name=".MainActivity"
android:exported="true">
@@ -29,4 +32,4 @@
android:value="true" />
</service>
</application>
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/CBS.java b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/CBS.java
index a555ce6..c85f830 100644
--- a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/CBS.java
+++ b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/CBS.java
@@ -20,7 +20,10 @@
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
+import android.net.TelephonyNetworkSpecifier;
import android.os.Bundle;
+import android.telephony.SubscriptionManager;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@@ -62,6 +65,7 @@
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mConnectivityManager = getContext().getSystemService(ConnectivityManager.class);
}
@Override
@@ -80,23 +84,33 @@
mRelease.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
- mConnectivityManager.unregisterNetworkCallback(
+ try {
+ mConnectivityManager.unregisterNetworkCallback(
mProfileCheckNetworkCallback);
+ } catch (Exception e) {
+ Log.d("SliceTest", "Exception: " + e);
+ }
}
});
mRequest = view.findViewById(R.id.requestcbs);
mRequest.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
- NetworkCallback mProfileCheckNetworkCallback = new NetworkCallback() {
+ mProfileCheckNetworkCallback = new NetworkCallback() {
@Override
public void onAvailable(final Network network) {
mNetwork = network;
+ Log.d("CBS", "onAvailable + " + network);
}
};
NetworkRequest.Builder builder = new NetworkRequest.Builder();
builder.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS);
+ builder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+ int subId = SubscriptionManager.getDefaultDataSubscriptionId();
+ builder.setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
+ .setSubscriptionId(subId).build());
mConnectivityManager.requestNetwork(builder.build(), mProfileCheckNetworkCallback);
+ Log.d("CBS", "onClick + " + builder.build());
}
});
mPing = view.findViewById(R.id.pingcbs);
@@ -106,8 +120,9 @@
if (mNetwork != null) {
//mNetwork.
try {
- new RequestTask().ping(mNetwork);
+ new RequestTask().execute(mNetwork);
} catch (Exception e) {
+ Log.d("SliceTest", "Exception: " + e);
}
}
}
diff --git a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeBandwidth.java b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeBandwidth.java
index d997178..6812ddc 100644
--- a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeBandwidth.java
+++ b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeBandwidth.java
@@ -21,6 +21,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.os.Bundle;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@@ -73,6 +74,7 @@
new NetworkCallback() {
@Override
public void onAvailable(final Network network) {
+ Log.d("SliceTest", "onAvailable: " + network);
mNetwork = network;
}
};
@@ -80,23 +82,30 @@
mRelease.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
- mConnectivityManager.unregisterNetworkCallback(mProfileCheckNetworkCallback);
+ try {
+ mConnectivityManager.unregisterNetworkCallback(
+ mProfileCheckNetworkCallback);
+ } catch (Exception e) {
+ Log.d("SliceTest", "Exception: " + e);
+ }
}
});
mRequest = view.findViewById(R.id.requestbw);
mRequest.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
- NetworkCallback mProfileCheckNetworkCallback =
+ mProfileCheckNetworkCallback =
new NetworkCallback() {
@Override
public void onAvailable(final Network network) {
+ Log.d("PrioritizeBandwidth", "onAvailable + " + network);
mNetwork = network;
}
};
NetworkRequest.Builder builder = new NetworkRequest.Builder();
builder.addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH);
mConnectivityManager.requestNetwork(builder.build(), mProfileCheckNetworkCallback);
+ Log.d("PrioritizeBandwidth", "onClick + " + builder.build());
}
});
mPing = view.findViewById(R.id.pingbw);
@@ -104,10 +113,10 @@
@Override
public void onClick(View view) {
if (mNetwork != null) {
- //mNetwork.
try {
- new RequestTask().ping(mNetwork);
+ new RequestTask().execute(mNetwork);
} catch (Exception e) {
+ Log.d("SliceTest", "Exception: " + e);
}
}
}
diff --git a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java
index b45362c..45ea666 100644
--- a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java
+++ b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java
@@ -21,6 +21,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.os.Bundle;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@@ -61,6 +62,7 @@
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mConnectivityManager = getContext().getSystemService(ConnectivityManager.class);
}
@Override
@@ -79,22 +81,29 @@
mRelease.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
- mConnectivityManager.unregisterNetworkCallback(mProfileCheckNetworkCallback);
+ try {
+ mConnectivityManager.unregisterNetworkCallback(
+ mProfileCheckNetworkCallback);
+ } catch (Exception e) {
+ Log.d("SliceTest", "Exception: " + e);
+ }
}
});
mRequest = view.findViewById(R.id.requestlatency);
mRequest.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
- NetworkCallback mProfileCheckNetworkCallback = new NetworkCallback() {
+ mProfileCheckNetworkCallback = new NetworkCallback() {
@Override
public void onAvailable(final Network network) {
+ Log.d("PrioritizeLatency", "onAvailable + " + network);
mNetwork = network;
}
};
NetworkRequest.Builder builder = new NetworkRequest.Builder();
builder.addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY);
mConnectivityManager.requestNetwork(builder.build(), mProfileCheckNetworkCallback);
+ Log.d("PrioritizeLatency", "onClick + " + builder.build());
}
});
mPing = view.findViewById(R.id.pinglatency);
@@ -106,6 +115,7 @@
try {
new RequestTask().ping(mNetwork);
} catch (Exception e) {
+ Log.d("SliceTest", "Exception: " + e);
}
}
}
diff --git a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/RequestTask.java b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/RequestTask.java
index b12939e..3849860 100644
--- a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/RequestTask.java
+++ b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/RequestTask.java
@@ -16,6 +16,8 @@
package com.google.android.sample.testsliceapp;
import android.net.Network;
+import android.os.AsyncTask;
+import android.util.Log;
import java.io.BufferedInputStream;
import java.io.IOException;
@@ -23,7 +25,11 @@
import java.net.HttpURLConnection;
import java.net.URL;
-class RequestTask{
+class RequestTask extends AsyncTask<Network, Integer, Integer> {
+ protected Integer doInBackground(Network... network) {
+ ping(network[0]);
+ return 0;
+ }
String ping(Network network) {
URL url = null;
try {
@@ -32,8 +38,12 @@
}
if (url != null) {
try {
- return httpGet(network, url);
+ Log.d("SliceTest", "ping " + url);
+ String result = httpGet(network, url);
+ Log.d("SliceTest", "result " + result);
+ return result;
} catch (Exception e) {
+ Log.d("SliceTest", "exception: " + e);
}
}
return "";
@@ -47,6 +57,7 @@
HttpURLConnection connection = (HttpURLConnection) network.openConnection(httpUrl);
try {
InputStream inputStream = connection.getInputStream();
+ Log.d("httpGet", "httpUrl + " + httpUrl);
return new BufferedInputStream(inputStream).toString();
} finally {
connection.disconnect();
diff --git a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/TestCarrierService.java b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/TestCarrierService.java
index b1d019e..daa1d17 100644
--- a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/TestCarrierService.java
+++ b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/TestCarrierService.java
@@ -21,6 +21,7 @@
import android.service.carrier.CarrierService;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
+import android.util.Log;
/**
* Carrier Service that sets the carrier config upon being bound by the system. Requires UICC
@@ -32,11 +33,13 @@
CarrierConfigManager cfgMgr =
(CarrierConfigManager) getSystemService(Context.CARRIER_CONFIG_SERVICE);
cfgMgr.notifyConfigChangedForSubId(SubscriptionManager.getDefaultSubscriptionId());
+ Log.d("TestCarrierService", "onCreate + ");
}
@Override
public PersistableBundle onLoadConfig(CarrierIdentifier carrierIdentifier) {
PersistableBundle config = new PersistableBundle();
+ Log.d("TestCarrierService", "onLoadConfig + ");
return config;
}
}
diff --git a/testapps/TestSliceApp/app/src/main/res/layout/fragment_c_b_s.xml b/testapps/TestSliceApp/app/src/main/res/layout/fragment_c_b_s.xml
index ac2ef9d..5305b53 100644
--- a/testapps/TestSliceApp/app/src/main/res/layout/fragment_c_b_s.xml
+++ b/testapps/TestSliceApp/app/src/main/res/layout/fragment_c_b_s.xml
@@ -8,9 +8,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/frameLayoutCBS">
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
+<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/frameLayout3"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -26,23 +24,26 @@
android:id="@+id/requestcbs"
android:layout_width="186dp"
android:layout_height="57dp"
+ android:layout_marginTop="164dp"
android:text="Request Network"
- tools:layout_editor_absoluteX="120dp"
- tools:layout_editor_absoluteY="154dp" />
+ app:layout_constraintTop_toTopOf="parent"
+ tools:layout_editor_absoluteX="112dp" />
<Button
android:id="@+id/releasecbs"
android:layout_width="187dp"
android:layout_height="61dp"
+ android:layout_marginTop="124dp"
android:text="Release Network"
- tools:layout_editor_absoluteX="119dp"
- tools:layout_editor_absoluteY="273dp" />
+ app:layout_constraintTop_toBottomOf="@+id/requestcbs"
+ tools:layout_editor_absoluteX="119dp" />
<Button
android:id="@+id/pingcbs"
android:layout_width="186dp"
android:layout_height="55dp"
android:text="Ping"
- tools:layout_editor_absoluteX="120dp"
- tools:layout_editor_absoluteY="379dp" />
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/releasecbs"
+ tools:layout_editor_absoluteX="120dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
</RelativeLayout>
\ No newline at end of file
diff --git a/testapps/TestSliceApp/app/src/main/res/layout/fragment_prioritize_latency.xml b/testapps/TestSliceApp/app/src/main/res/layout/fragment_prioritize_latency.xml
index 9527d69..b040995 100644
--- a/testapps/TestSliceApp/app/src/main/res/layout/fragment_prioritize_latency.xml
+++ b/testapps/TestSliceApp/app/src/main/res/layout/fragment_prioritize_latency.xml
@@ -8,51 +8,52 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/frameLayoutLatency">
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/frameLayout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".PrioritizeLatency" >
- <Button
- android:id="@+id/requestlatency"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="RequestNetwork"
- app:layout_constraintBottom_toTopOf="@+id/button6"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_bias="0.461"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintVertical_bias="0.717" />
- <Button
- android:id="@+id/releaselatency"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="76dp"
- android:text="Release Network"
- app:layout_constraintBottom_toTopOf="@+id/button7"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_bias="0.478"
- app:layout_constraintStart_toStartOf="parent" />
- <Button
- android:id="@+id/pinglatency"
- android:layout_width="182dp"
- android:layout_height="42dp"
- android:layout_marginBottom="308dp"
- android:text="Ping"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_bias="0.471"
- app:layout_constraintStart_toStartOf="parent" />
- <TextView
- android:id="@+id/textView"
- android:layout_width="371dp"
- android:layout_height="52dp"
- android:text="Prioritize Latency"
- tools:layout_editor_absoluteX="21dp"
- tools:layout_editor_absoluteY="1dp" />
-</androidx.constraintlayout.widget.ConstraintLayout>
- </FrameLayout>
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/frameLayout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".PrioritizeLatency">
+ <Button
+ android:id="@+id/requestlatency"
+ android:layout_width="183dp"
+ android:layout_height="50dp"
+ android:layout_marginTop="176dp"
+ android:text="RequestNetwork"
+ app:layout_constraintBottom_toTopOf="@+id/button6"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.495"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintVertical_bias="0.717" />
+ <Button
+ android:id="@+id/releaselatency"
+ android:layout_width="183dp"
+ android:layout_height="50dp"
+ android:layout_marginTop="84dp"
+ android:text="ReleaseNetwork"
+ app:layout_constraintBottom_toTopOf="@+id/button6"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/requestlatency"
+ app:layout_constraintVertical_bias="0.717" />
+ <Button
+ android:id="@+id/pinglatency"
+ android:layout_width="182dp"
+ android:layout_height="42dp"
+ android:layout_marginBottom="92dp"
+ android:text="Ping"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.493"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/releaselatency" />
+ <TextView
+ android:id="@+id/textView"
+ android:layout_width="371dp"
+ android:layout_height="52dp"
+ android:text="Prioritize Latency"
+ tools:layout_editor_absoluteX="16dp"
+ tools:layout_editor_absoluteY="16dp" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
+ </FrameLayout>
</RelativeLayout>
\ No newline at end of file
diff --git a/tests/src/com/android/phone/ImsStateCallbackControllerTest.java b/tests/src/com/android/phone/ImsStateCallbackControllerTest.java
index cb4321c..60374bc 100644
--- a/tests/src/com/android/phone/ImsStateCallbackControllerTest.java
+++ b/tests/src/com/android/phone/ImsStateCallbackControllerTest.java
@@ -28,6 +28,8 @@
import static com.android.ims.FeatureConnector.UNAVAILABLE_REASON_NOT_READY;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Matchers.any;
@@ -874,6 +876,36 @@
assertFalse(mImsStateCallbackController.isRegistered(mCallback1));
}
+ @Test
+ @SmallTest
+ public void testImsManagerInstance() throws Exception {
+ createController(1);
+
+ // MmTelConnection not ready
+ // check ImsManager instance
+ ImsManager imsManager = mImsStateCallbackController.getImsManager(SLOT_0_SUB_ID);
+ assertNull(imsManager);
+
+ // MmTelConnection ready
+ mMmTelConnectorListenerSlot0.getValue()
+ .connectionReady(mMmTelFeatureManager, SLOT_0_SUB_ID);
+ processAllMessages();
+
+ // check ImsManager instance
+ imsManager = mImsStateCallbackController.getImsManager(SLOT_0_SUB_ID);
+ assertNotNull(imsManager);
+
+ // MmTelConnection unavailable
+ mMmTelConnectorListenerSlot0.getValue()
+ .connectionUnavailable(UNAVAILABLE_REASON_NOT_READY);
+ processAllMessages();
+
+ // MmTelConnection unavailable
+ // check ImsManager instance
+ imsManager = mImsStateCallbackController.getImsManager(SLOT_0_SUB_ID);
+ assertNull(imsManager);
+ }
+
private void createController(int slotCount) throws Exception {
if (Looper.myLooper() == null) {
Looper.prepare();
diff --git a/tests/src/com/android/phone/NotificationMgrTest.java b/tests/src/com/android/phone/NotificationMgrTest.java
new file mode 100644
index 0000000..a6ee276
--- /dev/null
+++ b/tests/src/com/android/phone/NotificationMgrTest.java
@@ -0,0 +1,661 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import static android.telephony.RadioAccessFamily.RAF_1xRTT;
+import static android.telephony.RadioAccessFamily.RAF_EDGE;
+import static android.telephony.RadioAccessFamily.RAF_EHRPD;
+import static android.telephony.RadioAccessFamily.RAF_EVDO_0;
+import static android.telephony.RadioAccessFamily.RAF_EVDO_A;
+import static android.telephony.RadioAccessFamily.RAF_EVDO_B;
+import static android.telephony.RadioAccessFamily.RAF_GPRS;
+import static android.telephony.RadioAccessFamily.RAF_GSM;
+import static android.telephony.RadioAccessFamily.RAF_HSDPA;
+import static android.telephony.RadioAccessFamily.RAF_HSPA;
+import static android.telephony.RadioAccessFamily.RAF_HSPAP;
+import static android.telephony.RadioAccessFamily.RAF_HSUPA;
+import static android.telephony.RadioAccessFamily.RAF_IS95A;
+import static android.telephony.RadioAccessFamily.RAF_IS95B;
+import static android.telephony.RadioAccessFamily.RAF_LTE;
+import static android.telephony.RadioAccessFamily.RAF_LTE_CA;
+import static android.telephony.RadioAccessFamily.RAF_TD_SCDMA;
+import static android.telephony.RadioAccessFamily.RAF_UMTS;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+import static com.android.phone.NotificationMgr.DATA_ROAMING_NOTIFICATION;
+import static com.android.phone.NotificationMgr.LIMITED_SIM_FUNCTION_NOTIFICATION;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.StatusBarManager;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.res.Resources;
+import android.os.Build;
+import android.os.PersistableBundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.telecom.TelecomManager;
+import android.telephony.CarrierConfigManager;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.util.NotificationChannelController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.lang.reflect.Field;
+
+/**
+ * Unit Test for NotificationMgr
+ */
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class NotificationMgrTest {
+
+ private static final int TEST_SUB_ID = 1;
+ private static final long SERIAL_NUMBER_OF_USER = 1234567L;
+ private static final String TEST_LABEL_CF = "test_call_forwarding";
+ private static final String TEST_SUB_INFO_DISPLAY_NAME = "display_name";
+ private static final String TEST_PACKAGE_NAME = "com.android.phone";
+ private static final String TEST_SELECTED_NETWORK_OPERATOR_NAME = "TheOperator";
+ private static final String MOBILE_NETWORK_SELECTION_PACKAGE = "com.android.phone";
+ private static final String MOBILE_NETWORK_SELECTION_CLASS = ".testClass";
+ private static final String CARRIER_NAME = "CoolCarrier";
+
+ @Mock PhoneGlobals mApp;
+ @Mock StatusBarManager mStatusBarManager;
+ @Mock UserManager mUserManager;
+ @Mock SubscriptionManager mSubscriptionManager;
+ @Mock TelecomManager mTelecomManager;
+ @Mock TelephonyManager mTelephonyManager;
+ @Mock Phone mPhone;
+ @Mock SharedPreferences mSharedPreferences;
+ @Mock NotificationManager mNotificationManager;
+ @Mock SubscriptionInfo mSubscriptionInfo;
+ @Mock Resources mResources;
+ @Mock ServiceState mServiceState;
+ @Mock CarrierConfigManager mCarrierConfigManager;
+
+ private Phone[] mPhones;
+ private NotificationMgr mNotificationMgr;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mPhones = new Phone[]{mPhone};
+ replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
+ when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM);
+ when(mApp.getSharedPreferences(anyString(), anyInt())).thenReturn(mSharedPreferences);
+
+ when(mApp.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
+ when(mApp.getSystemService(Context.STATUS_BAR_SERVICE)).thenReturn(mStatusBarManager);
+ when(mApp.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+ when(mApp.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)).thenReturn(
+ mSubscriptionManager);
+ when(mApp.getSystemServiceName(TelecomManager.class)).thenReturn(Context.TELECOM_SERVICE);
+ when(mApp.getSystemService(TelecomManager.class)).thenReturn(mTelecomManager);
+ when(mApp.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
+ when(mApp.getSystemServiceName(CarrierConfigManager.class)).thenReturn(
+ Context.CARRIER_CONFIG_SERVICE);
+ when(mApp.getSystemService(CarrierConfigManager.class)).thenReturn(mCarrierConfigManager);
+ when(mApp.getSystemServiceName(CarrierConfigManager.class)).thenReturn(
+ Context.CARRIER_CONFIG_SERVICE);
+ when(mApp.getSystemService(CarrierConfigManager.class)).thenReturn(mCarrierConfigManager);
+
+ when(mApp.createPackageContextAsUser(any(), eq(0), any())).thenReturn(mApp);
+ when(mApp.getSystemService(Context.NOTIFICATION_SERVICE)).thenReturn(mNotificationManager);
+ when(mUserManager.getSerialNumbersOfUsers(true)).thenReturn(
+ new long[]{SERIAL_NUMBER_OF_USER});
+ when(mUserManager.getUserForSerialNumber(eq(SERIAL_NUMBER_OF_USER))).thenReturn(
+ UserHandle.SYSTEM);
+ when(mApp.getResources()).thenReturn(mResources);
+ when(mResources.getString(R.string.labelCF)).thenReturn(TEST_LABEL_CF);
+ ApplicationInfo appWithSdkS = buildApplicationInfo(Build.VERSION_CODES.S);
+ when(mApp.getApplicationInfo()).thenReturn(appWithSdkS);
+ when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
+ when(mTelephonyManager.getServiceState()).thenReturn(mServiceState);
+
+ mNotificationMgr = new NotificationMgr(mApp);
+ }
+
+ @Test
+ public void testUpdateCfi_visible_noActiveSubscription_notificationNeverSent()
+ throws Exception {
+ // Given no active subscription available
+ when(mSubscriptionManager.getActiveSubscriptionInfo(eq(TEST_SUB_ID))).thenReturn(null);
+
+ // When updateCfi method is called
+ mNotificationMgr.updateCfi(TEST_SUB_ID, /*visible=*/true, /*isFresh=*/false);
+
+ // Then the notification should never be sent
+ verify(mNotificationManager, never()).notify(any(), anyInt(), any());
+ }
+
+ @Test
+ public void testUpdateCfi_visible_hasActiveSub_singleSIM_notificationSent() throws Exception {
+ when(mTelephonyManager.getPhoneCount()).thenReturn(1);
+ when(mSubscriptionManager.getActiveSubscriptionInfo(eq(TEST_SUB_ID))).thenReturn(
+ mSubscriptionInfo);
+
+ mNotificationMgr.updateCfi(TEST_SUB_ID, /*visible=*/true, /*isFresh=*/false);
+
+ verifyNotificationSentWithChannelId(NotificationChannelController.CHANNEL_ID_CALL_FORWARD);
+ }
+
+ @Test
+ public void testUpdateCfi_visible_hasActiveSub_multiSIM_notificationSentWithoutDisplayName()
+ throws Exception {
+ when(mTelephonyManager.getPhoneCount()).thenReturn(2);
+ when(mSubscriptionManager.getActiveSubscriptionInfo(eq(TEST_SUB_ID))).thenReturn(
+ mSubscriptionInfo);
+ when(mSubscriptionInfo.getDisplayName()).thenReturn(null);
+
+ mNotificationMgr.updateCfi(TEST_SUB_ID, /*visible=*/true, /*isFresh=*/false);
+
+ verifyNotificationSentWithChannelId(NotificationChannelController.CHANNEL_ID_CALL_FORWARD);
+ }
+
+ @Test
+ public void testUpdateCfi_visible_hasActiveSub_multiSIM_notificationSentWithDisplayName()
+ throws Exception {
+ when(mTelephonyManager.getPhoneCount()).thenReturn(2);
+ when(mSubscriptionManager.getActiveSubscriptionInfo(eq(TEST_SUB_ID))).thenReturn(
+ mSubscriptionInfo);
+ when(mSubscriptionInfo.getDisplayName()).thenReturn(TEST_SUB_INFO_DISPLAY_NAME);
+
+ mNotificationMgr.updateCfi(TEST_SUB_ID, /*visible=*/true, /*isFresh=*/false);
+
+ verifyNotificationSentWithChannelId(NotificationChannelController.CHANNEL_ID_CALL_FORWARD);
+ }
+
+ @Test
+ public void testUpdateCfi_invisible_hasUnmanagedProfile_notificationCanceled()
+ throws Exception {
+ when(mUserManager.isManagedProfile(anyInt())).thenReturn(false);
+
+ mNotificationMgr.updateCfi(TEST_SUB_ID, /*visible=*/false, /*isFresh=*/false);
+
+ verify(mNotificationManager).cancel(any(), anyInt());
+ }
+
+ @Test
+ public void testUpdateCfi_invisible_allProfilesAreManaged_notificationNeverCanceled()
+ throws Exception {
+ when(mUserManager.isManagedProfile(anyInt())).thenReturn(true);
+
+ mNotificationMgr.updateCfi(TEST_SUB_ID, /*visible=*/false, /*isFresh=*/false);
+
+ verify(mNotificationManager, never()).cancel(any(), anyInt());
+ }
+
+ @Test
+ public void testShowDataRoamingNotification_roamingOn() throws Exception {
+ mNotificationMgr.showDataRoamingNotification(TEST_SUB_ID, /*roamingOn=*/true);
+
+ verifyNotificationSentWithChannelId(
+ NotificationChannelController.CHANNEL_ID_MOBILE_DATA_STATUS);
+ }
+
+ @Test
+ public void testShowDataRoamingNotification_roamingOff() throws Exception {
+ mNotificationMgr.showDataRoamingNotification(TEST_SUB_ID, /*roamingOn=*/false);
+
+ verifyNotificationSentWithChannelId(
+ NotificationChannelController.CHANNEL_ID_MOBILE_DATA_STATUS);
+ }
+
+ @Test
+ public void testHideDataRoamingNotification() {
+ mNotificationMgr.hideDataRoamingNotification();
+
+ verify(mNotificationManager).cancel(any(), eq(DATA_ROAMING_NOTIFICATION));
+ }
+
+ @Test
+ public void testUpdateNetworkSelection_justOutOfService_notificationNeverSent()
+ throws Exception {
+ prepareResourcesForNetworkSelection();
+
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ignored) {
+ }
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+
+ verify(mNotificationManager, never()).notify(any(), anyInt(), any());
+ }
+
+ @Test
+ public void testUpdateNetworkSelection_oosEnoughTime_selectionVisibleToUser_notificationSent()
+ throws Exception {
+ prepareResourcesForNetworkSelection();
+ when(mTelephonyManager.isManualNetworkSelectionAllowed()).thenReturn(true);
+ PersistableBundle config = new PersistableBundle();
+ config.putBoolean(CarrierConfigManager.KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
+ config.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, false);
+ config.putBoolean(CarrierConfigManager.KEY_CSP_ENABLED_BOOL, false);
+ config.putBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL, true);
+ when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
+
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+ // TODO: use effective TestLooper time eclipse instead of sleeping
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException ignored) {
+ }
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+
+ verifyNotificationSentWithChannelId(NotificationChannelController.CHANNEL_ID_ALERT);
+ }
+
+ @Test
+ public void testUpdateNetworkSelection_invalidSubscription_notificationNotSent()
+ throws Exception {
+ prepareResourcesForNetworkSelection();
+ when(mTelephonyManager.isManualNetworkSelectionAllowed()).thenReturn(true);
+ PersistableBundle config = new PersistableBundle();
+ config.putBoolean(CarrierConfigManager.KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
+ config.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, false);
+ config.putBoolean(CarrierConfigManager.KEY_CSP_ENABLED_BOOL, false);
+ config.putBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL, true);
+ when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
+
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE,
+ INVALID_SUBSCRIPTION_ID);
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException ignored) {
+ }
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE,
+ INVALID_SUBSCRIPTION_ID);
+
+ verify(mNotificationManager, never()).notify(any(), anyInt(), any());
+ }
+
+ @Test
+ public void testUpdateNetworkSelection_nullCarrierConfig_notificationNotSent()
+ throws Exception {
+ prepareResourcesForNetworkSelection();
+
+ when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(null);
+
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException ignored) {
+ }
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+
+ verify(mNotificationManager, never()).notify(any(), anyInt(), any());
+ }
+
+ @Test
+ public void testUpdateNetworkSelection_userNotAllowedToChooseOperator_notificationNotSent()
+ throws Exception {
+ prepareResourcesForNetworkSelection();
+
+ PersistableBundle config = new PersistableBundle();
+ // User is NOT allowed to choose operator
+ config.putBoolean(CarrierConfigManager.KEY_OPERATOR_SELECTION_EXPAND_BOOL, false);
+ config.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, false);
+ config.putBoolean(CarrierConfigManager.KEY_CSP_ENABLED_BOOL, false);
+ when(mTelephonyManager.isManualNetworkSelectionAllowed()).thenReturn(false);
+ config.putBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL, true);
+ when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
+
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException ignored) {
+ }
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+
+ verify(mNotificationManager, never()).notify(any(), anyInt(), any());
+ }
+
+ @Test
+ public void testUpdateNetworkSelection_OverrideHideCarrierNetworkSelection_notificationNotSent()
+ throws Exception {
+ prepareResourcesForNetworkSelection();
+
+ PersistableBundle config = new PersistableBundle();
+ // Hide network selection menu
+ config.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, true);
+ config.putBoolean(CarrierConfigManager.KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
+ config.putBoolean(CarrierConfigManager.KEY_CSP_ENABLED_BOOL, false);
+ when(mTelephonyManager.isManualNetworkSelectionAllowed()).thenReturn(false);
+ config.putBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL, true);
+ when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
+
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException ignored) {
+ }
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+
+ verify(mNotificationManager, never()).notify(any(), anyInt(), any());
+ }
+
+ @Test
+ public void testUpdateNetworkSelection_simPreventManualSelection_notificationNotSent()
+ throws Exception {
+ prepareResourcesForNetworkSelection();
+
+ PersistableBundle config = new PersistableBundle();
+ config.putBoolean(CarrierConfigManager.KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
+ config.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, false);
+ // SIM card can prevent manual network selection which is forbidden
+ config.putBoolean(CarrierConfigManager.KEY_CSP_ENABLED_BOOL, true);
+ when(mTelephonyManager.isManualNetworkSelectionAllowed()).thenReturn(false);
+ config.putBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL, true);
+ when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
+
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException ignored) {
+ }
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+
+ verify(mNotificationManager, never()).notify(any(), anyInt(), any());
+ }
+
+ @Test
+ public void testUpdateNetworkSelection_worldMode_userSetLTE_notificationNotSent()
+ throws Exception {
+ prepareResourcesForNetworkSelection();
+
+ PersistableBundle config = new PersistableBundle();
+ config.putBoolean(CarrierConfigManager.KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
+ config.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, false);
+ config.putBoolean(CarrierConfigManager.KEY_CSP_ENABLED_BOOL, false);
+ config.putBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL, true);
+
+ // World mode is on
+ config.putBoolean(CarrierConfigManager.KEY_WORLD_MODE_ENABLED_BOOL, true);
+ // User set Network mode as LTE
+ when(mTelephonyManager.getAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER)).thenReturn(
+ (long) (RAF_LTE | RAF_LTE_CA | RAF_IS95A | RAF_IS95B | RAF_1xRTT | RAF_EVDO_0
+ | RAF_EVDO_A | RAF_EVDO_B | RAF_EHRPD));
+ when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
+
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException ignored) {
+ }
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+
+ verify(mNotificationManager, never()).notify(any(), anyInt(), any());
+ }
+
+ @Test
+ public void testUpdateNetworkSelection_worldMode_userSetTDSCDMA_notSupported_notifNotSent()
+ throws Exception {
+ prepareResourcesForNetworkSelection();
+
+ PersistableBundle config = new PersistableBundle();
+ config.putBoolean(CarrierConfigManager.KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
+ config.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, false);
+ config.putBoolean(CarrierConfigManager.KEY_CSP_ENABLED_BOOL, false);
+ config.putBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL, true);
+
+ // World mode is on
+ config.putBoolean(CarrierConfigManager.KEY_WORLD_MODE_ENABLED_BOOL, true);
+ // User set Network mode as NETWORK_MODE_LTE_TDSCDMA_GSM
+ when(mTelephonyManager.getAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER)).thenReturn(
+ (long) (RAF_LTE | RAF_LTE_CA | RAF_TD_SCDMA | RAF_GSM | RAF_GPRS | RAF_EDGE));
+ // But TDSCDMA is NOT supported
+ config.putBoolean(CarrierConfigManager.KEY_SUPPORT_TDSCDMA_BOOL, false);
+ when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
+
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException ignored) {
+ }
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+
+ verify(mNotificationManager, never()).notify(any(), anyInt(), any());
+ }
+
+ @Test
+ public void testUpdateNetworkSelection_worldMode_userSetWCDMA_notificationSent()
+ throws Exception {
+ prepareResourcesForNetworkSelection();
+
+ PersistableBundle config = new PersistableBundle();
+ config.putBoolean(CarrierConfigManager.KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
+ config.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, false);
+ config.putBoolean(CarrierConfigManager.KEY_CSP_ENABLED_BOOL, false);
+ config.putBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL, true);
+
+ // World mode is on
+ config.putBoolean(CarrierConfigManager.KEY_WORLD_MODE_ENABLED_BOOL, true);
+ // User set Network mode as NETWORK_MODE_LTE_TDSCDMA_GSM
+ when(mTelephonyManager.getAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER)).thenReturn(
+ (long) (RAF_LTE | RAF_LTE_CA | RAF_GSM | RAF_GPRS | RAF_EDGE | RAF_HSUPA | RAF_HSDPA
+ | RAF_HSPA | RAF_HSPAP | RAF_UMTS));
+ // But TDSCDMA is NOT supported
+ config.putBoolean(CarrierConfigManager.KEY_SUPPORT_TDSCDMA_BOOL, false);
+ when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
+
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException ignored) {
+ }
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+
+ verifyNotificationSentWithChannelId(NotificationChannelController.CHANNEL_ID_ALERT);
+ }
+
+ @Test
+ public void testUpdateNetworkSelection_worldPhone_networkSelectionNotHide_notificationSent()
+ throws Exception {
+ prepareResourcesForNetworkSelection();
+
+ PersistableBundle config = new PersistableBundle();
+ config.putBoolean(CarrierConfigManager.KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
+ config.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, false);
+ config.putBoolean(CarrierConfigManager.KEY_CSP_ENABLED_BOOL, false);
+ // World mode is off
+ config.putBoolean(CarrierConfigManager.KEY_WORLD_MODE_ENABLED_BOOL, false);
+ // World phone is on
+ config.putBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL, true);
+ when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
+
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException ignored) {
+ }
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+
+ verifyNotificationSentWithChannelId(NotificationChannelController.CHANNEL_ID_ALERT);
+ }
+
+ @Test
+ public void testUpdateNetworkSelection_gsmBasicOptionOn_notificationSent()
+ throws Exception {
+ prepareResourcesForNetworkSelection();
+
+ PersistableBundle config = new PersistableBundle();
+ config.putBoolean(CarrierConfigManager.KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
+ config.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, false);
+ config.putBoolean(CarrierConfigManager.KEY_CSP_ENABLED_BOOL, false);
+ // World phone is on
+ config.putBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL, true);
+ // World mode is off
+ config.putBoolean(CarrierConfigManager.KEY_WORLD_MODE_ENABLED_BOOL, false);
+ when(mTelephonyManager.getPhoneType()).thenReturn(TelephonyManager.PHONE_TYPE_GSM);
+ when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
+
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException ignored) {
+ }
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+
+ verifyNotificationSentWithChannelId(NotificationChannelController.CHANNEL_ID_ALERT);
+ }
+
+ @Test
+ public void testUpdateNetworkSelection_gsmBasicOptionOff_notificationNotSent()
+ throws Exception {
+ prepareResourcesForNetworkSelection();
+
+ PersistableBundle config = new PersistableBundle();
+ config.putBoolean(CarrierConfigManager.KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
+ config.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, false);
+ config.putBoolean(CarrierConfigManager.KEY_CSP_ENABLED_BOOL, false);
+ // World mode is off
+ config.putBoolean(CarrierConfigManager.KEY_WORLD_MODE_ENABLED_BOOL, false);
+ when(mCarrierConfigManager.getConfigForSubId(TEST_SUB_ID)).thenReturn(config);
+ when(mTelephonyManager.getPhoneType()).thenReturn(TelephonyManager.PHONE_TYPE_CDMA);
+
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException ignored) {
+ }
+ mNotificationMgr.updateNetworkSelection(ServiceState.STATE_OUT_OF_SERVICE, TEST_SUB_ID);
+
+ verify(mNotificationManager, never()).notify(any(), anyInt(), any());
+ }
+
+ @Test
+ public void testShowLimitedSimFunctionWarningNotification_forTheFirstTime_notificationSent()
+ throws Exception {
+ when(mResources.getText(R.string.limited_sim_function_notification_message)).thenReturn(
+ CARRIER_NAME);
+ when(mResources.getText(
+ R.string.limited_sim_function_with_phone_num_notification_message)).thenReturn(
+ "123");
+
+ mNotificationMgr.showLimitedSimFunctionWarningNotification(TEST_SUB_ID, CARRIER_NAME);
+
+ verifyNotificationSentWithChannelId(
+ NotificationChannelController.CHANNEL_ID_SIM_HIGH_PRIORITY);
+ }
+
+ @Test
+ public void testShowLimitedSimFunctionWarningNotification_consecutiveCall_notificationSentOnce()
+ throws Exception {
+ when(mResources.getText(R.string.limited_sim_function_notification_message)).thenReturn(
+ CARRIER_NAME);
+ when(mResources.getText(
+ R.string.limited_sim_function_with_phone_num_notification_message)).thenReturn(
+ "123");
+
+ // Call the method TWICE with the same subscription
+ mNotificationMgr.showLimitedSimFunctionWarningNotification(TEST_SUB_ID, CARRIER_NAME);
+ mNotificationMgr.showLimitedSimFunctionWarningNotification(TEST_SUB_ID, CARRIER_NAME);
+
+ // Verify the notification is only sent ONCE
+ verifyNotificationSentWithChannelId(
+ NotificationChannelController.CHANNEL_ID_SIM_HIGH_PRIORITY);
+ }
+
+ @Test
+ public void testDismissLimitedSimFunctionWarningNotification_noShowCalledBefore_noCancelSent()
+ throws Exception {
+ // showLimitedSimFunctionWarningNotification was never called before
+
+ mNotificationMgr.dismissLimitedSimFunctionWarningNotification(TEST_SUB_ID);
+
+ verify(mNotificationManager, never()).cancel(any(), anyInt());
+ }
+
+ @Test
+ public void testDismissLimitedSimFunctionWarningNotification_showCalledBefore_cancelSent()
+ throws Exception {
+ when(mResources.getText(R.string.limited_sim_function_notification_message)).thenReturn(
+ CARRIER_NAME);
+ when(mResources.getText(
+ R.string.limited_sim_function_with_phone_num_notification_message)).thenReturn(
+ "123");
+ mNotificationMgr.showLimitedSimFunctionWarningNotification(TEST_SUB_ID, CARRIER_NAME);
+
+ mNotificationMgr.dismissLimitedSimFunctionWarningNotification(TEST_SUB_ID);
+
+ verify(mNotificationManager).cancel(any(), eq(LIMITED_SIM_FUNCTION_NOTIFICATION));
+ }
+
+ private ApplicationInfo buildApplicationInfo(int targetSdkVersion) {
+ ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.targetSdkVersion = targetSdkVersion;
+ return applicationInfo;
+ }
+
+ private void verifyNotificationSentWithChannelId(String expectedNotificationChannelId) {
+ ArgumentCaptor<Notification> notificationArgumentCaptor = ArgumentCaptor.forClass(
+ Notification.class);
+ verify(mNotificationManager).notify(any(), anyInt(), notificationArgumentCaptor.capture());
+ Notification capturedNotification = notificationArgumentCaptor.getAllValues().get(0);
+ assertThat(capturedNotification.getChannelId()).isEqualTo(expectedNotificationChannelId);
+ }
+
+ private void prepareResourcesForNetworkSelection() {
+ when(mSharedPreferences.getString(Phone.NETWORK_SELECTION_NAME_KEY + TEST_SUB_ID,
+ "")).thenReturn(TEST_SELECTED_NETWORK_OPERATOR_NAME);
+ when(mResources.getBoolean(
+ com.android.internal.R.bool.skip_restoring_network_selection)).thenReturn(false);
+ when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
+ when(mApp.getString(R.string.mobile_network_settings_package)).thenReturn(
+ MOBILE_NETWORK_SELECTION_PACKAGE);
+ when(mApp.getString(R.string.mobile_network_settings_class)).thenReturn(
+ MOBILE_NETWORK_SELECTION_CLASS);
+ }
+
+ private static void replaceInstance(final Class c,
+ final String instanceName, final Object obj, final Object newValue) throws Exception {
+ Field field = c.getDeclaredField(instanceName);
+ field.setAccessible(true);
+ field.set(obj, newValue);
+ }
+}
diff --git a/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java b/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java
index 7f9efdc..28a7b02 100644
--- a/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java
+++ b/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java
@@ -17,19 +17,104 @@
package com.android.services.telephony;
import static android.media.ToneGenerator.TONE_PROP_PROMPT;
+import static android.media.ToneGenerator.TONE_SUP_BUSY;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.TestCase.assertEquals;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
import android.telephony.DisconnectCause;
+import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.TelephonyTestBase;
+import com.android.internal.telephony.GsmCdmaPhone;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
+import com.android.phone.common.R;
+
+import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Locale;
+
@RunWith(AndroidJUnit4.class)
-public class DisconnectCauseUtilTest {
+public class DisconnectCauseUtilTest extends TelephonyTestBase {
+
+ // constants
+ public static final int PHONE_ID = 123;
+ public static final String EMPTY_STRING = "";
+
+ // dynamic
+ private Context mContext;
+ private HashMap<InstanceKey, Object> mOldInstances = new HashMap<InstanceKey, Object>();
+ private ArrayList<InstanceKey> mInstanceKeys = new ArrayList<InstanceKey>();
+
+ //Mocks
+ @Mock
+ private GsmCdmaPhone mMockPhone;
+
+ // inner classes
+ private static class InstanceKey {
+ public final Class mClass;
+ public final String mInstName;
+ public final Object mObj;
+
+ InstanceKey(final Class c, final String instName, final Object obj) {
+ mClass = c;
+ mInstName = instName;
+ mObj = obj;
+ }
+
+ @Override
+ public int hashCode() {
+ return (mClass.getName().hashCode() * 31 + mInstName.hashCode()) * 31;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || !(obj instanceof InstanceKey)) {
+ return false;
+ }
+
+ InstanceKey other = (InstanceKey) obj;
+ return (other.mClass == mClass && other.mInstName.equals(mInstName)
+ && other.mObj == mObj);
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ // objects that call static getInstance()
+ mMockPhone = Mockito.mock(GsmCdmaPhone.class);
+ mContext = InstrumentationRegistry.getTargetContext();
+ // set mocks
+ setSinglePhone();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ // restoreInstance.
+ // Not doing so will potentially "confuse" other tests with the mocked instance
+ restoreInstance(PhoneFactory.class, "sPhones", null);
+ super.tearDown();
+ }
+
+
/**
* Verifies that a call drop due to loss of WIFI results in a disconnect cause of error and that
* the label, description and tone are all present.
@@ -43,4 +128,109 @@
assertNotNull(tcCause.getDescription());
assertNotNull(tcCause.getReason());
}
+
+ /**
+ * ensure the default behavior was not changed when a disconnect cause comes in as
+ * DisconnectCause.ERROR_UNSPECIFIED
+ */
+ @Test
+ public void testDefaultDisconnectCauseBehaviorForCauseNotInCarrierBusyToneArray() {
+ android.telecom.DisconnectCause tcCause = DisconnectCauseUtil.toTelecomDisconnectCause(
+ DisconnectCause.ERROR_UNSPECIFIED, EMPTY_STRING, PHONE_ID);
+ // CODE
+ assertEquals(android.telecom.DisconnectCause.ERROR, tcCause.getCode());
+ // LABEL
+ safeAssertLabel(null, tcCause);
+ // TONE
+ assertEquals(TONE_PROP_PROMPT, tcCause.getTone());
+ }
+
+ /**
+ * Simulate a Carrier classifying the DisconnectCause.ERROR_UNSPECIFIED as a
+ * DisconnectCause.BUSY. The code, label, and tone should match DisconnectCause.BUSY.
+ */
+ @Test
+ public void testCarrierSetDisconnectCauseInBusyToneArray() {
+ int[] carrierBusyArr = {DisconnectCause.BUSY, DisconnectCause.ERROR_UNSPECIFIED};
+ PersistableBundle config = new PersistableBundle();
+
+ config.putIntArray(
+ CarrierConfigManager.KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY,
+ carrierBusyArr);
+
+ android.telecom.DisconnectCause tcCause =
+ DisconnectCauseUtil.toTelecomDisconnectCause(
+ DisconnectCause.ERROR_UNSPECIFIED, -1,
+ EMPTY_STRING, PHONE_ID, null, config);
+
+ // CODE
+ assertEquals(android.telecom.DisconnectCause.BUSY, tcCause.getCode());
+ // LABEL
+ safeAssertLabel(R.string.callFailed_userBusy, tcCause);
+ // TONE
+ assertEquals(TONE_SUP_BUSY, tcCause.getTone());
+ }
+
+ private void setSinglePhone() throws Exception {
+ Phone[] mPhones = new Phone[]{mMockPhone};
+ replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
+ }
+
+
+ protected synchronized void replaceInstance(final Class c, final String instanceName,
+ final Object obj, final Object newValue)
+ throws Exception {
+ Field field = c.getDeclaredField(instanceName);
+ field.setAccessible(true);
+
+ InstanceKey key = new InstanceKey(c, instanceName, obj);
+ if (!mOldInstances.containsKey(key)) {
+ mOldInstances.put(key, field.get(obj));
+ mInstanceKeys.add(key);
+ }
+ field.set(obj, newValue);
+ }
+
+ protected synchronized void restoreInstance(final Class c, final String instanceName,
+ final Object obj) throws Exception {
+ InstanceKey key = new InstanceKey(c, instanceName, obj);
+ if (mOldInstances.containsKey(key)) {
+ Field field = c.getDeclaredField(instanceName);
+ field.setAccessible(true);
+ field.set(obj, mOldInstances.get(key));
+ mOldInstances.remove(key);
+ mInstanceKeys.remove(key);
+ }
+ }
+
+ private Resources getResourcesForLocale(Context context, Locale locale) {
+ Configuration config = new Configuration();
+ config.setToDefaults();
+ config.setLocale(locale);
+ Context localeContext = context.createConfigurationContext(config);
+ return localeContext.getResources();
+ }
+
+ private void safeAssertLabel(Integer resourceId,
+ android.telecom.DisconnectCause disconnectCause) {
+ Resources r = getResourcesForLocale(mContext, Locale.US);
+ if (resourceId == null || r == null) {
+ return;
+ }
+ String label = r.getString(resourceId);
+ assertEquals(label, disconnectCause.getLabel());
+ }
+
+ /**
+ * Verifies that an ICC_ERROR disconnect cause generates a message which mentions there is no
+ * SIM.
+ */
+ @Test
+ public void testIccError() {
+ android.telecom.DisconnectCause tcCause = DisconnectCauseUtil.toTelecomDisconnectCause(
+ DisconnectCause.ICC_ERROR);
+ assertEquals(android.telecom.DisconnectCause.ERROR, tcCause.getCode());
+ assertNotNull(tcCause.getLabel());
+ assertNotNull(tcCause.getDescription());
+ }
}
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index efa906e..c4d22ab 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -49,6 +49,7 @@
import android.telephony.CarrierConfigManager;
import android.telephony.RadioAccessFamily;
import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.emergency.EmergencyNumber;
import android.test.suitebuilder.annotation.SmallTest;
@@ -396,9 +397,6 @@
// Slot 1 has more capabilities
setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
- // Slot 1 has SIM inserted.
- setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
- setSlotHasIccCard(SLOT_1_PHONE_ID, true /*isInserted*/);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
@@ -511,9 +509,6 @@
// Make Capability the same
setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
- // Two SIMs inserted
- setSlotHasIccCard(SLOT_0_PHONE_ID, true /*isInserted*/);
- setSlotHasIccCard(SLOT_1_PHONE_ID, true /*isInserted*/);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
@@ -542,9 +537,6 @@
// Make Capability the same
setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
- // Slot 0 has SIM inserted.
- setSlotHasIccCard(SLOT_0_PHONE_ID, true /*isInserted*/);
- setSlotHasIccCard(SLOT_1_PHONE_ID, false /*isInserted*/);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
@@ -573,9 +565,35 @@
// Make Capability the same
setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
- // Slot 1 has SIM inserted.
- setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
- setSlotHasIccCard(SLOT_1_PHONE_ID, true /*isInserted*/);
+
+ Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+ assertEquals(slot1Phone, resultPhone);
+ }
+
+ /**
+ * Prerequisites:
+ * - MSIM Device with one ESIM, only slot 1 inserted has PSIM inserted
+ * - Both phones have the same capability
+ *
+ * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone because it is the only one
+ * with a SIM inserted
+ */
+ @Test
+ @SmallTest
+ public void testEqualCapabilitySim1Inserted_WithOneEsim() {
+ Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ setDefaultPhone(slot0Phone);
+ setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+ when(slot0Phone.getSubId()).thenReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+ setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+ // Make Capability the same
+ setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
+ setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
@@ -604,9 +622,6 @@
// Make Capability the same
setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
- // No SIMs inserted
- setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
- setSlotHasIccCard(SLOT_1_PHONE_ID, false /*isInserted*/);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
@@ -634,9 +649,63 @@
// Make Capability the same
setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_UNKNOWN);
setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_UNKNOWN);
- // No SIMs inserted
- setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
- setSlotHasIccCard(SLOT_1_PHONE_ID, false /*isInserted*/);
+
+ Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+ assertEquals(slot0Phone, resultPhone);
+ }
+
+ /**
+ * Prerequisites:
+ * - MSIM Device, no SIMs inserted (one ESIM)
+ * - Both SIMs have the same capability (Unknown)
+ *
+ * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone, since it is the first slot.
+ */
+ @Test
+ @SmallTest
+ public void testEqualCapabilityNoSimsInserted_WithOneESim() {
+ Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ setDefaultPhone(slot0Phone);
+ setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+ setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
+ when(slot1Phone.getSubId()).thenReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+ // Make Capability the samesvim
+ setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_UNKNOWN);
+ setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_UNKNOWN);
+
+ Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+ assertEquals(slot0Phone, resultPhone);
+ }
+
+ /**
+ * Prerequisites:
+ * - MSIM Device, both ESIMS (no profile activated)
+ * - Both phones have the same capability (Unknown)
+ *
+ * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone, since it is the first slot.
+ */
+ @Test
+ @SmallTest
+ public void testEqualCapabilityNoSimsInserted_WithTwoESims() {
+ Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ setDefaultPhone(slot0Phone);
+ setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+ when(slot0Phone.getSubId()).thenReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+ when(slot1Phone.getSubId()).thenReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+ // Make Capability the sames
+ setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_UNKNOWN);
+ setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_UNKNOWN);
Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
@@ -1497,10 +1566,6 @@
when(mSubscriptionManagerProxy.getSimStateForSlotIdx(slotId)).thenReturn(slotState);
}
- private void setSlotHasIccCard(int slotId, boolean isInserted) {
- when(mTelephonyManagerProxy.hasIccCard(slotId)).thenReturn(isInserted);
- }
-
private void setDefaultPhone(Phone phone) {
when(mPhoneFactoryProxy.getDefaultPhone()).thenReturn(phone);
}
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionTest.java
index 388fd29..c996e5f 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionTest.java
@@ -14,6 +14,7 @@
import static org.mockito.Mockito.when;
import android.os.Bundle;
+import android.os.PersistableBundle;
import android.telecom.Connection;
import android.telephony.CarrierConfigManager;
import android.telephony.DisconnectCause;
@@ -25,6 +26,7 @@
import com.android.internal.telephony.d2d.DtmfTransport;
import com.android.internal.telephony.d2d.RtpTransport;
import com.android.internal.telephony.imsphone.ImsPhoneConnection;
+import com.android.phone.PhoneGlobals;
import com.android.phone.R;
import org.junit.Before;
@@ -212,4 +214,47 @@
fail("refreshConferenceSupported threw ClassCastException");
}
}
+
+ /**
+ * Tests TelephonyConnection#getCarrierConfig never returns a null given all cases that can
+ * cause a potential null.
+ */
+ @Test
+ public void testGetCarrierConfigBehaviorWithNull() throws Exception {
+ TestTelephonyConnectionSimple c = new TestTelephonyConnectionSimple();
+
+ // case: return a valid carrier config (good case)
+ when(c.mPhoneGlobals.getCarrierConfigForSubId(c.getPhone().getSubId())).
+ thenReturn(CarrierConfigManager.getDefaultConfig());
+ assertNotNull(c.getCarrierConfig());
+
+ // case: PhoneGlobals.getInstance().getCarrierConfigForSubId(int) returns null
+ when(c.mPhoneGlobals.getCarrierConfigForSubId(c.getPhone().getSubId()))
+ .thenReturn(null);
+ assertNotNull(c.getCarrierConfig());
+
+ // case: phone is null
+ c.setMockPhone(null);
+ assertNull(c.getPhone());
+ assertNotNull(c.getCarrierConfig());
+ }
+
+ /**
+ * Tests the behavior of TelephonyConnection#isRttMergeSupported(@NonNull PersistableBundle).
+ * Note, the function should be able to handle an empty PersistableBundle and should NEVER
+ * receive a null object as denoted in by @NonNull annotation.
+ */
+ @Test
+ public void testIsRttMergeSupportedBehavior() {
+ TestTelephonyConnection c = new TestTelephonyConnection();
+ // ensure isRttMergeSupported(PersistableBundle) does not throw NPE when given an Empty PB
+ assertFalse(c.isRttMergeSupported(new PersistableBundle()));
+
+ // simulate the passing situation
+ c.getCarrierConfigBundle().putBoolean(
+ CarrierConfigManager.KEY_ALLOW_MERGING_RTT_CALLS_BOOL,
+ true);
+ assertTrue(c.isRttMergeSupported(c.getCarrierConfig()));
+ }
+
}
diff --git a/tests/src/com/android/services/telephony/TelephonyManagerTest.java b/tests/src/com/android/services/telephony/TelephonyManagerTest.java
index cf1ae8f..89b558c 100644
--- a/tests/src/com/android/services/telephony/TelephonyManagerTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyManagerTest.java
@@ -15,11 +15,14 @@
*/
package com.android.services.telephony;
-
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -28,6 +31,8 @@
import android.app.PropertyInvalidatedCache;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.RemoteException;
import android.telecom.PhoneAccountHandle;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -37,6 +42,8 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.telephony.ITelephony;
+import com.android.internal.telephony.IPhoneSubInfo;
+import com.android.internal.telephony.PhoneConstants;
import org.junit.After;
import org.junit.Before;
@@ -61,8 +68,10 @@
private static final int TEST_SUBID_2 = 2;
private ITelephony mMockITelephony;
+ private IPhoneSubInfo mMockIPhoneSubInfo;
private SubscriptionManager mMockSubscriptionManager;
private Context mMockContext;
+ private final PackageManager mPackageManager = mock(PackageManager.class);
private TelephonyManager mTelephonyManager;
@@ -89,18 +98,23 @@
}
return null;
}
+ @Override
+ public PackageManager getPackageManager() {
+ return mPackageManager;
+ }
};
@Before
public void setUp() throws Exception {
mMockITelephony = mock(ITelephony.class);
+ mMockIPhoneSubInfo = mock(IPhoneSubInfo.class);
mMockSubscriptionManager = mock(SubscriptionManager.class);
mMockContext = mock(Context.class);
when(mMockContext.getSystemService(eq(Context.TELEPHONY_SUBSCRIPTION_SERVICE)))
.thenReturn(mMockSubscriptionManager);
-
mTelephonyManager = new TelephonyManager(mContext);
TelephonyManager.setupITelephonyForTest(mMockITelephony);
+ TelephonyManager.setupIPhoneSubInfoForTest(mMockIPhoneSubInfo);
TelephonyManager.enableServiceHandleCaching();
}
@@ -218,4 +232,32 @@
verify(mMockITelephony, times(1)).getSubIdForPhoneAccountHandle(eq(TEST_HANDLE2),
anyString(), anyString());
}
+
+ @Test
+ public void testGetSimServiceTable_USIM() throws RemoteException {
+ assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION, true));
+ when(mMockIPhoneSubInfo.getSimServiceTable(anyInt(), anyInt())).thenReturn("12345");
+ assertEquals("12345", mTelephonyManager.getSimServiceTable(PhoneConstants.APPTYPE_USIM));
+ verify(mMockIPhoneSubInfo, times(1)).getSimServiceTable(anyInt(), anyInt());
+ }
+
+ @Test
+ public void testGetSimServiceTable_ISIM() throws RemoteException {
+ when(mMockIPhoneSubInfo.getIsimIst(anyInt())).thenReturn("12345");
+ assertEquals("12345", mTelephonyManager.getSimServiceTable(PhoneConstants.APPTYPE_ISIM));
+ verify(mMockIPhoneSubInfo, times(1)).getIsimIst(anyInt());
+ }
+
+ @Test
+ public void testGetSimServiceTable_RUSIM() throws RemoteException {
+ assumeFalse(hasFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION, false));
+ assertEquals(null, mTelephonyManager.getSimServiceTable(PhoneConstants.APPTYPE_RUIM));
+ }
+
+ private boolean hasFeature(String feature, boolean status) {
+ doReturn(status)
+ .when(mPackageManager).hasSystemFeature(
+ PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION);
+ return mContext.getPackageManager().hasSystemFeature(feature);
+ }
}
diff --git a/tests/src/com/android/services/telephony/TestTelephonyConnectionSimple.java b/tests/src/com/android/services/telephony/TestTelephonyConnectionSimple.java
new file mode 100644
index 0000000..9dc2551
--- /dev/null
+++ b/tests/src/com/android/services/telephony/TestTelephonyConnectionSimple.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.services.telephony;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.AttributionSource;
+import android.content.Context;
+import android.os.Process;
+import android.telephony.TelephonyManager;
+
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.phone.PhoneGlobals;
+
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+public class TestTelephonyConnectionSimple extends TelephonyConnection{
+
+ @Mock
+ Context mMockContext;
+
+ @Mock
+ PhoneGlobals mPhoneGlobals;
+
+ private Phone mMockPhone;
+
+ public TelephonyConnection cloneConnection() {
+ return this;
+ }
+
+ public TestTelephonyConnectionSimple(){
+ super(null, null, android.telecom.Call.Details.DIRECTION_INCOMING);
+ MockitoAnnotations.initMocks(this);
+
+ AttributionSource attributionSource = new AttributionSource.Builder(
+ Process.myUid()).build();
+
+ mMockPhone = mock(Phone.class);
+ mMockContext = mock(Context.class);
+ mPhoneGlobals = mock(PhoneGlobals.class);
+
+ when(mMockPhone.getSubId()).thenReturn(1);
+ }
+
+ public void setMockPhone(Phone newPhone) {
+ mMockPhone = newPhone;
+ }
+
+ @Override
+ public Phone getPhone() {
+ return mMockPhone;
+ }
+
+}