Merge "Listen to changes in the original connection for domain tracking"
diff --git a/assets/CarrierRestrictionOperatorDetails.json b/assets/CarrierRestrictionOperatorDetails.json
new file mode 100644
index 0000000..166cc39
--- /dev/null
+++ b/assets/CarrierRestrictionOperatorDetails.json
@@ -0,0 +1,4 @@
+{
+ "_comment": "Operator should register with its application package name, carrierId and all the corresponding SHAIDs",
+ "_comment": "Example format :: << \"packageName\" : {\"carrierId\":<int>, \"callerSHA1Id\":[<SHAID1>, <SHAID2>]} >>"
+}
\ No newline at end of file
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 955929e..7a251d8 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Gekoppel"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Opgeskort"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Onbekend"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Primêr"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"grepe"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 5137085..dcd184e 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"ተገናኝቷል"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"ታግዷል"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"ያልታወቀ"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"ቀዳሚ"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"ባይቶች"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 24e634f..db93b63 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"متّصل بالإنترنت"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"معلّق"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"غير معروف"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"أساسي"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"الحزم"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"بايت"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"بالديسيبل"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index aab6884..125539f 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"সংযোগ কৰা হ’ল"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"নিলম্বন কৰা হৈছে"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"অজ্ঞাত"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"প্ৰাথমিক"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"পিকেটিএছ"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"বাইটসমূহ"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"ডিবিএম"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 479738f..a1e694b 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Qoşuldu"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Dayandırılıb"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Naməlum"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"İlkin"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkt"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bayt"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 9815d95..0f72816 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Povezano"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Suspendovano"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Nepoznato"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Primarno"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pak."</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bajt(ov)a"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 188e778..c3f1678 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Падключана"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Прыпынена"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Невядома"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Асноўны"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"пак."</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"Б"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"дБм"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 9426c5c..168d749 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Установена е връзка"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Спрени"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Неизвестно"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Основна"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"пакета"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"байта"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 4054d88..93685f0 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"কানেক্ট করা হয়েছে"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"সাসপেন্ড করা হয়েছে"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"অজানা"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"প্রাথমিক"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"বাইট"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index c0bb458..7f0c408 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Povezano"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Obustavljeno"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Nepoznato"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Primarno"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"paketi"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bajtova"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 6b18654..be5be33 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Amb connexió"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"En suspensió"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Desconegut"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Principal"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"paquets"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bytes"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index fc63e25..b0cde9a 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Připojeno"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Pozastaveno"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Neznámé"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Primární"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pakety"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"B"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index c41d548..e55fa8e 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -577,7 +577,7 @@
<string name="dialerKeyboardHintText" msgid="1115266533703764049">"Brug tastatur til at ringe op"</string>
<string name="onscreenHoldText" msgid="4025348842151665191">"Hold"</string>
<string name="onscreenEndCallText" msgid="6138725377654842757">"Afslut"</string>
- <string name="onscreenShowDialpadText" msgid="658465753816164079">"Nummerblok"</string>
+ <string name="onscreenShowDialpadText" msgid="658465753816164079">"Opkaldstastatur"</string>
<string name="onscreenMuteText" msgid="5470306116733843621">"Lyd fra"</string>
<string name="onscreenAddCallText" msgid="9075675082903611677">"Tilføj opkald"</string>
<string name="onscreenMergeCallsText" msgid="3692389519611225407">"Slå opkald sammen"</string>
@@ -657,8 +657,8 @@
<string name="selectContact" msgid="1527612842599767382">"vælg kontakt"</string>
<string name="not_voice_capable" msgid="2819996734252084253">"Taleopkald understøttes ikke"</string>
<string name="description_dial_button" msgid="8614631902795087259">"ring op"</string>
- <string name="description_dialpad_button" msgid="7395114120463883623">"vis numerisk tastatur"</string>
- <string name="pane_title_emergency_dialpad" msgid="3627372514638694401">"Numerisk tastatur til nødopkald"</string>
+ <string name="description_dialpad_button" msgid="7395114120463883623">"vis opkaldstastatur"</string>
+ <string name="pane_title_emergency_dialpad" msgid="3627372514638694401">"Nødopkaldstastatur"</string>
<string name="voicemail_visual_voicemail_switch_title" msgid="6610414098912832120">"Visuel telefonsvarer"</string>
<string name="voicemail_set_pin_dialog_title" msgid="7005128605986960003">"Angiv pinkode"</string>
<string name="voicemail_change_pin_dialog_title" msgid="4633077715231764435">"Skift pinkode"</string>
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Tilsluttet"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Suspenderet"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Ukendt"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Primær"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pk."</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bytes"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 2594f47..45875d1 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Verbunden"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Gesperrt"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Unbekannt"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Primär"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"Pakete"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"Bytes"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 6af4940..8400f09 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Σε σύνδεση"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Σε αναστολή"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Άγνωστο"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Κύρια"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"byte"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index dc357ae..8451cc7 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Connected"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Suspended"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Unknown"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Primary"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bytes"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index e605117..67cb90d 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Connected"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Suspended"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Unknown"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Primary"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bytes"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index dc357ae..8451cc7 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Connected"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Suspended"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Unknown"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Primary"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bytes"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index dc357ae..8451cc7 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Connected"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Suspended"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Unknown"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Primary"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bytes"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 2284c44..8a26155 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Connected"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Suspended"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Unknown"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Primary"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bytes"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 2ba08e9..97f7985 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Conectado"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Suspendido"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Desconocido"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Principal"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"paquetes"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bytes"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index b447036..b5e18fb 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Conectado"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Suspendido"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Desconocido"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Principal"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pqts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bytes"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index c458160..84566b5 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Ühendatud"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Peatatud"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Teadmata"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Peamine"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"baiti"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 92df0e7..b205fc8 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -615,7 +615,7 @@
<string name="ota_title_activate" msgid="4049645324841263423">"Aktibatu telefonoa"</string>
<string name="ota_touch_activate" msgid="838764494319694754">"Telefono-zerbitzua aktibatzeko, dei berezi bat egin behar da.\n\n\"Aktibatu\" sakatu ondoren, telefonoa aktibatzeko, entzun ematen zaizkizun argibideak."</string>
<string name="ota_hfa_activation_title" msgid="3300556778212729671">"Aktibatzen…"</string>
- <string name="ota_hfa_activation_dialog_message" msgid="7921718445773342996">"Telefonoa datu-konexioaren zerbitzua aktibatzen ari da.\n\nEragiketa 5 minutura arte luza daiteke."</string>
+ <string name="ota_hfa_activation_dialog_message" msgid="7921718445773342996">"Telefonoa mugikorretarako datu-zerbitzua aktibatzen ari da.\n\nEragiketa gehienez 5 minutu luza daiteke."</string>
<string name="ota_skip_activation_dialog_title" msgid="7666611236789203797">"Aktibazioa saltatu nahi duzu?"</string>
<string name="ota_skip_activation_dialog_message" msgid="6691722887019708713">"Aktibazioa saltatzen baduzu, ezingo duzu deirik egin, ez eta datu-konexioaren sareetara konektatu ere, baina Wi-Fi sareetara konektatu ahal izango duzu. Telefonoa aktibatzen duzun arte, pizten duzun bakoitzean eskatuko zaizu aktibatzeko."</string>
<string name="ota_skip_activation_dialog_skip_label" msgid="5908029466817825633">"Saltatu"</string>
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Konektatuta"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Behin-behinean itxitakoak"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Ezezaguna"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Nagusia"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"byte"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 6743e96..5d6a5ce 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"متصل"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"تعلیقشده"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"نامشخص"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"اصلی"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"بایت"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index b835a0c..a4c9836 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Yhdistetty"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Jäädytetty"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Tuntematon"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Ensisijainen"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pakettia"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"tavua"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index a2e9063..0483dd6 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Connecté"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Suspendu"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Inconnu"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Principal"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"paquets"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"octets"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 55fc28e..e3662ec 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Connecté"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Suspendu"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Inconnu"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Principal"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"paquets"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"octets"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index adaef55..9890857 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Conectada"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Suspendido"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Descoñecido"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Principal"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bytes"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 1cc4dd1..bafa321 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"કનેક્ટેડ"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"સસ્પેન્ડ કરી"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"અજાણ"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"પ્રાથમિક"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"બાઇટ"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index d9de3dd..d2be9dd 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"कनेक्ट किया गया"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"थोड़ी देर के लिए रोक लगी है"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"अज्ञात"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"प्राइमरी"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"बाइट"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index d5349a0..c7d0607 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Povezano"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Obustavljeno"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Nepoznato"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Primarno"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bajtovi"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 63ae0b9..872abe1 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Csatlakoztatva"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Felfüggesztve"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Ismeretlen"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Elsődleges"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"csomag"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bájt"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 4b9a9a9..26b2648 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Միացված է"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Անջատված է"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Անհայտ"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Հիմնական"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"բայթ"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index d58999b..4551592 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -48,7 +48,7 @@
<string name="no_vm_number_msg" msgid="5165161462411372504">"Tidak ada nomor kotak pesan tersimpan pada kartu SIM."</string>
<string name="add_vm_number_str" msgid="7368168964435881637">"Tambahkan nomor"</string>
<string name="voice_number_setting_primary_user_only" msgid="3394706575741912843">"Setelan Pesan Suara hanya dapat diubah oleh Pengguna Utama."</string>
- <string name="puk_unlocked" msgid="4627340655215746511">"Kartu SIM Anda tidak lagi dicekal. Ponsel Anda sedang dibuka kuncinya..."</string>
+ <string name="puk_unlocked" msgid="4627340655215746511">"Kartu SIM Anda tidak lagi diblokir. Ponsel Anda sedang dibuka kuncinya..."</string>
<string name="label_ndp" msgid="7617392683877410341">"PIN pembuka kunci jaringan SIM"</string>
<string name="label_phoneid" msgid="8775611434123577808">"SIM dikunci untuk operator"</string>
<string name="sim_ndp_unlock_text" msgid="7737338355451978338">"Buka kunci"</string>
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Terhubung"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Ditangguhkan"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Tidak diketahui"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Primer"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"byte"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index a475a9e..0ccd715 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Tengt"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Lokað tímabundið"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Óþekkt"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Aðal"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pk."</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bæti"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 2eaf7ee..be494db 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Connesso"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Sospeso"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Sconosciuto"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Principale"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkt"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"byte"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 154c8a0..c8f246e 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"מקושר"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"בהשעיה"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"לא ידוע"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"ראשי"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"בייטים"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 4d9f50d..0679d84 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"接続済み"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"停止中"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"不明"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"メイン"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"バイト"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 3f4f5a1..f5d6045 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"დაკავშირებულია"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"შეჩერებულია"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"უცნობი"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"ძირითადი"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"პკტ."</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"ბაიტი"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 048b5a0..0d13867 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -452,7 +452,7 @@
<string name="sum_fdn_change_pin" msgid="3510994280557335727">"ТТН қол жетімділігі үшін PIN кодты өзгерту"</string>
<string name="sum_fdn_manage_list" msgid="3311397063233992907">"Телефон нөмірлері тізімін басқару"</string>
<string name="voice_privacy" msgid="7346935172372181951">"Дауыс құпиялығы"</string>
- <string name="voice_privacy_summary" msgid="3556460926168473346">"Жетілдірілген құпиялылық режимін қосу"</string>
+ <string name="voice_privacy_summary" msgid="3556460926168473346">"Жетілдірілген құпиялық режимін қосу"</string>
<string name="tty_mode_option_title" msgid="3843817710032641703">"Tелетайп режимі"</string>
<string name="tty_mode_option_summary" msgid="4770510287236494371">"Телетайп режиміне реттеу"</string>
<string name="auto_retry_mode_title" msgid="2985801935424422340">"Әрекетті автоматты қайталау"</string>
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Жалғанған"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Уақытша тоқтатылған"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Белгісіз"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Негізгі"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"байт"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 40ebda9..38177be 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"បានភ្ជាប់"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"បានផ្អាក"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"មិនស្គាល់"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"ចម្បង"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"បៃ"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 97ce9fc..8b7b574 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"ಅಮಾನತುಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"ಅಪರಿಚಿತ"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"ಪ್ರಾಥಮಿಕ"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"ಬೈಟ್ಗಳು"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 7e6fe78..2e64555 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"연결됨"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"정지됨"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"알 수 없음"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"기본"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"패킷"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"바이트"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index d966d45..17ef040 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -68,7 +68,7 @@
<string name="phone_accounts_make_sip_calls_with" msgid="4691221006731847255">"SIP чалууларын төмөнкү менен жасоо"</string>
<string name="phone_accounts_ask_every_time" msgid="6192347582666047168">"Биринчи сурасын"</string>
<string name="phone_accounts_default_account_label" msgid="5107598881335931101">"Тармак жок"</string>
- <string name="phone_accounts_settings_header" msgid="6296501692964706536">"Жөндөөлөр"</string>
+ <string name="phone_accounts_settings_header" msgid="6296501692964706536">"Параметрлер"</string>
<string name="phone_accounts_choose_accounts" msgid="4748805293314824974">"Аккаунттарды тандоо"</string>
<string name="phone_accounts_selection_header" msgid="2945830843104108440">"Телефон каттоо эсептери"</string>
<string name="phone_accounts_add_sip_account" msgid="1437634802033309305">"SIP аккаунтун кошуу"</string>
@@ -93,7 +93,7 @@
<string name="sum_cdma_call_settings" msgid="3185825305136993636">"CDMA менен гана чалуунун кошумча жөндөөлөрү"</string>
<string name="labelNwService" msgid="6015891883487125120">"Тармак кызматынын жөндөөлөрү"</string>
<string name="labelCallerId" msgid="2090540744550903172">"Чалуучуну аныктоо"</string>
- <string name="sum_loading_settings" msgid="434063780286688775">"Жөндөөлөр жүктөлүүдө…"</string>
+ <string name="sum_loading_settings" msgid="434063780286688775">"Параметрлер жүктөлүүдө…"</string>
<string name="sum_hide_caller_id" msgid="131100328602371933">"Чыгуучу чалууларда номер жашырылган"</string>
<string name="sum_show_caller_id" msgid="3571854755324664591">"Чыгуучу чалууларда көрсөтүлчү номер"</string>
<string name="sum_default_caller_id" msgid="1767070797135682959">"Кимдир-бирөөгө чалып жатканда ага номерим көрүнүшү үчүн байланыш операторунун стандарттуу жөндөөлөрү колдонулат."</string>
@@ -133,11 +133,11 @@
<string name="cdma_call_waiting_in_ims_off" msgid="1099246114368636334">"IMS платформасында CDMA чалуу күтүүcү өчүрүлгөн"</string>
<string name="updating_title" msgid="6130548922615719689">"Чалуу жөндөөлөрү"</string>
<string name="call_settings_admin_user_only" msgid="7238947387649986286">"Чалуу жөндөөлөрүн администратор гана өзгөртө алат."</string>
- <string name="call_settings_with_label" msgid="8460230435361579511">"Жөндөөлөр (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+ <string name="call_settings_with_label" msgid="8460230435361579511">"Параметрлер (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
<string name="error_updating_title" msgid="2024290892676808965">"Чалуу жөндөөлөрүндө ката кетти"</string>
- <string name="reading_settings" msgid="1605904432450871183">"Жөндөөлөр окулууда…"</string>
- <string name="updating_settings" msgid="3650396734816028808">"Жөндөөлөр жаңыртылууда…"</string>
- <string name="reverting_settings" msgid="7378668837291012205">"Жөндөөлөр артка кайтарылууда…"</string>
+ <string name="reading_settings" msgid="1605904432450871183">"Параметрлер окулууда…"</string>
+ <string name="updating_settings" msgid="3650396734816028808">"Параметрлер жаңыртылууда…"</string>
+ <string name="reverting_settings" msgid="7378668837291012205">"Параметрлер артка кайтарылууда…"</string>
<string name="response_error" msgid="3904481964024543330">"Тармактан күтүлбөгөн жооп алынды."</string>
<string name="exception_error" msgid="330994460090467">"Тармак же SIM карта катасы."</string>
<string name="stk_cc_ss_to_dial_error" msgid="5147693491690618704">"SS сурамы демейки чалууга өзгөртүлдү"</string>
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Туташты"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Убактылуу токтотулду"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Белгисиз"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Башкы"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"байттар"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
@@ -902,7 +903,7 @@
<string name="radio_info_smsc_update_label" msgid="5141996256097115753">"Жаңыртуу"</string>
<string name="radio_info_smsc_refresh_label" msgid="8409923721451604560">"Жаңылоо"</string>
<string name="radio_info_toggle_dns_check_label" msgid="1394078554927787350">"DNS текшерүүнү которуштуруу"</string>
- <string name="oem_radio_info_label" msgid="2914167475119997456">"OEM\'ге тиешелүү Маалымат/Жөндөөлөр"</string>
+ <string name="oem_radio_info_label" msgid="2914167475119997456">"OEM\'ге тиешелүү Маалымат/Параметрлер"</string>
<string name="radio_info_endc_available" msgid="2983767110681230019">"EN-DC жеткиликтүү (NSA):"</string>
<string name="radio_info_dcnr_restricted" msgid="7147511536420148173">"DCNR чектелген (NSA):"</string>
<string name="radio_info_nr_available" msgid="3383388088451237182">"NR жеткиликтүү (NSA):"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index bd7e6ab..9dbd694 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"ເຊື່ອມຕໍ່ແລ້ວ"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"ລະງັບໄວ້ແລ້ວ"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"ບໍ່ຮູ້ຈັກ"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"ຫຼັກ"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"ໄບຕ໌"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 4784b8a..ef02da0 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Prisijungta"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Laikinai sustabdyta"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Nežinoma"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Pagrindinis"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pakuot."</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"B"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index a61f412..890dc79 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Savienojums izveidots"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Darbība apturēta"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Nezināms"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Primārais"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"baiti"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 16e5f8d..70a9d6e 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Поврзан"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Суспендиран"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Непознат"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Примарен"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"бајти"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index a7fa922..3d01a16 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"കണക്റ്റ് ചെയ്തു"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"താൽക്കാലികമായി റദ്ദാക്കി"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"അജ്ഞാതം"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"പ്രാഥമികം"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"ബൈറ്റുകൾ"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index b04b00d..bdf8df1 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Холбогдсон"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Түр хаасан"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Тодорхойгүй"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Үндсэн"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"байт"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index a1c4bf0..719297a 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -424,7 +424,7 @@
</string-array>
<string name="cdma_subscription_title" msgid="3449527179325589434">"CDMA सदस्यता"</string>
<string name="cdma_subscription_summary" msgid="5681152534466169001">"RUIM/सिम आणि NV मध्ये बदला"</string>
- <string name="cdma_subscription_dialogtitle" msgid="8872086335839723980">"सदस्यता"</string>
+ <string name="cdma_subscription_dialogtitle" msgid="8872086335839723980">"सदस्यत्व"</string>
<string-array name="cdma_subscription_choices">
<item msgid="7989486897370727698">"RUIM/सिम"</item>
<item msgid="5445342771222849381">"NV"</item>
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"कनेक्ट केले"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"निलंबित केले"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"अज्ञात"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"प्राथमिक"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"बाइट"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 8bacab4..2240b6f 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Disambungkan"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Digantung"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Tidak diketahui"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Utama"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"bgksn"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bait"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 9dbce74..6114e94 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"ချိတ်ဆက်ထားသည်"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"ဆိုင်းငံ့ထားသည်"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"မသိရသေးပါ"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"အဓိက"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"ဘိုက်"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index a099240..2957043 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Tilkoblet"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Sperret midlertidig"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Ukjent"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Primær"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pakker"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"byte"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index d2ba6c3..f21bb2a 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"जडान गरियो"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"निलम्बित"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"अज्ञात"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"प्राथमिक"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"बाइटहरू"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index e7fa4d0..3820e52 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Verbonden"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Opgeschort"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Onbekend"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Primair"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pakketten"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bytes"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 89aa190..5db4c61 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"ସଂଯୋଗ କରାଯାଇଛି"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"ନିଲମ୍ବନ କରାଯାଇଛି"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"ଅଜଣା"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"ପ୍ରାଥମିକ"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"ପ୍ୟାକେଟ୍"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"ବାଇଟ୍ସ"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 40bf12a..8a44ab8 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"ਕਨੈਕਟ ਹੈ"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"ਮੁਅੱਤਲ ਕੀਤਾ ਗਿਆ"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"ਅਗਿਆਤ"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"ਪ੍ਰਾਇਮਰੀ"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"ਬਾਈਟਾਂ"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index d9774d9..cd9e7a6 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Połączono"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Zawieszone"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Brak informacji"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Główny"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"– pakiety"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"B"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index c8ce62f..4e19fc0 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Ligado"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Suspenso"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Desconhecido"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Principal"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bytes"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 6cbc051..38109a8 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Conectado"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Suspenso"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Desconhecido"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Principal"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bytes"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 90f918e..df11b3f 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Conectat"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Suspendat"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Necunoscut"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Principal"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pachete"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"byți"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 9df5817..88059d8 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Подключено"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Заблокировано"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Неизвестно"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Основной"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"байт"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 97b09d7..f04a45f 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"සම්බන්ධිතයි"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"අත්හිටුවා ඇත"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"නොදන්නා"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"මූලික"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"බයිට"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index b084876..faf16d4 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Pripojené"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Pozastavené"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Neznáme"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Primárne"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pakety"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"B"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index ff14a87..71e47d8 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Povezano"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Onemogočeno"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Neznano"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Glavno"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"B"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 6866372..ce593ed 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -660,7 +660,7 @@
<string name="description_dialpad_button" msgid="7395114120463883623">"shfaq bllokun e formimit të numrit"</string>
<string name="pane_title_emergency_dialpad" msgid="3627372514638694401">"Blloku i formimit të numrit të urgjencës"</string>
<string name="voicemail_visual_voicemail_switch_title" msgid="6610414098912832120">"Posta zanore vizuale"</string>
- <string name="voicemail_set_pin_dialog_title" msgid="7005128605986960003">"Konfiguro kodin PIN"</string>
+ <string name="voicemail_set_pin_dialog_title" msgid="7005128605986960003">"Cakto kodin PIN"</string>
<string name="voicemail_change_pin_dialog_title" msgid="4633077715231764435">"Ndrysho kodin PIN"</string>
<string name="preference_category_ringtone" msgid="8787281191375434976">"Me zile dhe me dridhje"</string>
<string name="pstn_connection_service_label" msgid="9200102709997537069">"Kartat e integruara SIM"</string>
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Lidhur"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Pezulluar"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"E panjohur"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Kryesore"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"paketa"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bajte"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 5a409f1..34892f3 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Повезано"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Суспендовано"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Непознато"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Примарно"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"пак."</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"бајт(ов)а"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index f64d1bc..cf5ba2a 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Ansluten"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Tillfälligt avstängt"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Okänt"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Primär"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"paket"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bytes"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 849691e..285f910 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Imeunganishwa"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Imesimamishwa"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Haijulikani"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Msingi"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"baiti"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index c782c0f..4919c99 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"இணைக்கப்பட்டுள்ளது"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"இடைநீக்கப்பட்டது"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"தெரியாதது"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"முதன்மை"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"பைட்டுகள்"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 0924ae7..80e077a 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -30,7 +30,7 @@
<string name="mmiStarted" msgid="9212975136944568623">"MMI కోడ్ ప్రారంభించబడింది"</string>
<string name="ussdRunning" msgid="1163586813106772717">"USSD కోడ్ అమలు చేయబడుతోంది…"</string>
<string name="mmiCancelled" msgid="5339191899200678272">"MMI కోడ్ రద్దు చేయబడింది"</string>
- <string name="cancel" msgid="8984206397635155197">"రద్దు చేయి"</string>
+ <string name="cancel" msgid="8984206397635155197">"రద్దు చేయండి"</string>
<string name="enter_input" msgid="6193628663039958990">"USSD మెసేజ్ తప్పనిసరిగా <xliff:g id="MIN_LEN">%1$d</xliff:g> మరియు <xliff:g id="MAX_LEN">%2$d</xliff:g> అక్షరాల మధ్య ఉండాలి. దయచేసి మళ్లీ ప్రయత్నించండి."</string>
<string name="manageConferenceLabel" msgid="8415044818156353233">"కాన్ఫరెన్స్ కాల్ను నిర్వహించండి"</string>
<string name="ok" msgid="7818974223666140165">"సరే"</string>
@@ -96,7 +96,7 @@
<string name="sum_loading_settings" msgid="434063780286688775">"సెట్టింగ్లను లోడ్ చేస్తోంది…"</string>
<string name="sum_hide_caller_id" msgid="131100328602371933">"అవుట్గోయింగ్ కాల్స్లో నంబర్ దాచబడుతుంది"</string>
<string name="sum_show_caller_id" msgid="3571854755324664591">"అవుట్గోయింగ్ కాల్స్లో నంబర్ ప్రదర్శించబడుతుంది"</string>
- <string name="sum_default_caller_id" msgid="1767070797135682959">"అవుట్గోయింగ్ కాల్స్లో నా నంబర్ను ప్రదర్శించడానికి ఆటోమేటిక్ ఆపరేటర్ సెట్టింగ్లను ఉపయోగించు"</string>
+ <string name="sum_default_caller_id" msgid="1767070797135682959">"అవుట్గోయింగ్ కాల్స్లో నా నంబర్ను ప్రదర్శించడానికి ఆటోమేటిక్ ఆపరేటర్ సెట్టింగ్లను ఉపయోగించండి"</string>
<string name="labelCW" msgid="8449327023861428622">"కాల్ నిరీక్షణ"</string>
<string name="sum_cw_enabled" msgid="3977308526187139996">"కాల్ సమయంలో, ఇన్కమింగ్ కాల్స్ల గురించి నాకు తెలియజేయి"</string>
<string name="sum_cw_disabled" msgid="3658094589461768637">"కాల్ సమయంలో, ఇన్కమింగ్ కాల్స్ల గురించి నాకు తెలియజేయి"</string>
@@ -104,7 +104,7 @@
<string name="call_forwarding_settings_with_label" msgid="2345432813399564272">"కాల్ ఫార్వార్డింగ్ సెట్టింగ్లు (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
<string name="labelCF" msgid="3578719437928476078">"కాల్ ఫార్వార్డింగ్"</string>
<string name="labelCFU" msgid="8870170873036279706">"ఎల్లప్పుడూ ఫార్వర్డ్ చేయి"</string>
- <string name="messageCFU" msgid="1361806450979589744">"ఎల్లప్పుడూ ఈ నంబర్ను ఉపయోగించు"</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_no_number" msgid="7287752761743377930">"నంబర్ అందుబాటులో లేదు"</string>
@@ -128,7 +128,7 @@
<string name="cdma_call_waiting" msgid="4565070960879673216">"కాల్ వెయిటింగ్ను ఆన్ చేయాలా?"</string>
<string name="enable_cdma_call_waiting_setting" msgid="5906811747921744307">"మీరు కాల్స్లో ఉండగా, ఇన్కమింగ్ కాల్స్ల గురించి మీకు తెలియజేయబడుతుంది"</string>
<string name="enable_cdma_cw" msgid="811047045863422232">"ఆన్ చేయి"</string>
- <string name="disable_cdma_cw" msgid="7119290446496301734">"రద్దు చేయి"</string>
+ <string name="disable_cdma_cw" msgid="7119290446496301734">"రద్దు చేయండి"</string>
<string name="cdma_call_waiting_in_ims_on" msgid="6390979414188659218">"IMSలో CDMA కాల్ వెయిటింగ్ ఆన్లో ఉంది"</string>
<string name="cdma_call_waiting_in_ims_off" msgid="1099246114368636334">"IMSలో CDMA కాల్ వెయిటింగ్ ఆఫ్లో ఉంది"</string>
<string name="updating_title" msgid="6130548922615719689">"కాల్ సెట్టింగ్లు"</string>
@@ -273,7 +273,7 @@
<string name="network_operator_category" msgid="4992217193732304680">"నెట్వర్క్"</string>
<string name="enhanced_4g_lte_mode_title" msgid="4213420368777080540">"మెరుగుపరిచిన 4G LTE మోడ్"</string>
<!-- no translation found for enhanced_4g_lte_mode_title_variant:0 (7240155150166394308) -->
- <string name="enhanced_4g_lte_mode_summary" msgid="7725708511804143638">"వాయిస్, ఇతర కమ్యూనికే. మెరుగుపరచడానికి LTE సేవలను ఉపయోగించు (సిఫార్సు చేయబడింది)"</string>
+ <string name="enhanced_4g_lte_mode_summary" msgid="7725708511804143638">"వాయిస్, ఇతర కమ్యూనికే. మెరుగుపరచడానికి LTE సేవలను ఉపయోగించండి (సిఫార్సు చేయబడింది)"</string>
<string name="enhanced_4g_lte_mode_summary_o2" msgid="2521108446409016542">"వాయిస్, ఇతర కమ్యూనికేషన్లను మెరుగుపరచడానికి 4G సేవలను ఉపయోగించండి (సిఫార్సు చేయబడింది)"</string>
<!-- no translation found for enhanced_4g_lte_mode_sumary_variant:0 (2943982616649705147) -->
<!-- no translation found for enhanced_4g_lte_mode_sumary_variant:1 (5262249464504131443) -->
@@ -465,7 +465,7 @@
<string name="get_pin2" msgid="4221654606863196332">"PIN2ని టైప్ చేయండి"</string>
<string name="name" msgid="1347432469852527784">"పేరు"</string>
<string name="number" msgid="1564053487748491000">"నంబర్"</string>
- <string name="save" msgid="983805790346099749">"సేవ్ చేయి"</string>
+ <string name="save" msgid="983805790346099749">"సేవ్ చేయండి"</string>
<string name="add_fdn_contact" msgid="1169713422306640887">"ఫిక్స్డ్ డయలింగ్ నంబర్ను జోడించండి"</string>
<string name="adding_fdn_contact" msgid="3112531600824361259">"ఫిక్స్డ్ డయలింగ్ నంబర్ను జోడిస్తోంది..."</string>
<string name="fdn_contact_added" msgid="2840016151693394596">"ఫిక్స్డ్ డయలింగ్ నంబర్ జోడించబడింది."</string>
@@ -685,7 +685,7 @@
<string name="callFailed_wfc_service_not_available_in_this_location" msgid="3624536608369524988">"ఈ లొకేషన్లో Wi-Fi కాలింగ్ అందుబాటులో లేదు."</string>
<string name="change_pin_title" msgid="3564254326626797321">"వాయిస్ మెయిల్ PINని మార్చండి"</string>
<string name="change_pin_continue_label" msgid="5177011752453506371">"కొనసాగించండి"</string>
- <string name="change_pin_cancel_label" msgid="2301711566758827936">"రద్దు చేయి"</string>
+ <string name="change_pin_cancel_label" msgid="2301711566758827936">"రద్దు చేయండి"</string>
<string name="change_pin_ok_label" msgid="6861082678817785330">"సరే"</string>
<string name="change_pin_enter_old_pin_header" msgid="853151335217594829">"మీ పాత PINని నిర్ధారించండి"</string>
<string name="change_pin_enter_old_pin_hint" msgid="8801292976275169367">"కొనసాగించడానికి మీ వాయిస్ మెయిల్ PINని నమోదు చేయండి."</string>
@@ -708,7 +708,7 @@
<string name="mobile_data_activate_diag_title" msgid="5401741936224757312">"డేటాను జోడించాలా?"</string>
<string name="mobile_data_activate_diag_message" msgid="3527260988020415441">"మీరు <xliff:g id="PROVIDER_NAME">%s</xliff:g> ద్వారా డేటాను జోడించాల్సి ఉండవచ్చు"</string>
<string name="mobile_data_activate_button" msgid="1139792516354374612">"డేటాను జోడించండి"</string>
- <string name="mobile_data_activate_cancel_button" msgid="3530174817572005860">"రద్దు చేయి"</string>
+ <string name="mobile_data_activate_cancel_button" msgid="3530174817572005860">"రద్దు చేయండి"</string>
<string name="clh_card_title_call_ended_txt" msgid="5977978317527299698">"కాల్ ముగిసింది"</string>
<string name="clh_callFailed_powerOff_txt" msgid="8279934912560765361">"విమానం మోడ్ ఆన్లో ఉంది"</string>
<string name="clh_callFailed_simError_txt" msgid="5128538525762326413">"SIM కార్డ్ని యాక్సెస్ చేయడం సాధ్యపడలేదు"</string>
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"కనెక్ట్ చేయబడింది"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"తాత్కాలికంగా నిలిపివేయబడింది"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"తెలియదు"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"ప్రాథమిక"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"బైట్లు"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
@@ -900,7 +901,7 @@
<string name="ping_test_label" msgid="448617502935719694">"పింగ్ పరీక్షను అమలు చేయండి"</string>
<string name="radio_info_smsc_label" msgid="3749927072726033763">"SMSC:"</string>
<string name="radio_info_smsc_update_label" msgid="5141996256097115753">"అప్డేట్ చేయండి"</string>
- <string name="radio_info_smsc_refresh_label" msgid="8409923721451604560">"రిఫ్రెష్ చేయి"</string>
+ <string name="radio_info_smsc_refresh_label" msgid="8409923721451604560">"రిఫ్రెష్ చేయండి"</string>
<string name="radio_info_toggle_dns_check_label" msgid="1394078554927787350">"DNS తనిఖీని టోగుల్ చేయండి"</string>
<string name="oem_radio_info_label" msgid="2914167475119997456">"OEM-నిర్దిష్ట సమాచారం/సెట్టింగ్లు"</string>
<string name="radio_info_endc_available" msgid="2983767110681230019">"EN-DC అందుబాటులో ఉన్న (NSA):"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index d8640f8..0f990bf 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"เชื่อมต่อแล้ว"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"ถูกระงับ"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"ไม่รู้จัก"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"หลัก"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"ไบต์"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 08df78b..eae12df 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -511,7 +511,7 @@
<string name="invalidPuk2" msgid="713729511903849544">"Maglagay ng PUK2 na 8 numero."</string>
<string name="pin2_changed" msgid="5710551850481287821">"Na-update na ang PIN2"</string>
<string name="label_puk2_code" msgid="2852217004288085562">"Ilagay ang PUK2 code"</string>
- <string name="fdn_enable_puk2_requested" msgid="5793652792131588041">"Mali ang password. Naka-block na ngayon ang PIN2. Upang subukang muli, baguhin ang PIN 2."</string>
+ <string name="fdn_enable_puk2_requested" msgid="5793652792131588041">"Mali ang password. Naka-block na ngayon ang PIN2. Upang subukan ulit, baguhin ang PIN 2."</string>
<string name="puk2_requested" msgid="6992374450720307514">"Mali ang password. Naka-lock na ngayon ang SIM. Ilagay ang PUK2."</string>
<string name="puk2_blocked" msgid="3131139031779319911">"Permanenteng na-block ang PUK2."</string>
<string name="pin2_attempts" msgid="5625178102026453023">\n"Mayroon ka na lang <xliff:g id="NUMBER">%d</xliff:g> (na) natitirang pagsubok."</string>
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Konektado"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Sinuspinde"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Hindi alam"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Pangunahin"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bytes"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 66ddb7f..1afe088 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Bağlı"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Askıya alındı"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Bilinmiyor"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Birincil"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkt"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bayt"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 16322ba..c2626c7 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Підключено"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Заблоковано"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Невідомо"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Основний"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"пак."</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"байт"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"дБм"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 1b0fbbf..0250039 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"منسلک"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"معطل کر دیا گیا"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"نامعلوم"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"بنیادی"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"پیکٹس"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"بائٹس"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index f8f663f..1577a55 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Ulangan"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Bloklangan"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Noma’lum"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Asosiy"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"bayt"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 186448a..caafd7a 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Đã kết nối"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Bị tạm ngưng"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Không xác định"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Chính"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"byte"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index acee999..58d0344 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"已连接"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"已暂停"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"未知"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"主要"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"字节"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 7923cbb..208d7d3 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"已連線"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"已停用"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"不明"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"主要"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkt"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"位元組"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index c43183c..7bcd733 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"已連線"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"待命"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"不明"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"主要"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"pkts"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"位元組"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index d111a5e..1fb675f 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -862,6 +862,7 @@
<string name="radioInfo_data_connected" msgid="7637335645634239508">"Ixhunyiwe"</string>
<string name="radioInfo_data_suspended" msgid="8695262782642002785">"Kumiswe okwesikhashana"</string>
<string name="radioInfo_unknown" msgid="5401423738500672850">"Akwaziwa"</string>
+ <string name="radioInfo_imei_primary" msgid="5948747378637224400">"Okuyinhloko"</string>
<string name="radioInfo_display_packets" msgid="6794302192441084157">"amaphakethe"</string>
<string name="radioInfo_display_bytes" msgid="7701006329222413797">"amabhaythi"</string>
<string name="radioInfo_display_dbm" msgid="7491944975710865703">"dBm"</string>
diff --git a/src/com/android/phone/EmergencyCallbackModeExitDialog.java b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
index fc0e513..6901789 100644
--- a/src/com/android/phone/EmergencyCallbackModeExitDialog.java
+++ b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
@@ -43,6 +43,8 @@
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.domainselection.DomainSelectionResolver;
+import com.android.internal.telephony.emergency.EmergencyStateTracker;
import java.util.HashMap;
import java.util.Map;
@@ -244,9 +246,16 @@
.setMessage(text)
.setPositiveButton(R.string.alert_dialog_yes,
new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog,int whichButton) {
+ public void onClick(DialogInterface dialog,
+ int whichButton) {
// User clicked Yes. Exit Emergency Callback Mode.
- mPhone.exitEmergencyCallbackMode();
+ if (DomainSelectionResolver.getInstance()
+ .isDomainSelectionSupported()) {
+ EmergencyStateTracker.getInstance()
+ .exitEmergencyCallbackMode();
+ } else {
+ mPhone.exitEmergencyCallbackMode();
+ }
// Show progress dialog
showDialog(EXIT_ECM_PROGRESS_DIALOG);
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index ff4dcfe..ccef4d8 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -31,6 +31,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.app.PropertyInvalidatedCache;
@@ -71,6 +72,7 @@
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.provider.Telephony;
+import android.service.carrier.CarrierIdentifier;
import android.sysprop.TelephonyProperties;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
@@ -222,6 +224,7 @@
import com.android.phone.callcomposer.ImageData;
import com.android.phone.settings.PickSmsSubscriptionActivity;
import com.android.phone.slice.SlicePurchaseController;
+import com.android.phone.utils.CarrierAllowListInfo;
import com.android.phone.vvm.PhoneAccountHandleConverter;
import com.android.phone.vvm.RemoteVvmTaskManager;
import com.android.phone.vvm.VisualVoicemailSettingsUtil;
@@ -373,7 +376,6 @@
private static final int EVENT_IS_VONR_ENABLED_DONE = 116;
private static final int CMD_PURCHASE_PREMIUM_CAPABILITY = 117;
private static final int EVENT_PURCHASE_PREMIUM_CAPABILITY_DONE = 118;
-
// Parameters of select command.
private static final int SELECT_COMMAND = 0xA4;
private static final int SELECT_P1 = 0x04;
@@ -436,6 +438,8 @@
private static final int SET_NETWORK_SELECTION_MODE_AUTOMATIC_TIMEOUT_MS = 2000; // 2 seconds
+ private static final int MODEM_ACTIVITY_TIME_OFFSET_CORRECTION_MS = 50;
+
/**
* With support for MEP(multiple enabled profile) in Android T, a SIM card can have more than
* one ICCID active at the same time.
@@ -489,13 +493,11 @@
private static final class PurchasePremiumCapabilityArgument {
public @TelephonyManager.PremiumCapability int capability;
- public @NonNull String appName;
public @NonNull IIntegerConsumer callback;
PurchasePremiumCapabilityArgument(@TelephonyManager.PremiumCapability int capability,
- @NonNull String appName, @NonNull IIntegerConsumer callback) {
+ @NonNull IIntegerConsumer callback) {
this.capability = capability;
- this.appName = appName;
this.callback = callback;
}
}
@@ -1467,6 +1469,8 @@
ModemActivityInfo info = (ModemActivityInfo) ar.result;
if (isModemActivityInfoValid(info)) {
mergeModemActivityInfo(info);
+ } else {
+ loge("queryModemActivityInfo: invalid response");
}
// This is needed to decouple ret from mLastModemActivityInfo
// We don't want to return mLastModemActivityInfo which is updated
@@ -1558,7 +1562,39 @@
loge("getAllowedCarriers: Unknown exception");
}
}
- notifyRequester(request);
+ if (request.argument != null) {
+ // This is for the implementation of carrierRestrictionStatus.
+ CallerCallbackInfo callbackInfo = (CallerCallbackInfo) request.argument;
+ Consumer<Integer> callback = callbackInfo.getConsumer();
+ int callerCarrierId = callbackInfo.getCarrierId();
+ int lockStatus = TelephonyManager.CARRIER_RESTRICTION_STATUS_UNKNOWN;
+ if (ar.exception == null && ar.result instanceof CarrierRestrictionRules) {
+ CarrierRestrictionRules carrierRestrictionRules =
+ (CarrierRestrictionRules) ar.result;
+ int carrierId = -1;
+ try {
+ CarrierIdentifier carrierIdentifier =
+ carrierRestrictionRules.getAllowedCarriers().get(0);
+ carrierId = CarrierResolver.getCarrierIdFromIdentifier(mApp,
+ carrierIdentifier);
+ } catch (NullPointerException | IndexOutOfBoundsException ex) {
+ Rlog.e(LOG_TAG, "CarrierIdentifier exception = " + ex);
+ }
+ lockStatus = carrierRestrictionRules.getCarrierRestrictionStatus();
+ if (carrierId != -1 && callerCarrierId == carrierId && lockStatus
+ == TelephonyManager.CARRIER_RESTRICTION_STATUS_RESTRICTED) {
+ lockStatus =
+ TelephonyManager.CARRIER_RESTRICTION_STATUS_RESTRICTED_TO_CALLER;
+ }
+ } else {
+ Rlog.e(LOG_TAG,
+ "getCarrierRestrictionStatus: exception ex = " + ar.exception);
+ }
+ callback.accept(lockStatus);
+ } else {
+ // This is for the implementation of getAllowedCarriers.
+ notifyRequester(request);
+ }
break;
case EVENT_GET_FORBIDDEN_PLMNS_DONE:
@@ -2177,7 +2213,7 @@
PurchasePremiumCapabilityArgument arg =
(PurchasePremiumCapabilityArgument) request.argument;
SlicePurchaseController.getInstance(request.phone).purchasePremiumCapability(
- arg.capability, arg.appName, onCompleted);
+ arg.capability, onCompleted);
break;
}
@@ -2422,10 +2458,10 @@
mRadioInterfaceCapabilities = RadioInterfaceCapabilityController.getInstance();
mNotifyUserActivity = new AtomicBoolean(false);
PropertyInvalidatedCache.invalidateCache(TelephonyManager.CACHE_KEY_PHONE_ACCOUNT_TO_SUBID);
- mTelephony2gUpdater = new Telephony2gUpdater(
- Executors.newSingleThreadExecutor(), mApp);
+ mTelephony2gUpdater = new Telephony2gUpdater(mApp);
mTelephony2gUpdater.init();
publish();
+ CarrierAllowListInfo.loadInstance(mApp);
}
@VisibleForTesting
@@ -2433,7 +2469,11 @@
return mTelephonySharedPreferences;
}
- private Phone getDefaultPhone() {
+ /**
+ * Get the default phone for this device.
+ */
+ @VisibleForTesting
+ public Phone getDefaultPhone() {
Phone thePhone = getPhone(getDefaultSubscription());
return (thePhone != null) ? thePhone : PhoneFactory.getDefaultPhone();
}
@@ -2460,6 +2500,20 @@
? getDefaultPhone() : getPhone(subId);
}
+ /**
+ * Get phone object associated with a subscription.
+ * Return default phone if phone object associated with subscription is null
+ * @param subId - subscriptionId
+ * @return phone object associated with a subscription or default phone if null.
+ */
+ private Phone getPhoneFromSubIdOrDefault(int subId) {
+ Phone phone = getPhoneFromSubId(subId);
+ if (phone == null) {
+ phone = getDefaultPhone();
+ }
+ return phone;
+ }
+
@Nullable
private UiccPort getUiccPortFromRequest(@NonNull MainThreadRequest request) {
Phone phone = getPhoneFromRequest(request);
@@ -3675,13 +3729,23 @@
}
/**
- * Make sure the caller has the MODIFY_PHONE_STATE permission.
+ * Make sure the caller has the READ_PHONE_STATE permission.
*
* @throws SecurityException if the caller does not have the required permission
*/
@VisibleForTesting
public void enforceReadPermission() {
- mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, null);
+ enforceReadPermission(null);
+ }
+
+ /**
+ * Make sure the caller has the READ_PHONE_STATE permissions.
+ *
+ * @throws SecurityException if the caller does not have the READ_PHONE_STATE permission.
+ */
+ @VisibleForTesting
+ public void enforceReadPermission(String msg) {
+ mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, msg);
}
private void enforceActiveEmergencySessionPermission() {
@@ -4379,7 +4443,18 @@
try {
int slotId = getSlotIndexOrException(subId);
verifyImsMmTelConfiguredOrThrow(slotId);
- ImsManager.getInstance(mApp, slotId).addCapabilitiesCallbackForSubscription(c, subId);
+
+ ImsStateCallbackController controller = ImsStateCallbackController.getInstance();
+ if (controller != null) {
+ ImsManager imsManager = controller.getImsManager(subId);
+ if (imsManager != null) {
+ imsManager.addCapabilitiesCallbackForSubscription(c, subId);
+ } else {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ } else {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
+ }
} catch (ImsException e) {
throw new ServiceSpecificException(e.getCode());
} finally {
@@ -4402,13 +4477,18 @@
final long token = Binder.clearCallingIdentity();
try {
- ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
- .removeCapabilitiesCallbackForSubscription(c, subId);
- } catch (ImsException e) {
- Log.i(LOG_TAG, "unregisterMmTelCapabilityCallback: " + subId
- + "is inactive, ignoring unregister.");
- // If the subscription is no longer active, just return, since the callback
- // will already have been removed internally.
+ ImsStateCallbackController controller = ImsStateCallbackController.getInstance();
+ if (controller != null) {
+ ImsManager imsManager = controller.getImsManager(subId);
+ if (imsManager != null) {
+ imsManager.removeCapabilitiesCallbackForSubscription(c, subId);
+ } else {
+ Log.i(LOG_TAG, "unregisterMmTelCapabilityCallback: " + subId
+ + " is inactive, ignoring unregister.");
+ // If the ImsManager is not valid, just return, since the callback
+ // will already have been removed internally.
+ }
+ }
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -4819,8 +4899,18 @@
}
int slotId = getSlotIndexOrException(subId);
verifyImsMmTelConfiguredOrThrow(slotId);
- ImsManager.getInstance(mApp, slotId)
- .addProvisioningCallbackForSubscription(callback, subId);
+
+ ImsStateCallbackController controller = ImsStateCallbackController.getInstance();
+ if (controller != null) {
+ ImsManager imsManager = controller.getImsManager(subId);
+ if (imsManager != null) {
+ imsManager.addProvisioningCallbackForSubscription(callback, subId);
+ } else {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ } else {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
+ }
} catch (ImsException e) {
throw new ServiceSpecificException(e.getCode());
} finally {
@@ -4837,13 +4927,18 @@
throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
}
try {
- ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
- .removeProvisioningCallbackForSubscription(callback, subId);
- } catch (ImsException e) {
- Log.i(LOG_TAG, "unregisterImsProvisioningChangedCallback: " + subId
- + "is inactive, ignoring unregister.");
- // If the subscription is no longer active, just return, since the callback will already
- // have been removed internally.
+ ImsStateCallbackController controller = ImsStateCallbackController.getInstance();
+ if (controller != null) {
+ ImsManager imsManager = controller.getImsManager(subId);
+ if (imsManager != null) {
+ imsManager.removeProvisioningCallbackForSubscription(callback, subId);
+ } else {
+ Log.i(LOG_TAG, "unregisterImsProvisioningChangedCallback: " + subId
+ + " is inactive, ignoring unregister.");
+ // If the ImsManager is not valid, just return, since the callback will already
+ // have been removed internally.
+ }
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -8019,7 +8114,7 @@
}
}
- // Checks that ModemActivityInfo is valid. Sleep time, Idle time, Rx time and Tx time should be
+ // Checks that ModemActivityInfo is valid. Sleep time and Idle time should be
// less than total activity duration.
private boolean isModemActivityInfoValid(ModemActivityInfo info) {
if (info == null) {
@@ -8027,13 +8122,13 @@
}
int activityDurationMs =
(int) (info.getTimestampMillis() - mLastModemActivityInfo.getTimestampMillis());
+ activityDurationMs += MODEM_ACTIVITY_TIME_OFFSET_CORRECTION_MS;
+
int totalTxTimeMs = Arrays.stream(info.getTransmitTimeMillis()).sum();
return (info.isValid()
&& (info.getSleepTimeMillis() <= activityDurationMs)
- && (info.getIdleTimeMillis() <= activityDurationMs)
- && (info.getReceiveTimeMillis() <= activityDurationMs)
- && (totalTxTimeMs <= activityDurationMs));
+ && (info.getIdleTimeMillis() <= activityDurationMs));
}
private void updateLastModemActivityInfo(ModemActivityInfo info, int rat, int freq) {
@@ -8351,7 +8446,8 @@
*
* @throws SecurityException if the caller does not have the required permission
*/
- private void enforceReadPrivilegedPermission(String message) {
+ @VisibleForTesting
+ public void enforceReadPrivilegedPermission(String message) {
mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
message);
}
@@ -8561,6 +8657,38 @@
}
/**
+ * Fetches the carrier restriction status of the device and sends the status to the caller
+ * through the callback.
+ *
+ * @param callback The callback that will be used to send the result.
+ * @throws SecurityException if the caller does not have the required permission/privileges or
+ * the caller is not allowlisted.
+ */
+ @Override
+ public void getCarrierRestrictionStatus(IIntegerConsumer callback, String packageName) {
+ enforceReadPermission("getCarrierRestrictionStatus");
+ int carrierId = validateCallerAndGetCarrierId(packageName);
+ if (carrierId == CarrierAllowListInfo.INVALID_CARRIER_ID) {
+ Rlog.e(LOG_TAG, "getCarrierRestrictionStatus: caller is not registered");
+ throw new SecurityException("Not an authorized caller");
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ Consumer<Integer> consumer = FunctionalUtils.ignoreRemoteException(callback::accept);
+ CallerCallbackInfo callbackInfo = new CallerCallbackInfo(consumer, carrierId);
+ sendRequestAsync(CMD_GET_ALLOWED_CARRIERS, callbackInfo);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @VisibleForTesting
+ public int validateCallerAndGetCarrierId(String packageName) {
+ CarrierAllowListInfo allowListInfo = CarrierAllowListInfo.loadInstance(mApp);
+ return allowListInfo.validateCallerAndGetCarrierId(packageName);
+ }
+
+ /**
* Action set from carrier signalling broadcast receivers to enable/disable radio
* @param subId the subscription ID that this action applies to.
* @param enabled control enable or disable radio.
@@ -10187,8 +10315,9 @@
throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
}
if (!isImsAvailableOnDevice()) {
- throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
- "IMS not available on device.");
+ // ProvisioningManager can not handle ServiceSpecificException.
+ // Throw the IllegalStateException and annotate ProvisioningManager.
+ throw new IllegalStateException("IMS not available on device.");
}
final long identity = Binder.clearCallingIdentity();
@@ -10787,8 +10916,9 @@
throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
}
if (!isImsAvailableOnDevice()) {
- throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
- "IMS not available on device.");
+ // operation failed silently
+ Rlog.w(LOG_TAG, "IMS not available on device.");
+ return;
}
final long identity = Binder.clearCallingIdentity();
@@ -10812,8 +10942,9 @@
throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
}
if (!isImsAvailableOnDevice()) {
- throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
- "IMS not available on device.");
+ // ProvisioningManager can not handle ServiceSpecificException.
+ // Throw the IllegalStateException and annotate ProvisioningManager.
+ throw new IllegalStateException("IMS not available on device.");
}
final long identity = Binder.clearCallingIdentity();
@@ -11443,6 +11574,12 @@
+ " failed due to missing permissions.");
throw new SecurityException("purchasePremiumCapability requires permission "
+ "READ_BASIC_PHONE_STATE.");
+ } else if (!TelephonyPermissions.checkInternetPermissionNoThrow(
+ mApp, "purchasePremiumCapability")) {
+ log("purchasePremiumCapability "
+ + TelephonyManager.convertPremiumCapabilityToString(capability)
+ + " failed due to missing permissions.");
+ throw new SecurityException("purchasePremiumCapability requires permission INTERNET.");
}
Phone phone = getPhone(subId);
@@ -11461,15 +11598,50 @@
}
return;
}
- String appName;
+
+ String callingProcess;
try {
- appName = mApp.getPackageManager().getApplicationLabel(mApp.getPackageManager()
- .getApplicationInfo(getCurrentPackageName(), 0)).toString();
+ callingProcess = mApp.getPackageManager().getApplicationInfo(
+ getCurrentPackageName(), 0).processName;
} catch (PackageManager.NameNotFoundException e) {
- appName = "An application";
+ callingProcess = getCurrentPackageName();
}
+
+ boolean isVisible = false;
+ ActivityManager am = mApp.getSystemService(ActivityManager.class);
+ if (am != null) {
+ List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
+ if (processes != null) {
+ for (ActivityManager.RunningAppProcessInfo process : processes) {
+ log("purchasePremiumCapability: process " + process.processName
+ + "has importance " + process.importance);
+ if (process.processName.equals(callingProcess) && process.importance
+ <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
+ isVisible = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!isVisible) {
+ try {
+ int result = TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_FOREGROUND;
+ callback.accept(result);
+ loge("purchasePremiumCapability: " + callingProcess + " is not in the foreground.");
+ } catch (RemoteException e) {
+ String logStr = "Purchase premium capability "
+ + TelephonyManager.convertPremiumCapabilityToString(capability)
+ + " failed due to RemoteException handling background application: " + e;
+ if (DBG) log(logStr);
+ AnomalyReporter.reportAnomaly(
+ UUID.fromString(PURCHASE_PREMIUM_CAPABILITY_ERROR_UUID), logStr);
+ }
+ return;
+ }
+
sendRequestAsync(CMD_PURCHASE_PREMIUM_CAPABILITY,
- new PurchasePremiumCapabilityArgument(capability, appName, callback), phone, null);
+ new PurchasePremiumCapabilityArgument(capability, callback), phone, null);
}
/**
@@ -11690,7 +11862,8 @@
boolean updateIfNeeded) {
enforceInteractAcrossUsersPermission("getDefaultRespondViaMessageApplication");
- Context context = getPhone(subId).getContext();
+ Context context = getPhoneFromSubIdOrDefault(subId).getContext();
+
UserHandle userHandle = null;
final long identity = Binder.clearCallingIdentity();
try {
@@ -11751,6 +11924,10 @@
throw new UnsupportedOperationException(
"Null cipher and integrity operations require HAL 2.1 or above");
}
+ if (!getDefaultPhone().isNullCipherAndIntegritySupported()) {
+ throw new UnsupportedOperationException(
+ "Null cipher and integrity operations unsupported by modem");
+ }
}
/**
@@ -11874,4 +12051,25 @@
}
return false;
}
+
+ /**
+ * Class binds the consumer[callback] and carrierId.
+ */
+ private static class CallerCallbackInfo {
+ private final Consumer<Integer> mConsumer;
+ private final int mCarrierId;
+
+ public CallerCallbackInfo(Consumer<Integer> consumer, int carrierId) {
+ mConsumer = consumer;
+ mCarrierId = carrierId;
+ }
+
+ public Consumer<Integer> getConsumer() {
+ return mConsumer;
+ }
+
+ public int getCarrierId() {
+ return mCarrierId;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/com/android/phone/Telephony2gUpdater.java b/src/com/android/phone/Telephony2gUpdater.java
index 0919385..baaa684 100644
--- a/src/com/android/phone/Telephony2gUpdater.java
+++ b/src/com/android/phone/Telephony2gUpdater.java
@@ -30,8 +30,13 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.RILConstants;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
/**
* A {@link BroadcastReceiver} that ensures that user restrictions are correctly applied to
@@ -39,27 +44,50 @@
* This includes handling broadcasts from user restriction state changes, as well as ensuring that
* SIM-specific settings are correctly applied when new subscriptions become active.
*
+ * <p>
* Callers are expected to call {@code init()} and keep an instance of this class alive.
+ * </p>
*/
public class Telephony2gUpdater extends BroadcastReceiver {
- private static final String TAG = "TelephonyUserManagerReceiver";
+ private static final String TAG = "Telephony2gUpdater";
// We can't interact with the HAL on the main thread of the phone process (where
// receivers are run by default), so we execute our logic from a separate thread.
+ // The correctness of this implementation relies heavily on this executor ensuring
+ // tasks are serially executed i.e. ExecutorService.newSingleThreadExecutor()
private final Executor mExecutor;
private final Context mContext;
private final long mBaseAllowedNetworks;
- public Telephony2gUpdater(Executor executor, Context context) {
- this(executor, context,
+ private UserManager mUserManager;
+ private TelephonyManager mTelephonyManager;
+ private SubscriptionManager mSubscriptionManager;
+
+ // The current subscription ids
+ // Ensure this value is never accessed concurrently
+ private Set<Integer> mCurrentSubscriptions;
+ // We keep track of the last value to avoid updating when unrelated user restrictions change
+ // Ensure this value is never accessed concurrently
+ private boolean mDisallowCellular2gRestriction;
+
+ public Telephony2gUpdater(Context context) {
+ this(Executors.newSingleThreadExecutor(), context,
RadioAccessFamily.getRafFromNetworkType(RILConstants.PREFERRED_NETWORK_MODE));
}
- public Telephony2gUpdater(Executor executor, Context context,
- long baseAllowedNetworks) {
+ @VisibleForTesting
+ public Telephony2gUpdater(Executor executor, Context context, long baseAllowedNetworks) {
mExecutor = executor;
mContext = context;
mBaseAllowedNetworks = baseAllowedNetworks;
+
+ mUserManager = mContext.getSystemService(UserManager.class);
+ mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+ mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
+
+ // All user restrictions are false by default
+ mDisallowCellular2gRestriction = false;
+ mCurrentSubscriptions = new HashSet<>();
}
/**
@@ -80,41 +108,42 @@
Log.i(TAG, "Received callback for action " + intent.getAction());
final PendingResult result = goAsync();
mExecutor.execute(() -> {
- Log.i(TAG, "Running handler for action " + intent.getAction());
- handleUserRestrictionsChanged(context);
- result.finish();
+ boolean disallow2g = mUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G);
+ if (mDisallowCellular2gRestriction == disallow2g) {
+ Log.i(TAG, "No update to DISALLOW_CELLULAR_2G restriction.");
+ return;
+ }
+
+ mDisallowCellular2gRestriction = disallow2g;
+
+ Log.i(TAG, "Running handler for all subscriptions based on DISALLOW_CELLULAR_2G change."
+ + " Restriction value: " + mDisallowCellular2gRestriction);
+ handleUserRestrictionsChanged(mCurrentSubscriptions);
+ if (result != null) {
+ result.finish();
+ }
});
}
/**
- * Update all active subscriptions with allowed network types depending on the current state
- * of the {@link UserManager.DISALLOW_2G}.
+ * Update subscriptions with allowed network types depending on the current state
+ * of the {@link UserManager#DISALLOW_CELLULAR_2G}.
+ *
+ * @param subIds A list of subIds to update.
*/
- @VisibleForTesting
- public void handleUserRestrictionsChanged(Context context) {
- UserManager um = context.getSystemService(UserManager.class);
- TelephonyManager tm = context.getSystemService(TelephonyManager.class);
- SubscriptionManager sm = context.getSystemService(SubscriptionManager.class);
+ private void handleUserRestrictionsChanged(Collection<Integer> subIds) {
final long twoGBitmask = TelephonyManager.NETWORK_CLASS_BITMASK_2G;
- boolean shouldDisable2g = um.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G);
-
- // This is expected when subscription info cannot be determined. We'll get another
- // callback in the future from our SubscriptionListener once we have valid subscriptions.
- List<SubscriptionInfo> subscriptionInfoList = sm.getAvailableSubscriptionInfoList();
- if (subscriptionInfoList == null) {
- return;
- }
-
long allowedNetworkTypes = mBaseAllowedNetworks;
// 2G device admin controls are global
- for (SubscriptionInfo info : subscriptionInfoList) {
- TelephonyManager telephonyManager = tm.createForSubscriptionId(
- info.getSubscriptionId());
- if (shouldDisable2g) {
+ for (Integer subId : subIds) {
+ TelephonyManager telephonyManager = mTelephonyManager.createForSubscriptionId(subId);
+ if (mDisallowCellular2gRestriction) {
+ Log.i(TAG, "Disabling 2g based on user restriction for subId: " + subId);
allowedNetworkTypes &= ~twoGBitmask;
} else {
+ Log.i(TAG, "Enabling 2g based on user restriction for subId: " + subId);
allowedNetworkTypes |= twoGBitmask;
}
telephonyManager.setAllowedNetworkTypesForReason(
@@ -126,8 +155,30 @@
private class SubscriptionListener extends SubscriptionManager.OnSubscriptionsChangedListener {
@Override
public void onSubscriptionsChanged() {
- Log.i(TAG, "Running handler for subscription change.");
- handleUserRestrictionsChanged(mContext);
+ // Note that this entire callback gets invoked in the single threaded executor
+ List<SubscriptionInfo> allSubscriptions =
+ mSubscriptionManager.getCompleteActiveSubscriptionInfoList();
+
+ HashSet<Integer> updatedSubIds = new HashSet<>(allSubscriptions.size());
+ List<Integer> newSubIds = new ArrayList<>();
+
+ for (SubscriptionInfo info : allSubscriptions) {
+ updatedSubIds.add(info.getSubscriptionId());
+ if (!mCurrentSubscriptions.contains(info.getSubscriptionId())) {
+ newSubIds.add(info.getSubscriptionId());
+ }
+ }
+
+ mCurrentSubscriptions = updatedSubIds;
+
+ if (newSubIds.isEmpty()) {
+ Log.d(TAG, "No new subIds. Skipping update.");
+ return;
+ }
+
+ Log.i(TAG, "New subscriptions found. Running handler to update 2g restrictions with "
+ + "subIds " + newSubIds.toString());
+ handleUserRestrictionsChanged(newSubIds);
}
}
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index fdaf1bb..f002e25 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -57,6 +57,7 @@
import com.android.internal.telephony.util.TelephonyUtils;
import com.android.modules.utils.BasicShellCommandHandler;
import com.android.phone.callcomposer.CallComposerPictureManager;
+import com.android.phone.utils.CarrierAllowListInfo;
import java.io.IOException;
import java.io.PrintWriter;
@@ -97,6 +98,8 @@
private static final String ENABLE = "enable";
private static final String DISABLE = "disable";
private static final String QUERY = "query";
+ private static final String CARRIER_RESTRICTION_STATUS_TEST = "carrier_restriction_status_test";
+ private final String QUOTES = "\"";
private static final String CALL_COMPOSER_TEST_MODE = "test-mode";
private static final String CALL_COMPOSER_SIMULATE_CALL = "simulate-outgoing-call";
@@ -341,6 +344,8 @@
return handleGetSimSlotsMapping();
case RADIO_SUBCOMMAND:
return handleRadioCommand();
+ case CARRIER_RESTRICTION_STATUS_TEST:
+ return handleCarrierRestrictionStatusCommand();
default: {
return handleDefaultCommands(cmd);
}
@@ -3011,4 +3016,74 @@
return -1;
}
+
+ private int handleCarrierRestrictionStatusCommand() {
+ try {
+ String MOCK_MODEM_SERVICE_NAME = "android.telephony.mockmodem.MockModemService";
+ if (!(checkShellUid() && MOCK_MODEM_SERVICE_NAME.equalsIgnoreCase(
+ mInterface.getModemService()))) {
+ Log.v(LOG_TAG,
+ "handleCarrierRestrictionStatusCommand, MockModem service check fails or "
+ + " checkShellUid fails");
+ return -1;
+ }
+ } catch (RemoteException ex) {
+ ex.printStackTrace();
+ }
+ String callerInfo = getNextOption();
+ CarrierAllowListInfo allowListInfo = CarrierAllowListInfo.loadInstance(mContext);
+ if (TextUtils.isEmpty(callerInfo)) {
+ // reset the Json content after testing
+ allowListInfo.updateJsonForTest(null);
+ return 0;
+ }
+ if (callerInfo.startsWith("--")) {
+ callerInfo = callerInfo.replace("--", "");
+ }
+ String params[] = callerInfo.split(",");
+ StringBuffer jsonStrBuffer = new StringBuffer();
+ String tokens;
+ for (int index = 0; index < params.length; index++) {
+ tokens = convertToJsonString(index, params[index]);
+ if (TextUtils.isEmpty(tokens)) {
+ // received wrong format from CTS
+ if (VDBG) {
+ Log.v(LOG_TAG,
+ "handleCarrierRestrictionStatusCommand, Shell command parsing error");
+ }
+ return -1;
+ }
+ jsonStrBuffer.append(tokens);
+ }
+ int result = allowListInfo.updateJsonForTest(jsonStrBuffer.toString());
+ return result;
+ }
+
+
+ /**
+ * Building the string that can be used to build the JsonObject which supports to stub the data
+ * in CarrierAllowListInfo for CTS testing. sample format is like
+ * {"com.android.example":{"carrierId":"10000","callerSHA1Id":["XXXXXXXXXXXXXX"]}}
+ */
+ private String convertToJsonString(int index, String param) {
+
+ String token[] = param.split(":");
+ String jSonString;
+ switch (index) {
+ case 0:
+ jSonString = "{" + QUOTES + token[1] + QUOTES + ":";
+ break;
+ case 1:
+ jSonString =
+ "{" + QUOTES + token[0] + QUOTES + ":" + QUOTES + token[1] + QUOTES + ",";
+ break;
+ case 2:
+ jSonString =
+ QUOTES + token[0] + QUOTES + ":" + "[" + QUOTES + token[1] + QUOTES + "]}}";
+ break;
+ default:
+ jSonString = null;
+ }
+ return jSonString;
+ }
}
diff --git a/src/com/android/phone/slice/SlicePurchaseController.java b/src/com/android/phone/slice/SlicePurchaseController.java
index 3864119..e36325e 100644
--- a/src/com/android/phone/slice/SlicePurchaseController.java
+++ b/src/com/android/phone/slice/SlicePurchaseController.java
@@ -40,6 +40,7 @@
import android.os.Message;
import android.os.PersistableBundle;
import android.provider.DeviceConfig;
+import android.sysprop.TelephonyProperties;
import android.telephony.AnomalyReporter;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
@@ -204,11 +205,9 @@
public static final String EXTRA_FAILURE_REASON =
"com.android.phone.slice.extra.FAILURE_REASON";
/**
- * Extra for the application name requesting to purchase the premium capability
- * from the slice purchase application.
+ * Extra for the user's carrier.
*/
- public static final String EXTRA_REQUESTING_APP_NAME =
- "com.android.phone.slice.extra.REQUESTING_APP_NAME";
+ public static final String EXTRA_CARRIER = "com.android.phone.slice.extra.CARRIER";
/**
* Extra for the canceled PendingIntent that the slice purchase application can send as a
* response if the performance boost notification or WebView was canceled by the user.
@@ -497,11 +496,10 @@
break;
}
case EVENT_START_SLICE_PURCHASE_APP: {
- int capability = msg.arg1;
- String appName = (String) msg.obj;
- logd("EVENT_START_SLICE_PURCHASE_APP: " + appName + " requests capability "
+ int capability = (int) msg.obj;
+ logd("EVENT_START_SLICE_PURCHASE_APP: "
+ TelephonyManager.convertPremiumCapabilityToString(capability));
- onStartSlicePurchaseApplication(capability, appName);
+ onStartSlicePurchaseApplication(capability);
break;
}
case EVENT_PURCHASE_TIMEOUT: {
@@ -565,13 +563,11 @@
* Purchase the given premium capability from the carrier.
*
* @param capability The premium capability to purchase.
- * @param appName The name of the application requesting premium capabilities.
* @param onComplete The callback message to send when the purchase request is complete.
*/
public synchronized void purchasePremiumCapability(
- @TelephonyManager.PremiumCapability int capability, @NonNull String appName,
- @NonNull Message onComplete) {
- logd("purchasePremiumCapability: " + appName + " requests capability "
+ @TelephonyManager.PremiumCapability int capability, @NonNull Message onComplete) {
+ logd("purchasePremiumCapability: "
+ TelephonyManager.convertPremiumCapabilityToString(capability));
// Check whether the premium capability can be purchased.
if (!arePremiumCapabilitiesSupportedByDevice()) {
@@ -627,8 +623,7 @@
// All state checks passed. Mark purchase pending and start the slice purchase application.
// Process through the handler since this method is synchronized.
mPendingPurchaseCapabilities.put(capability, onComplete);
- sendMessage(obtainMessage(EVENT_START_SLICE_PURCHASE_APP, capability, 0 /* unused */,
- appName));
+ sendMessage(obtainMessage(EVENT_START_SLICE_PURCHASE_APP, capability));
}
private void sendPurchaseResult(@TelephonyManager.PremiumCapability int capability,
@@ -687,8 +682,8 @@
}
}
- private void onStartSlicePurchaseApplication(@TelephonyManager.PremiumCapability int capability,
- @NonNull String appName) {
+ private void onStartSlicePurchaseApplication(
+ @TelephonyManager.PremiumCapability int capability) {
PremiumNetworkEntitlementResponse premiumNetworkEntitlementResponse =
mPremiumNetworkEntitlementApi.checkEntitlementStatus(capability);
@@ -721,7 +716,8 @@
}
String purchaseUrl = getPurchaseUrl(premiumNetworkEntitlementResponse);
- if (TextUtils.isEmpty(purchaseUrl)) {
+ String carrier = getSimOperator();
+ if (TextUtils.isEmpty(purchaseUrl) || TextUtils.isEmpty(carrier)) {
handlePurchaseResult(capability,
PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED, false);
return;
@@ -753,7 +749,7 @@
intent.putExtra(EXTRA_SUB_ID, mPhone.getSubId());
intent.putExtra(EXTRA_PREMIUM_CAPABILITY, capability);
intent.putExtra(EXTRA_PURCHASE_URL, purchaseUrl);
- intent.putExtra(EXTRA_REQUESTING_APP_NAME, appName);
+ intent.putExtra(EXTRA_CARRIER, carrier);
intent.putExtra(EXTRA_INTENT_CANCELED, createPendingIntent(
ACTION_SLICE_PURCHASE_APP_RESPONSE_CANCELED, capability, false));
intent.putExtra(EXTRA_INTENT_CARRIER_ERROR, createPendingIntent(
@@ -805,6 +801,20 @@
}
/**
+ * Get the SIM operator. This is the carrier name from the SIM rather than from the network,
+ * which will be the same regardless of whether the user is roaming or not.
+ *
+ * @return The operator name from the SIM.
+ */
+ @VisibleForTesting
+ @Nullable public String getSimOperator() {
+ if (mPhone.getPhoneId() < TelephonyProperties.icc_operator_alpha().size()) {
+ return TelephonyProperties.icc_operator_alpha().get(mPhone.getPhoneId());
+ }
+ return null;
+ }
+
+ /**
* Create the PendingIntent to allow the slice purchase application to send back responses.
*
* @param action The action that will be sent for this PendingIntent
@@ -819,6 +829,7 @@
Intent intent = new Intent(action);
intent.putExtra(EXTRA_PHONE_ID, mPhone.getPhoneId());
intent.putExtra(EXTRA_PREMIUM_CAPABILITY, capability);
+ intent.setPackage(mPhone.getContext().getPackageName());
return PendingIntent.getBroadcast(mPhone.getContext(), capability, intent,
PendingIntent.FLAG_CANCEL_CURRENT
| (mutable ? PendingIntent.FLAG_MUTABLE : PendingIntent.FLAG_IMMUTABLE));
@@ -1028,6 +1039,11 @@
}
private boolean isNetworkAvailable() {
+ if (mPhone.getServiceState().getDataRoaming()) {
+ logd("Network unavailable because it is roaming.");
+ return false;
+ }
+
// TODO (b/251558673): Create a listener for data network type changed to dismiss
// notification and activity when the network is no longer available.
switch (mPhone.getServiceState().getDataNetworkType()) {
diff --git a/src/com/android/phone/utils/CarrierAllowListInfo.java b/src/com/android/phone/utils/CarrierAllowListInfo.java
new file mode 100644
index 0000000..208eff3
--- /dev/null
+++ b/src/com/android/phone/utils/CarrierAllowListInfo.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone.utils;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
+import android.telephony.Rlog;
+import android.text.TextUtils;
+
+import com.android.internal.telephony.uicc.IccUtils;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class CarrierAllowListInfo {
+ private static final String LOG_TAG = "CarrierAllowListInfo";
+ private JSONObject mDataJSON;
+ private static final String JSON_CHARSET = "UTF-8";
+ private static final String MESSAGE_DIGEST_ALGORITHM = "SHA1";
+ private static final String CALLER_SHA_1_ID = "callerSHA1Id";
+ private static final String CALLER_CARRIER_ID = "carrierId";
+ public static final int INVALID_CARRIER_ID = -1;
+
+ private static final String CARRIER_RESTRICTION_OPERATOR_REGISTERED_FILE =
+ "CarrierRestrictionOperatorDetails.json";
+
+ private static CarrierAllowListInfo mInstance = null;
+ private Context mContext;
+
+ private CarrierAllowListInfo(Context context) {
+ mContext = context;
+ loadJsonFile(context);
+ }
+
+ public static CarrierAllowListInfo loadInstance(Context context) {
+ if (mInstance == null) {
+ mInstance = new CarrierAllowListInfo(context);
+ }
+ return mInstance;
+ }
+
+ public int validateCallerAndGetCarrierId(String packageName) {
+ CarrierInfo carrierInfo = parseJsonForCallerInfo(packageName);
+ boolean isValid = (carrierInfo != null) && validateCallerSignature(mContext, packageName,
+ carrierInfo.getSHAIdList());
+ return (isValid) ? carrierInfo.getCallerCarrierId() : INVALID_CARRIER_ID;
+ }
+
+ private void loadJsonFile(Context context) {
+ try {
+ String jsonString = getJsonFromAssets(context,
+ CARRIER_RESTRICTION_OPERATOR_REGISTERED_FILE, JSON_CHARSET);
+ if (!TextUtils.isEmpty(jsonString)) {
+ mDataJSON = new JSONObject(jsonString);
+ }
+ } catch (Exception ex) {
+ Rlog.e(LOG_TAG, "CarrierAllowListInfo: JSON file reading exception = " + ex);
+ }
+ }
+
+ /**
+ * Parse the JSON object to fetch the given caller's SHA-Ids and carrierId.
+ */
+ private CarrierInfo parseJsonForCallerInfo(String callerPackage) {
+ try {
+ if (mDataJSON != null && callerPackage != null) {
+ JSONObject callerJSON = mDataJSON.getJSONObject(callerPackage.trim());
+ JSONArray callerJSONArray = callerJSON.getJSONArray(CALLER_SHA_1_ID);
+ int carrierId = callerJSON.getInt(CALLER_CARRIER_ID);
+ List<String> appSignatures = new ArrayList<>();
+ for (int index = 0; index < callerJSONArray.length(); index++) {
+ appSignatures.add((String) callerJSONArray.get(index));
+ }
+ return new CarrierInfo(carrierId, appSignatures);
+ }
+ } catch (JSONException ex) {
+ Rlog.e(LOG_TAG, "getCallerSignatureInfo: JSONException = " + ex);
+ }
+ return null;
+ }
+
+ /**
+ * Read the Json file from the assert folder.
+ *
+ * @param context context
+ * @param fileName JSON file name in assets folder
+ * @param charset JSON file data format
+ * @return JSON file content in string format or null in case of IOException
+ */
+ private static String getJsonFromAssets(Context context, String fileName, String charset) {
+ String jsonStr;
+ try {
+ InputStream ipStream = context.getAssets().open(fileName);
+ int bufSize = ipStream.available();
+ byte[] fileBuffer = new byte[bufSize];
+ ipStream.read(fileBuffer);
+ ipStream.close();
+ jsonStr = new String(fileBuffer, charset);
+ } catch (IOException ex) {
+ Rlog.e(LOG_TAG, "getJsonFromAssets: Exception = " + ex);
+ return null;
+ }
+ return jsonStr;
+ }
+
+ /**
+ * API fetches all the related signatures of the given package from the packageManager
+ * and validate all the signatures.
+ *
+ * @param context context
+ * @param packageName package name of the caller to validate the signatures.
+ * @param allowListSignatures list of signatures to be validated.
+ * @return {@code true} if all the signatures are available with package manager.
+ * {@code false} if any one of the signatures won't match with package manager.
+ */
+ public static boolean validateCallerSignature(Context context, String packageName,
+ List<String> allowListSignatures) {
+ if (TextUtils.isEmpty(packageName) || allowListSignatures.size() == 0) {
+ // package name is mandatory
+ return false;
+ }
+ final PackageManager packageManager = context.getPackageManager();
+ try {
+ MessageDigest sha1MDigest = MessageDigest.getInstance(MESSAGE_DIGEST_ALGORITHM);
+ final PackageInfo packageInfo = packageManager.getPackageInfo(packageName,
+ PackageManager.GET_SIGNATURES);
+ for (Signature signature : packageInfo.signatures) {
+ final byte[] signatureSha1 = sha1MDigest.digest(signature.toByteArray());
+ final String hexSignatureSha1 = IccUtils.bytesToHexString(signatureSha1);
+ if (!allowListSignatures.contains(hexSignatureSha1)) {
+ return false;
+ }
+ }
+ return true;
+ } catch (NoSuchAlgorithmException | PackageManager.NameNotFoundException ex) {
+ Rlog.e(LOG_TAG, "validateCallerSignature: Exception = " + ex);
+ return false;
+ }
+ }
+
+ public int updateJsonForTest(String callerInfo) {
+ try {
+ if (callerInfo == null) {
+ // reset the Json content after testing
+ loadJsonFile(mContext);
+ } else {
+ mDataJSON = new JSONObject(callerInfo);
+ }
+ return 0;
+ } catch (JSONException ex) {
+ Rlog.e(LOG_TAG, "updateJsonForTest: Exception = " + ex);
+ }
+ return -1;
+ }
+
+ private static class CarrierInfo {
+ final private int mCallerCarrierId;
+ final private List<String> mSHAIdList;
+
+ public CarrierInfo(int carrierId, List<String> SHAIds) {
+ mCallerCarrierId = carrierId;
+ mSHAIdList = SHAIds;
+ }
+
+ public int getCallerCarrierId() {
+ return mCallerCarrierId;
+ }
+
+ public List<String> getSHAIdList() {
+ return mSHAIdList;
+ }
+ }
+}
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 9d36c48..1cf35a5 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -144,6 +144,7 @@
private static final int MSG_REJECT = 21;
private static final int MSG_DTMF_DONE = 22;
private static final int MSG_MEDIA_ATTRIBUTES_CHANGED = 23;
+ private static final int MSG_ON_RTT_INITIATED = 24;
private static final String JAPAN_COUNTRY_CODE_WITH_PLUS_SIGN = "+81";
private static final String JAPAN_ISO_COUNTRY_CODE = "JP";
@@ -331,6 +332,15 @@
args.recycle();
}
break;
+ case MSG_ON_RTT_INITIATED:
+ if (mOriginalConnection != null) {
+ // if mOriginalConnection is null, the properties will get set when
+ // mOriginalConnection gets set.
+ updateConnectionProperties();
+ refreshConferenceSupported();
+ }
+ sendRttInitiationSuccess();
+ break;
}
}
};
@@ -752,13 +762,11 @@
@Override
public void onRttInitiated() {
- if (mOriginalConnection != null) {
- // if mOriginalConnection is null, the properties will get set when
- // mOriginalConnection gets set.
- updateConnectionProperties();
- refreshConferenceSupported();
- }
- sendRttInitiationSuccess();
+ Log.i(TelephonyConnection.this, "onRttInitiated: callId=%s", getTelecomCallId());
+ // Post RTT initiation to the Handler associated with this TelephonyConnection.
+ // This avoids a race condition where a call starts as RTT but ConnectionService call to
+ // handleCreateConnectionComplete happens AFTER the RTT status is reported to Telecom.
+ mHandler.obtainMessage(MSG_ON_RTT_INITIATED).sendToTarget();
}
@Override
@@ -823,6 +831,7 @@
private RttTextStream mRttTextStream = null;
private boolean mWasImsConnection;
+ private boolean mWasCrossSim;
/**
* Tracks the multiparty state of the ImsCall so that changes in the bit state can be detected.
@@ -2373,6 +2382,16 @@
ImsCallProfile.EXTRA_CONFERENCE_AVAIL)) {
updateConnectionCapabilities();
}
+ // If extras contain or contained Cross Sim information,
+ // then ensure connection properties are updated and propagated to Telecom.
+ // Also, update the status hints in the case the call has
+ // has moved from cross sim call back to wifi
+ mWasCrossSim |= mOriginalConnectionExtras.containsKey(
+ ImsCallProfile.EXTRA_IS_CROSS_SIM_CALL);
+ if (mWasCrossSim) {
+ updateStatusHints();
+ updateConnectionProperties();
+ }
} else {
Log.d(this, "Extras update not required");
}
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 8da1b7d..4a89bd6 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -567,12 +567,22 @@
Connection connection, @Connection.ConnectionState int state) {
TelephonyConnection c = (TelephonyConnection) connection;
if (c != null) {
- if (c.getState() == Connection.STATE_ACTIVE) {
- Log.d(LOG_TAG, "Call State->ACTIVE."
- + "Clearing DomainSelectionConnection");
- c.removeTelephonyConnectionListener(mNormalCallConnectionListener);
- mDomainSelectionConnection.finishSelection();
- mDomainSelectionConnection = null;
+ switch(c.getState()) {
+ case Connection.STATE_ACTIVE: {
+ Log.d(LOG_TAG, "Call State->ACTIVE."
+ + "Clearing DomainSelectionConnection");
+ if (mDomainSelectionConnection != null) {
+ mDomainSelectionConnection.finishSelection();
+ mDomainSelectionConnection = null;
+ }
+ mNormalCallConnection = null;
+ }
+ break;
+
+ case Connection.STATE_DISCONNECTED: {
+ c.removeTelephonyConnectionListener(mNormalCallConnectionListener);
+ }
+ break;
}
}
}
@@ -599,36 +609,40 @@
new DomainSelectionConnection.DomainSelectionConnectionCallback() {
@Override
public void onSelectionTerminated(@DisconnectCauses int cause) {
- Log.v(this, "Call domain selection terminated.");
- if (mDomainSelectionConnection != null) {
- mDomainSelectionConnection = null;
- }
-
- if (mNormalCallConnection != null) {
- // TODO: To support ShowPreciseFailedCause,
- // TelephonyConnection.getShowPreciseFailedCause API should be added.
-
- // If cause is NOT_VALID then, it's a redial cancellation and use cause
- // code from original connection.
- com.android.internal.telephony.Connection connection =
- mNormalCallConnection.getOriginalConnection();
- if (connection != null) {
- if (cause == android.telephony.DisconnectCause.NOT_VALID) {
- cause = connection.getDisconnectCause();
+ mDomainSelectionMainExecutor.execute(new Runnable() {
+ int mCause = cause;
+ @Override
+ public void run() {
+ Log.v(this, "Call domain selection terminated.");
+ if (mDomainSelectionConnection != null) {
+ mDomainSelectionConnection = null;
}
+ if (mNormalCallConnection != null) {
+ // TODO: To support ShowPreciseFailedCause, TelephonyConnection
+ // .getShowPreciseFailedCause API should be added.
- String reason = connection.getVendorDisconnectCause();
+ // If cause is NOT_VALID then, it's a redial cancellation and
+ // use cause code from original connection.
+ com.android.internal.telephony.Connection connection =
+ mNormalCallConnection.getOriginalConnection();
+ if (connection != null) {
+ if (mCause == android.telephony.DisconnectCause.NOT_VALID) {
+ mCause = connection.getDisconnectCause();
+ }
- mNormalCallConnection.setTelephonyConnectionDisconnected(
- mDisconnectCauseFactory.toTelecomDisconnectCause(
- cause, reason));
- Log.d(this, "Call connection closed. Cause: " + cause
- + " Reason: " + reason);
+ String reason = connection.getVendorDisconnectCause();
+ int phoneId = mNormalCallConnection.getPhone().getPhoneId();
+ mNormalCallConnection.setTelephonyConnectionDisconnected(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
+ mCause, reason, phoneId));
+ Log.d(this, "Call connection closed. Cause: " + mCause
+ + " Reason: " + reason);
+ }
+ mNormalCallConnection.close();
+ mNormalCallConnection = null;
+ }
}
- mNormalCallConnection.close();
- mNormalCallConnection = null;
- }
-
+ });
}
};
@@ -2052,8 +2066,10 @@
e.getMessage(), phone.getPhoneId()));
mNormalCallConnection.close();
}
- mDomainSelectionConnection.finishSelection();
- mDomainSelectionConnection = null;
+ if (mDomainSelectionConnection != null) {
+ mDomainSelectionConnection.finishSelection();
+ mDomainSelectionConnection = null;
+ }
mNormalCallConnection = null;
}
@@ -2064,6 +2080,10 @@
return false;
}
+ if (phone == null) {
+ return false;
+ }
+
String dialPart = PhoneNumberUtils.extractNetworkPortionAlt(
PhoneNumberUtils.stripSeparators(number));
boolean isMmiCode = (dialPart.startsWith("*") || dialPart.startsWith("#"))
@@ -2076,6 +2096,16 @@
return false;
}
+ // Check and select same domain as ongoing call on the same subscription (if exists)
+ int activeCallDomain = getActiveCallDomain(phone.getSubId());
+ if (activeCallDomain != NetworkRegistrationInfo.DOMAIN_UNKNOWN) {
+ Log.d(LOG_TAG, "Selecting same domain as ongoing call on same subId");
+ mNormalCallConnection = connection;
+ handleOutgoingCallConnectionByCallDomainSelection(
+ activeCallDomain, phone, number, videoState);
+ return true;
+ }
+
mDomainSelectionConnection = mDomainSelectionResolver
.getDomainSelectionConnection(phone, SELECTOR_TYPE_CALLING, false);
if (mDomainSelectionConnection == null) {
@@ -2317,6 +2347,7 @@
callFailCause, reasonInfo);
Log.d(LOG_TAG, "Reselecting the domain for call");
+ mNormalCallConnection = c;
CompletableFuture<Integer> future = mDomainSelectionConnection
.reselectDomain(selectionAttributes);
if (future != null) {
@@ -2333,7 +2364,7 @@
mDomainSelectionConnection = null;
}
mNormalCallConnection = null;
- Log.d(LOG_TAG, "Reselecting the domain for call failed");
+ Log.d(LOG_TAG, "Reselect call domain not triggered.");
return false;
}
@@ -3463,4 +3494,25 @@
}
});
}
+
+ private @NetworkRegistrationInfo.Domain int getActiveCallDomain(int subId) {
+ for (Connection c: getAllConnections()) {
+ if ((c instanceof TelephonyConnection)) {
+ TelephonyConnection connection = (TelephonyConnection) c;
+ Phone phone = connection.getPhone();
+ if (phone == null) {
+ continue;
+ }
+
+ if (phone.getSubId() == subId) {
+ if (phone instanceof GsmCdmaPhone) {
+ return NetworkRegistrationInfo.DOMAIN_CS;
+ } else if (phone instanceof ImsPhone) {
+ return NetworkRegistrationInfo.DOMAIN_PS;
+ }
+ }
+ }
+ }
+ return NetworkRegistrationInfo.DOMAIN_UNKNOWN;
+ }
}
diff --git a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
index 9aaf6da..8100e63 100644
--- a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
@@ -41,14 +41,22 @@
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL;
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL;
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_SCAN_TIMER_SEC_INT;
+import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT;
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT;
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL;
import static android.telephony.CarrierConfigManager.ImsEmergency.SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_SETTING_ENABLED;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_VALID_EID;
+import static android.telephony.CarrierConfigManager.ImsWfc.KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL;
import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME;
import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING;
import android.annotation.NonNull;
import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
import android.os.CancellationSignal;
import android.os.Looper;
import android.os.Message;
@@ -69,6 +77,7 @@
import android.telephony.TransportSelectorCallback;
import android.telephony.ims.ImsManager;
import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ProvisioningManager;
import android.text.TextUtils;
import android.util.LocalLog;
@@ -97,6 +106,30 @@
private static final LocalLog sLocalLog = new LocalLog(LOG_SIZE);
+ /**
+ * Network callback used to determine whether Wi-Fi is connected or not.
+ */
+ private ConnectivityManager.NetworkCallback mNetworkCallback =
+ new ConnectivityManager.NetworkCallback() {
+ @Override
+ public void onAvailable(Network network) {
+ logi("onAvailable: " + network);
+ mWiFiAvailable = true;
+ }
+
+ @Override
+ public void onLost(Network network) {
+ logi("onLost: " + network);
+ mWiFiAvailable = false;
+ }
+
+ @Override
+ public void onUnavailable() {
+ logi("onUnavailable");
+ mWiFiAvailable = false;
+ }
+ };
+
private boolean mIsEmergencyBarred;
private boolean mImsRegistered;
private boolean mIsVoiceCapable;
@@ -122,10 +155,14 @@
private @CarrierConfigManager.ImsEmergency.EmergencyDomain int[] mDomainPreferenceRoam;
private List<String> mCdmaPreferredNumbers;
private boolean mPreferImsWhenCallsOnCs;
+ private int mVoWifiRequiresCondition;
+ private boolean mIsMonitoringConnectivity;
+ private boolean mWiFiAvailable;
private int mScanTimeout;
private int mMaxNumOfVoWifiTries;
+ private boolean mVoWifiOverEmergencyPdn;
private @CarrierConfigManager.ImsEmergency.EmergencyScanType int mPreferredNetworkScanType;
- private int mCallSetupTimerOnCurrentRatSec;
+ private int mCallSetupTimerOnCurrentRat;
private boolean mRequiresImsRegistration;
private boolean mRequiresVoLteEnabled;
private boolean mLtePreferredAfterNrFailure;
@@ -221,8 +258,14 @@
@Override
public void reselectDomain(SelectionAttributes attr) {
- logi("reselectDomain tryCsWhenPsFails=" + mTryCsWhenPsFails + ", attr=" + attr);
+ logi("reselectDomain attr=" + attr);
mSelectionAttributes = attr;
+ post(() -> { reselectDomain(); });
+ }
+
+ private void reselectDomain() {
+ logi("reselectDomain tryCsWhenPsFails=" + mTryCsWhenPsFails);
+
if (mTryCsWhenPsFails) {
mTryCsWhenPsFails = false;
mCsNetworkType = getSelectableCsNetworkType();
@@ -231,20 +274,11 @@
onWwanNetworkTypeSelected(mCsNetworkType);
return;
}
- } else if (getImsNetworkTypeConfiguration().isEmpty()
- || (mRequiresVoLteEnabled && !isAdvancedCallingSettingEnabled())) {
- // Emergency call over IMS is not supported.
- mCsNetworkType = UTRAN;
- onWwanNetworkTypeSelected(mCsNetworkType);
- return;
}
if (mLastTransportType == TRANSPORT_TYPE_WLAN) {
// Dialing over Wi-Fi failed. Try scanning cellular networks.
- onWwanSelected(() -> {
- requestScan(true, false, true);
- mDomainSelected = false;
- });
+ onWwanSelected(this::reselectDomainInternal);
return;
}
@@ -252,6 +286,13 @@
mDomainSelected = false;
}
+ private void reselectDomainInternal() {
+ post(() -> {
+ requestScan(true, false, true);
+ mDomainSelected = false;
+ });
+ }
+
@Override
public void finishSelection() {
logi("finishSelection");
@@ -343,11 +384,13 @@
mDomainPreferenceRoam = b.getIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_ROAMING_INT_ARRAY);
mPreferImsWhenCallsOnCs = b.getBoolean(
KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL);
- mScanTimeout = b.getInt(KEY_EMERGENCY_SCAN_TIMER_SEC_INT);
+ mVoWifiRequiresCondition = b.getInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT);
+ mScanTimeout = b.getInt(KEY_EMERGENCY_SCAN_TIMER_SEC_INT) * 1000;
mMaxNumOfVoWifiTries = b.getInt(KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT);
+ mVoWifiOverEmergencyPdn = b.getBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL);
mPreferredNetworkScanType = b.getInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT);
- mCallSetupTimerOnCurrentRatSec = b.getInt(
- KEY_EMERGENCY_CALL_SETUP_TIMER_ON_CURRENT_NETWORK_SEC_INT);
+ mCallSetupTimerOnCurrentRat = b.getInt(
+ KEY_EMERGENCY_CALL_SETUP_TIMER_ON_CURRENT_NETWORK_SEC_INT) * 1000;
mRequiresImsRegistration = b.getBoolean(KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL);
mRequiresVoLteEnabled = b.getBoolean(KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL);
mLtePreferredAfterNrFailure = b.getBoolean(
@@ -376,11 +419,13 @@
+ ", domainPrefRoam=" + arrayToString(mDomainPreferenceRoam,
EmergencyCallDomainSelector::domainPreferenceToString)
+ ", preferImsOnCs=" + mPreferImsWhenCallsOnCs
+ + ", voWifiRequiresCondition=" + mVoWifiRequiresCondition
+ ", scanTimeout=" + mScanTimeout
+ ", maxNumOfVoWifiTries=" + mMaxNumOfVoWifiTries
+ + ", voWifiOverEmergencyPdn=" + mVoWifiOverEmergencyPdn
+ ", preferredScanType=" + carrierConfigNetworkScanTypeToString(
mPreferredNetworkScanType)
- + ", callSetupTimer=" + mCallSetupTimerOnCurrentRatSec
+ + ", callSetupTimer=" + mCallSetupTimerOnCurrentRat
+ ", requiresImsReg=" + mRequiresImsRegistration
+ ", requiresVoLteEnabled=" + mRequiresVoLteEnabled
+ ", ltePreferredAfterNr=" + mLtePreferredAfterNrFailure
@@ -422,14 +467,10 @@
}
private void selectDomainInternal() {
- if (getImsNetworkTypeConfiguration().isEmpty()
- || (mRequiresVoLteEnabled && !isAdvancedCallingSettingEnabled())) {
- // Emergency call over IMS is not supported.
- mCsNetworkType = UTRAN;
- onWwanNetworkTypeSelected(mCsNetworkType);
- return;
- }
+ post(this::selectDomainFromInitialState);
+ }
+ private void selectDomainFromInitialState() {
boolean csInService = isCsInService();
boolean psInService = isPsInService();
@@ -546,6 +587,7 @@
// remove any pending timers.
removeMessages(MSG_NETWORK_SCAN_TIMEOUT);
sendEmptyMessageDelayed(MSG_NETWORK_SCAN_TIMEOUT, mScanTimeout);
+ registerForConnectivityChanges();
}
}
}
@@ -557,6 +599,12 @@
* @return The list of preferred network types.
*/
private @RadioAccessNetworkType List<Integer> getNextPreferredNetworks(boolean csPreferred) {
+ if (mRequiresVoLteEnabled && !isAdvancedCallingSettingEnabled()) {
+ // Emergency call over IMS is not supported.
+ logi("getNextPreferredNetworks VoLte setting is not enabled.");
+ return generatePreferredNetworks(getCsNetworkTypeConfiguration());
+ }
+
List<Integer> preferredNetworks = new ArrayList<>();
List<Integer> domains = getDomainPreference();
@@ -625,8 +673,33 @@
}
private void handleNetworkScanTimeout() {
- if (isImsRegisteredWithVoiceCapability()
- && isImsRegisteredOverWifi()) {
+ logi("handleNetworkScanTimeout overEmergencyPdn=" + mVoWifiOverEmergencyPdn
+ + ", wifiAvailable=" + mWiFiAvailable);
+ boolean available = mWiFiAvailable;
+ if (mVoWifiOverEmergencyPdn) {
+ // SOS APN
+ if (!available && isImsRegisteredOverCrossSim()) {
+ available = true;
+ }
+ if (available) {
+ switch (mVoWifiRequiresCondition) {
+ case VOWIFI_REQUIRES_SETTING_ENABLED:
+ available = isWifiCallingSettingEnabled();
+ break;
+ case VOWIFI_REQUIRES_VALID_EID:
+ available = isWifiCallingActivated();
+ break;
+ default:
+ break;
+ }
+ }
+ } else {
+ // IMS APN. When IMS is already registered over Wi-Fi.
+ available = isImsRegisteredWithVoiceCapability() && isImsRegisteredOverWifi();
+ }
+
+ logi("handleNetworkScanTimeout VoWi-Fi available=" + available);
+ if (available) {
if (mCancelSignal != null) {
mCancelSignal.cancel();
mCancelSignal = null;
@@ -710,6 +783,11 @@
EmergencyRegResult regResult = mSelectionAttributes.getEmergencyRegResult();
logi("getSelectablePsNetworkType regResult=" + regResult);
if (regResult == null) return UNKNOWN;
+ if (mRequiresVoLteEnabled && !isAdvancedCallingSettingEnabled()) {
+ // Emergency call over IMS is not supported.
+ logi("getSelectablePsNetworkType VoLte setting is not enabled.");
+ return UNKNOWN;
+ }
int accessNetwork = regResult.getAccessNetwork();
List<Integer> ratList = getImsNetworkTypeConfiguration();
@@ -797,6 +875,41 @@
return true;
}
+ private boolean isWifiCallingActivated() {
+ try {
+ ImsManager imsMngr = mContext.getSystemService(ImsManager.class);
+ ProvisioningManager pm = imsMngr.getProvisioningManager(getSubId());
+ String eid = pm.getProvisioningStringValue(
+ ProvisioningManager.KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID);
+ boolean activated = (!TextUtils.isEmpty(eid)) && (!TextUtils.equals("0", eid));
+ logi("isWifiCallingActivated " + activated);
+ return activated;
+ } catch (Exception e) {
+ logi("isWifiCallingActivated e=" + e);
+ }
+ return false;
+ }
+
+ private boolean isWifiCallingSettingEnabled() {
+ boolean result = false;
+ try {
+ if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
+ ImsManager imsMngr = mContext.getSystemService(ImsManager.class);
+ ImsMmTelManager mmTelManager = imsMngr.getImsMmTelManager(getSubId());
+ if (isInRoaming()) {
+ result = mmTelManager.isVoWiFiRoamingSettingEnabled();
+ } else {
+ result = mmTelManager.isVoWiFiSettingEnabled();
+ }
+ logi("isWifiCallingSettingEnabled " + result);
+ return result;
+ }
+ } catch (Exception e) {
+ logi("isWifiCallingSettingEnabled e=" + e);
+ }
+ return result;
+ }
+
private @NonNull List<Integer> getImsNetworkTypeConfiguration() {
int[] rats = mImsRatsConfig;
if (isInRoaming()) rats = mImsRoamRatsConfig;
@@ -883,6 +996,21 @@
}
/**
+ * Determines whether IMS is registered over the mobile data of another subscription.
+ *
+ * @return {@code true} if IMS is registered over the mobile data of another subscription.
+ */
+ private boolean isImsRegisteredOverCrossSim() {
+ boolean ret = false;
+ if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
+ ret = mImsStateTracker.isImsRegisteredOverCrossSim();
+ }
+
+ logi("isImsRegisteredOverCrossSim " + ret);
+ return ret;
+ }
+
+ /**
* Determines whether IMS is registered with voice capability.
*
* @return {@code true} if IMS is registered with voice capability.
@@ -896,6 +1024,12 @@
private void onWlanSelected() {
logi("onWlanSelected");
+ if (mLastTransportType == TRANSPORT_TYPE_WLAN) {
+ logi("onWlanSelected ignore duplicated callback");
+ return;
+ }
+
+ mDomainSelected = true;
mLastTransportType = TRANSPORT_TYPE_WLAN;
mVoWifiTrialCount++;
mTransportSelectorCallback.onWlanSelected();
@@ -904,10 +1038,8 @@
private void onWwanSelected(Runnable runnable) {
logi("onWwanSelected");
- if (mLastTransportType == TRANSPORT_TYPE_WWAN
- && mWwanSelectorCallback != null) {
- logi("onWwanSelected already notified");
- runnable.run();
+ if (mLastTransportType == TRANSPORT_TYPE_WWAN) {
+ logi("onWwanSelected ignore duplicated callback");
return;
}
@@ -934,6 +1066,40 @@
mWwanSelectorCallback.onDomainSelected(domain);
}
+ /**
+ * Registers for changes to network connectivity.
+ */
+ private void registerForConnectivityChanges() {
+ if (mIsMonitoringConnectivity) {
+ return;
+ }
+
+ ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+ if (cm != null) {
+ logi("registerForConnectivityChanges");
+ NetworkRequest.Builder builder = new NetworkRequest.Builder();
+ builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+ cm.registerNetworkCallback(builder.build(), mNetworkCallback);
+ mIsMonitoringConnectivity = true;
+ }
+ }
+
+ /**
+ * Unregisters for connectivity changes.
+ */
+ private void unregisterForConnectivityChanges() {
+ if (!mIsMonitoringConnectivity) {
+ return;
+ }
+
+ ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+ if (cm != null) {
+ logi("unregisterForConnectivityChanges");
+ cm.unregisterNetworkCallback(mNetworkCallback);
+ mIsMonitoringConnectivity = false;
+ }
+ }
+
private static String arrayToString(int[] intArray, IntFunction<String> func) {
int length = intArray.length;
StringBuilder sb = new StringBuilder("{");
@@ -1009,6 +1175,7 @@
mDestroyed = true;
mImsStateTracker.removeBarringInfoListener(this);
mImsStateTracker.removeImsStateListener(this);
+ unregisterForConnectivityChanges();
super.destroy();
}
diff --git a/src/com/android/services/telephony/domainselection/ImsStateTracker.java b/src/com/android/services/telephony/domainselection/ImsStateTracker.java
index e1d0d31..fc3f811 100644
--- a/src/com/android/services/telephony/domainselection/ImsStateTracker.java
+++ b/src/com/android/services/telephony/domainselection/ImsStateTracker.java
@@ -130,6 +130,7 @@
/** The IMS registration state and the network type that performed IMS registration. */
private Boolean mImsRegistered;
private @RadioAccessNetworkType int mImsAccessNetworkType = AccessNetworkType.UNKNOWN;
+ private Boolean mImsRegisteredOverCrossSim;
/** The MMTEL capabilities - Voice, Video, SMS, and Ut. */
private MmTelCapabilities mMmTelCapabilities;
private final Runnable mMmTelFeatureUnavailableRunnable = new Runnable() {
@@ -361,6 +362,13 @@
}
/**
+ * Returns {@code true} if IMS is registered over the mobile data of another subscription.
+ */
+ public boolean isImsRegisteredOverCrossSim() {
+ return mImsRegisteredOverCrossSim != null && mImsRegisteredOverCrossSim;
+ }
+
+ /**
* Returns {@code true} if IMS voice call is capable, {@code false} otherwise.
*/
public boolean isImsVoiceCapable() {
@@ -406,6 +414,7 @@
mMmTelFeatureAvailable = null;
mImsRegistered = null;
mImsAccessNetworkType = AccessNetworkType.UNKNOWN;
+ mImsRegisteredOverCrossSim = null;
mMmTelCapabilities = null;
}
@@ -418,6 +427,7 @@
setMmTelFeatureAvailable(false);
setImsRegistered(false);
setImsAccessNetworkType(AccessNetworkType.UNKNOWN);
+ setImsRegisteredOverCrossSim(false);
setMmTelCapabilities(new MmTelCapabilities());
}
@@ -450,6 +460,13 @@
}
}
+ private void setImsRegisteredOverCrossSim(boolean crossSim) {
+ if (!Objects.equals(mImsRegisteredOverCrossSim, Boolean.valueOf(crossSim))) {
+ logi("setImsRegisteredOverCrossSim: " + mImsRegisteredOverCrossSim + " >> " + crossSim);
+ mImsRegisteredOverCrossSim = Boolean.valueOf(crossSim);
+ }
+ }
+
/**
* Notifies the specified listener of the current IMS state if it's valid.
*
@@ -548,6 +565,8 @@
setImsStateAsUnavailable();
unregisterImsRegistrationCallback();
unregisterMmTelCapabilityCallback();
+ // ImsStateCallback has already been removed after calling onUnavailable.
+ mImsStateCallback = null;
notifyImsMmTelFeatureAvailableChanged();
} else {
logw("onMmTelFeatureUnavailable: unexpected reason=" + reason);
@@ -563,6 +582,8 @@
setImsRegistered(true);
setImsAccessNetworkType(
imsRegTechToAccessNetworkType(attributes.getRegistrationTechnology()));
+ setImsRegisteredOverCrossSim(attributes.getRegistrationTechnology()
+ == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM);
notifyImsRegistrationStateChanged();
}
@@ -573,6 +594,7 @@
logd("onImsUnregistered: " + info);
setImsRegistered(false);
setImsAccessNetworkType(AccessNetworkType.UNKNOWN);
+ setImsRegisteredOverCrossSim(false);
setMmTelCapabilities(new MmTelCapabilities());
notifyImsRegistrationStateChanged();
}
@@ -773,6 +795,7 @@
case ImsRegistrationImplBase.REGISTRATION_TECH_NR:
return AccessNetworkType.NGRAN;
case ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN:
+ case ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM:
return AccessNetworkType.IWLAN;
default:
return AccessNetworkType.UNKNOWN;
diff --git a/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java b/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
index 82057d3..146874c 100644
--- a/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/NormalCallDomainSelector.java
@@ -215,6 +215,12 @@
}
}
+ private boolean isOutOfService() {
+ return (mServiceState.getState() == ServiceState.STATE_OUT_OF_SERVICE
+ || mServiceState.getState() == ServiceState.STATE_POWER_OFF
+ || mServiceState.getState() == ServiceState.STATE_EMERGENCY_ONLY);
+ }
+
private synchronized void selectDomain() {
if (mStopDomainSelection || mSelectionAttributes == null
|| mTransportSelectorCallback == null) {
@@ -225,12 +231,6 @@
if (mServiceState == null) {
logd("Waiting for ServiceState callback.");
return;
- } else if (mServiceState.getState() == ServiceState.STATE_OUT_OF_SERVICE
- || mServiceState.getState() == ServiceState.STATE_POWER_OFF
- || mServiceState.getState() == ServiceState.STATE_EMERGENCY_ONLY) {
- loge("Cannot place call in current ServiceState: " + mServiceState.getState());
- notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
- return;
}
// Check if this is a re-dial scenario
@@ -240,8 +240,13 @@
logd("PsDisconnectCause:" + imsReasonInfo.mCode);
mReselectDomain = false;
if (imsReasonInfo.mCode == ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED) {
- logd("Redialing over CS");
- notifyCsSelected();
+ if (isOutOfService()) {
+ loge("Cannot place call in current ServiceState: " + mServiceState.getState());
+ notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
+ } else {
+ logd("Redialing over CS");
+ notifyCsSelected();
+ }
return;
} else {
logd("Redialing cancelled.");
@@ -269,7 +274,12 @@
if (!mImsStateTracker.isImsRegistered()) {
logd("IMS is NOT registered");
- notifyCsSelected();
+ if (isOutOfService()) {
+ loge("Cannot place call in current ServiceState: " + mServiceState.getState());
+ notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
+ } else {
+ notifyCsSelected();
+ }
return;
}
@@ -289,11 +299,21 @@
} else {
logd("IMS is not voice capable");
// Voice call CS fallback
- notifyCsSelected();
+ if (isOutOfService()) {
+ loge("Cannot place call in current ServiceState: " + mServiceState.getState());
+ notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
+ } else {
+ notifyCsSelected();
+ }
}
} else {
logd("IMS is not registered or unavailable");
- notifyCsSelected();
+ if (isOutOfService()) {
+ loge("Cannot place call in current ServiceState: " + mServiceState.getState());
+ notifySelectionTerminated(DisconnectCause.OUT_OF_SERVICE);
+ } else {
+ notifyCsSelected();
+ }
}
}
}
diff --git a/testapps/GbaTestApp/res/values-ky/strings.xml b/testapps/GbaTestApp/res/values-ky/strings.xml
index bf5cd30..00383d5 100644
--- a/testapps/GbaTestApp/res/values-ky/strings.xml
+++ b/testapps/GbaTestApp/res/values-ky/strings.xml
@@ -2,7 +2,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="2922839697457005451">"GbaTestApp"</string>
- <string name="label_settings" msgid="8030871890526865502">"Жөндөөлөр"</string>
+ <string name="label_settings" msgid="8030871890526865502">"Параметрлер"</string>
<string name="label_carrier" msgid="1470455313066422804">"Байланыш операторунун конфигурациясы"</string>
<string name="label_service" msgid="2668963955237345578">"Кызматтын конфигурациясы"</string>
<string name="label_test" msgid="8425079572898571918">"Сыноо конфигурациясы"</string>
diff --git a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java
index 0f120f4..a74e7f0 100644
--- a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java
+++ b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java
@@ -23,7 +23,7 @@
import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_FEATURE_NOT_SUPPORTED;
import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE;
import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION;
-import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_OVERRIDDEN;
+import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_FOREGROUND;
import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP;
import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_SUCCESS;
import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED;
@@ -271,8 +271,8 @@
return "Already purchased";
case PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS:
return "Already in progress";
- case PURCHASE_PREMIUM_CAPABILITY_RESULT_OVERRIDDEN:
- return "Overridden";
+ case PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_FOREGROUND:
+ return "Not foreground";
case PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_CANCELED:
return "User canceled";
case PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED:
diff --git a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
index 6e4a65f..4cc793d 100644
--- a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
+++ b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
@@ -21,6 +21,8 @@
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
@@ -42,6 +44,7 @@
import com.android.TelephonyTestBase;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.RILConstants;
+import com.android.internal.telephony.IIntegerConsumer;
import org.junit.Before;
import org.junit.Test;
@@ -57,6 +60,7 @@
public class PhoneInterfaceManagerTest extends TelephonyTestBase {
private PhoneInterfaceManager mPhoneInterfaceManager;
private SharedPreferences mSharedPreferences;
+ private IIntegerConsumer mIIntegerConsumer;
@Mock
PhoneGlobals mPhoneGlobals;
@@ -74,6 +78,7 @@
mPhoneInterfaceManager = spy(PhoneInterfaceManager.init(mPhoneGlobals));
mSharedPreferences = mPhoneInterfaceManager.getSharedPreferences();
mSharedPreferences.edit().remove(Phone.PREF_NULL_CIPHER_AND_INTEGRITY_ENABLED).commit();
+ mIIntegerConsumer = mock(IIntegerConsumer.class);
}
@Test
@@ -149,6 +154,7 @@
@Test
public void setNullCipherAndIntegrityEnabled_successfullyEnable() {
+ whenModemSupportsNullCiphers();
doReturn(201).when(mPhoneInterfaceManager).getHalVersion(anyInt());
doNothing().when(mPhoneInterfaceManager).enforceModifyPermission();
assertFalse(mSharedPreferences.contains(Phone.PREF_NULL_CIPHER_AND_INTEGRITY_ENABLED));
@@ -161,6 +167,7 @@
@Test
public void setNullCipherAndIntegrityEnabled_successfullyDisable() {
+ whenModemSupportsNullCiphers();
doReturn(201).when(mPhoneInterfaceManager).getHalVersion(anyInt());
doNothing().when(mPhoneInterfaceManager).enforceModifyPermission();
assertFalse(mSharedPreferences.contains(Phone.PREF_NULL_CIPHER_AND_INTEGRITY_ENABLED));
@@ -194,10 +201,10 @@
@Test
public void isNullCipherAndIntegrityPreferenceEnabled() {
+ whenModemSupportsNullCiphers();
doReturn(201).when(mPhoneInterfaceManager).getHalVersion(anyInt());
doNothing().when(mPhoneInterfaceManager).enforceModifyPermission();
- assertTrue(mPhoneInterfaceManager.isNullCipherAndIntegrityPreferenceEnabled());
mPhoneInterfaceManager.setNullCipherAndIntegrityEnabled(false);
assertFalse(
mSharedPreferences.getBoolean(Phone.PREF_NULL_CIPHER_AND_INTEGRITY_ENABLED, true));
@@ -215,6 +222,18 @@
}
@Test
+ public void isNullCipherAndIntegrityPreferenceEnabled_lackingModemSupport() {
+ whenModemDoesNotSupportNullCiphers();
+ doReturn(201).when(mPhoneInterfaceManager).getHalVersion(anyInt());
+ doNothing().when(mPhoneInterfaceManager).enforceModifyPermission();
+
+ assertThrows(UnsupportedOperationException.class, () -> {
+ mPhoneInterfaceManager.isNullCipherAndIntegrityPreferenceEnabled();
+ });
+
+ }
+
+ @Test
public void isNullCipherAndIntegrityPreferenceEnabled_lackingPermissions() {
doReturn(201).when(mPhoneInterfaceManager).getHalVersion(anyInt());
doThrow(SecurityException.class).when(mPhoneInterfaceManager).enforceReadPermission();
@@ -223,4 +242,39 @@
mPhoneInterfaceManager.isNullCipherAndIntegrityPreferenceEnabled();
});
}
+
+ private void whenModemDoesNotSupportNullCiphers() {
+ doReturn(false).when(mPhone).isNullCipherAndIntegritySupported();
+ doReturn(mPhone).when(
+ mPhoneInterfaceManager).getDefaultPhone();
+ }
+
+ private void whenModemSupportsNullCiphers() {
+ doReturn(true).when(mPhone).isNullCipherAndIntegritySupported();
+ doReturn(mPhone).when(
+ mPhoneInterfaceManager).getDefaultPhone();
+ }
+
+ /**
+ * Verify getCarrierRestrictionStatus throws exception for invalid caller package name.
+ */
+ @Test
+ public void getCarrierRestrictionStatus_ReadPrivilegedException2() {
+ doThrow(SecurityException.class).when(
+ mPhoneInterfaceManager).enforceReadPrivilegedPermission(anyString());
+ assertThrows(SecurityException.class, () -> {
+ mPhoneInterfaceManager.getCarrierRestrictionStatus(mIIntegerConsumer, "");
+ });
+ }
+
+ /**
+ * Verify getCarrierRestrictionStatus doesn't throw any exception with valid package name
+ * and with READ_PHONE_STATE permission granted.
+ */
+ @Test
+ public void getCarrierRestrictionStatus() {
+ when(mPhoneInterfaceManager.validateCallerAndGetCarrierId(anyString())).thenReturn(1);
+ mPhoneInterfaceManager.getCarrierRestrictionStatus(mIIntegerConsumer,
+ "com.test.package");
+ }
}
diff --git a/tests/src/com/android/phone/Telephony2gUpdaterTest.java b/tests/src/com/android/phone/Telephony2gUpdaterTest.java
index 3443767..3684f30 100644
--- a/tests/src/com/android/phone/Telephony2gUpdaterTest.java
+++ b/tests/src/com/android/phone/Telephony2gUpdaterTest.java
@@ -16,13 +16,17 @@
package com.android.phone;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.Intent;
import android.os.UserManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -35,22 +39,33 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
public class Telephony2gUpdaterTest extends TelephonyTestBase {
+ private static final long DRAIN_TIMEOUT = 10;
private Telephony2gUpdater mTelephony2gUpdater;
+ private SubscriptionManager.OnSubscriptionsChangedListener mChangedListener;
private Executor mExecutor;
+ private CountDownLatch mLatch;
private UserManager mMockUserManager;
private TelephonyManager mMockTelephonyManager;
private SubscriptionManager mMockSubscriptionManager;
+ // Set up to be returned from mMockSubscriptionManager.getCompleteActiveSubscriptionInfoList()
+ // Updates will be reflected in subsequent calls to the mock method.
+ private List<SubscriptionInfo> mCurrentSubscriptions;
+
// 2G Bitmask is 0b10000000_01001011
private static final long BASE_NETWORK = 0b11111111_11111111;
private static final long EXPECTED_DISABLED = 0b01111111_10110100;
@@ -65,89 +80,247 @@
mMockUserManager = mContext.getSystemService(UserManager.class);
mMockSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
+ mCurrentSubscriptions = new ArrayList<>();
+ setupMutableSubscriptionInfoMock();
+
mExecutor = Executors.newSingleThreadExecutor();
- mTelephony2gUpdater = new Telephony2gUpdater(mExecutor,
- getTestContext(), BASE_NETWORK);
+ mTelephony2gUpdater = new Telephony2gUpdater(mExecutor, getTestContext(), BASE_NETWORK);
+ mTelephony2gUpdater.init();
+ ArgumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener> argument =
+ ArgumentCaptor.forClass(SubscriptionManager.OnSubscriptionsChangedListener.class);
+ verify(mMockSubscriptionManager).addOnSubscriptionsChangedListener(any(Executor.class),
+ argument.capture());
+ mChangedListener = argument.getValue();
}
@Test
- public void handleUserRestrictionsChanged_noSubscriptions_noAllowedNetworksChanged() {
- when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
- new ArrayList<>());
- mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
+ public void onSubscriptionsChanged_noSubscriptions_noAllowedNetworksChanged() {
+ triggerOnSubscriptionChangedAndWait();
verify(mMockTelephonyManager, never()).setAllowedNetworkTypesForReason(anyInt(), anyInt());
}
@Test
- public void handleUserRestrictionsChanged_nullSubscriptions_noAllowedNetworksChanged() {
- when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(null);
- mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
- verify(mMockTelephonyManager, never()).setAllowedNetworkTypesForReason(anyInt(), anyInt());
- }
+ public void onSubscriptionsChanged_oneSubscription_allowedNetworksUpdated() {
+ TelephonyManager tmSubscription1 = addSubscriptionAndGetMock(1001);
+ triggerOnSubscriptionChangedAndWait();
- @Test
- public void handleUserRestrictionsChanged_oneSubscription_allowedNetworksUpdated() {
- TelephonyManager tmSubscription1 = mock(TelephonyManager.class);
- when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
- Collections.singletonList(getSubInfo(1)));
- when(mMockTelephonyManager.createForSubscriptionId(1)).thenReturn(tmSubscription1);
- when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
- true);
-
- mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
-
- System.out.println(TelephonyManager.convertNetworkTypeBitmaskToString(11L));
verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
- TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
}
@Test
- public void handleUserRestrictionsChanged_manySubscriptionsDisallow2g_allowedNetworkUpdated() {
-
- // Two subscriptions are available
- when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
- Arrays.asList(getSubInfo(1), getSubInfo(2)));
- TelephonyManager tmSubscription1 = mock(TelephonyManager.class);
- TelephonyManager tmSubscription2 = mock(TelephonyManager.class);
- when(mMockTelephonyManager.createForSubscriptionId(1)).thenReturn(tmSubscription1);
- when(mMockTelephonyManager.createForSubscriptionId(2)).thenReturn(tmSubscription2);
+ public void onSubscriptionsChanged_manySubscriptionsDisallow2g_allowedNetworkUpdated() {
// 2g is disallowed
when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
true);
+ triggerBroadcastReceiverAndWait();
- mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
+ TelephonyManager tmSubscription1 = addSubscriptionAndGetMock(1001);
+ TelephonyManager tmSubscription2 = addSubscriptionAndGetMock(1002);
+
+ triggerOnSubscriptionChangedAndWait();
verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+ verify(tmSubscription2, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+ }
+
+ @Test
+ public void onSubscriptionsChanged_noNewSubscriptions_noAllowedNetworksChanged() {
+ when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
+ true);
+ triggerBroadcastReceiverAndWait();
+
+ TelephonyManager tmSubscription1 = addSubscriptionAndGetMock(1001);
+
+ triggerOnSubscriptionChangedAndWait();
+ triggerOnSubscriptionChangedAndWait();
+
+ // subscriptions were updated twice, but we have no new subIds so we only expect one update
verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
}
@Test
- public void handleUserRestrictionsChanged_manySubscriptionsAllow2g_allowedNetworkUpdated() {
+ public void onSubscriptionsChanged_removeSubscription_noAdditionalNetworkChanges() {
+ // We start with 2 subIds
+ TelephonyManager tmSubscription1 = addSubscriptionAndGetMock(1001);
+ TelephonyManager tmSubscription2 = addSubscriptionAndGetMock(1002);
- // Two subscriptions are available
- when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
- Arrays.asList(getSubInfo(1), getSubInfo(2)));
- TelephonyManager tmSubscription1 = mock(TelephonyManager.class);
- TelephonyManager tmSubscription2 = mock(TelephonyManager.class);
- when(mMockTelephonyManager.createForSubscriptionId(1)).thenReturn(tmSubscription1);
- when(mMockTelephonyManager.createForSubscriptionId(2)).thenReturn(tmSubscription2);
+ triggerOnSubscriptionChangedAndWait();
- // 2g is allowed
+ // 2g is still enabled since the default is to not set the user restriction
+ verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ verify(tmSubscription2, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+
+
+ mCurrentSubscriptions.remove(1);
+ triggerOnSubscriptionChangedAndWait();
+
+ // Subscriptions have changed, but we've only removed a subscription so there should be no
+ // extra updates to allowed network types
+ verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ verify(tmSubscription2, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ }
+
+ @Test
+ public void onSubscriptionsChanged_removeSubscriptionAndReAdd() {
+ when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
+ true);
+ triggerBroadcastReceiverAndWait();
+
+ TelephonyManager tmSubscription1 = addSubscriptionAndGetMock(1001);
+ triggerOnSubscriptionChangedAndWait();
+ mCurrentSubscriptions.remove(0);
+ triggerOnSubscriptionChangedAndWait();
+ mCurrentSubscriptions.add(getSubInfo(1001));
+ triggerOnSubscriptionChangedAndWait();
+
+ // subscriptions were updated thrice, but one of those updates removed a subscription
+ // such that the sub list was empty, so we only expect an update on the first and last
+ // updates.
+ verify(tmSubscription1, times(2)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+ }
+
+ @Test
+ public void onSubscriptionsChanged_addSubscription_updateAllowedNetworks() {
+ // We start with 2 subIds and update subscriptions
+ TelephonyManager tmSubscription1 = addSubscriptionAndGetMock(1001);
+ TelephonyManager tmSubscription2 = addSubscriptionAndGetMock(1002);
+ triggerOnSubscriptionChangedAndWait();
+
+ // Then add a subId and update subscriptions again
+ TelephonyManager tmSubscription3 = addSubscriptionAndGetMock(1003);
+ triggerOnSubscriptionChangedAndWait();
+
+ // we only need to update the new subscription
+ verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ verify(tmSubscription2, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ verify(tmSubscription3, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ }
+
+ @Test
+ public void onUserRestrictionUnchanged_noChangeToRestriction_noAllowedNetworksUpdated() {
+ TelephonyManager tmSubscription = addSubscriptionAndGetMock(1001);
+ triggerOnSubscriptionChangedAndWait();
+ // precondition: we've updated allowed networks to the default (2g enabled)
+ verify(tmSubscription, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ verify(tmSubscription, never()).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+
+ when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
+ true);
+ triggerBroadcastReceiverAndWait();
+ triggerBroadcastReceiverAndWait();
+
+ // expect we only updated once even though we got two broadcasts for user restriction
+ // updates
+ verify(tmSubscription, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+ // extra check to ensure we haven't also somehow updated back to enabled along the way
+ verify(tmSubscription, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ }
+
+ @Test
+ public void onUserRestrictionChanged_restrictionChanged_allowedNetworksUpdated() {
+ // precondition: we've updated allowed networks to the default (2g enabled)
+ TelephonyManager tmSubscription = addSubscriptionAndGetMock(1001);
+ triggerOnSubscriptionChangedAndWait();
+ verify(tmSubscription, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ verify(tmSubscription, never()).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+
+ // update the user restriction to disallow 2g
+ reset(tmSubscription);
+ when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
+ true);
+ triggerBroadcastReceiverAndWait();
+ verify(tmSubscription, never()).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ verify(tmSubscription, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+
+
+ // update the user restriction to allow 2g again
+ reset(tmSubscription);
when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
false);
-
- mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
-
- verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
+ triggerBroadcastReceiverAndWait();
+ verify(tmSubscription, times(1)).setAllowedNetworkTypesForReason(
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
- verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
- TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ verify(tmSubscription, never()).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+
}
private SubscriptionInfo getSubInfo(int id) {
return new SubscriptionInfo(id, "890126042XXXXXXXXXXX", 0, "T-mobile", "T-mobile", 0, 255,
"12345", 0, null, "310", "260", "156", false, null, null);
}
+
+ private void triggerOnSubscriptionChangedAndWait() {
+ mExecutor.execute(() -> mChangedListener.onSubscriptionsChanged());
+ drainSingleThreadedExecutor();
+ }
+
+ private void triggerBroadcastReceiverAndWait() {
+ mTelephony2gUpdater.onReceive(mContext, new Intent());
+ drainSingleThreadedExecutor();
+ }
+
+ /**
+ * Wait for all tasks on executor up to the point of invocation to drain, then return.
+ *
+ * This helper takes advantage of the fact that we're using an immutable single threaded
+ * executor that guarantees tasks are executed in the order they are enqueued. It enqueues a
+ * task that decrements a latch and then waits on that task to finish. By definition, once the
+ * test task finishes, all previously enqueued tasks will have also completed.
+ */
+ private void drainSingleThreadedExecutor() {
+ resetExecutorLatch();
+ mExecutor.execute(() -> mLatch.countDown());
+ try {
+ mLatch.await(DRAIN_TIMEOUT, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ private void resetExecutorLatch() {
+ mLatch = new CountDownLatch(1);
+ }
+
+ /**
+ * Helper that allows you to update subInfo and have that change reflected on subsequent calls
+ * to {@link SubscriptionManager#getCompleteActiveSubscriptionInfoList()}
+ */
+ private void setupMutableSubscriptionInfoMock() {
+ var answer = new Answer<List<SubscriptionInfo>>() {
+ @Override
+ public List<SubscriptionInfo> answer(InvocationOnMock invocation) throws Throwable {
+ return mCurrentSubscriptions;
+ }
+ };
+ when(mMockSubscriptionManager.getCompleteActiveSubscriptionInfoList()).thenAnswer(answer);
+ }
+
+ private TelephonyManager addSubscriptionAndGetMock(int subId) {
+ mCurrentSubscriptions.add(getSubInfo(subId));
+ TelephonyManager tmSubscription = mock(TelephonyManager.class);
+ when(mMockTelephonyManager.createForSubscriptionId(subId)).thenReturn(tmSubscription);
+ return tmSubscription;
+ }
+
}
diff --git a/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java b/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
index e2ebac0..921babb 100644
--- a/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
+++ b/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
@@ -70,7 +70,7 @@
@RunWith(AndroidJUnit4.class)
public class SlicePurchaseControllerTest extends TelephonyTestBase {
- private static final String TAG = "SlicePurchaseControllerTest";
+ private static final String CARRIER = "Some Carrier";
private static final String DAILY_NOTIFICATION_COUNT_KEY = "daily_notification_count0";
private static final String MONTHLY_NOTIFICATION_COUNT_KEY = "monthly_notification_count0";
private static final int YEAR = 2000;
@@ -148,6 +148,7 @@
mSlicePurchaseController = spy(slicePurchaseController);
doReturn(null).when(mSlicePurchaseController).createPendingIntent(
anyString(), anyInt(), anyBoolean());
+ doReturn(CARRIER).when(mSlicePurchaseController).getSimOperator();
replaceInstance(SlicePurchaseController.class, "sInstances", mSlicePurchaseController,
Map.of(PHONE_ID, mSlicePurchaseController));
replaceInstance(SlicePurchaseController.class, "mPremiumNetworkEntitlementApi",
@@ -272,8 +273,7 @@
@Test
public void testPurchasePremiumCapabilityResultFeatureNotSupported() {
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_FEATURE_NOT_SUPPORTED,
mResult);
@@ -283,8 +283,7 @@
.getCachedAllowedNetworkTypesBitmask();
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertNotEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_FEATURE_NOT_SUPPORTED,
mResult);
@@ -296,8 +295,7 @@
.getCachedAllowedNetworkTypesBitmask();
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED, mResult);
@@ -308,8 +306,7 @@
SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertNotEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED,
mResult);
@@ -325,8 +322,7 @@
SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(
TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION,
@@ -336,8 +332,7 @@
doReturn(SubscriptionManager.getDefaultDataSubscriptionId()).when(mPhone).getSubId();
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertNotEquals(
TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION,
@@ -355,8 +350,7 @@
doReturn(SubscriptionManager.getDefaultDataSubscriptionId()).when(mPhone).getSubId();
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE,
mResult);
@@ -365,8 +359,7 @@
doReturn(TelephonyManager.NETWORK_TYPE_NR).when(mServiceState).getDataNetworkType();
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertNotEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE,
mResult);
@@ -385,8 +378,7 @@
doReturn(null).when(mPremiumNetworkEntitlementApi).checkEntitlementStatus(anyInt());
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ENTITLEMENT_CHECK_FAILED,
mResult);
@@ -398,8 +390,7 @@
.checkEntitlementStatus(anyInt());
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED,
mResult);
@@ -409,8 +400,7 @@
PremiumNetworkEntitlementResponse.PREMIUM_NETWORK_PROVISION_STATUS_IN_PROGRESS;
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS,
mResult);
@@ -425,16 +415,14 @@
PURCHASE_CONDITION_TIMEOUT);
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ENTITLEMENT_CHECK_FAILED,
mResult);
// retry to verify throttled
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
@@ -450,16 +438,14 @@
sendValidPurchaseRequest();
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS,
mResult);
// retry to verify same result
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS,
mResult);
@@ -487,8 +473,7 @@
testPurchasePremiumCapabilityResultSuccess();
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP,
mResult);
@@ -507,16 +492,14 @@
sendNetworkSlicingConfig(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, true);
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED,
mResult);
// retry to verify same result
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED,
mResult);
@@ -537,8 +520,7 @@
// retry to verify throttled
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
@@ -565,8 +547,7 @@
// retry to verify throttled
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
@@ -596,8 +577,7 @@
// retry to verify throttled
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
@@ -660,8 +640,7 @@
// retry to verify throttled
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
@@ -678,8 +657,7 @@
// retry to verify throttled
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
}
@@ -741,8 +719,7 @@
// send purchase request
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
// verify that the purchase request was sent successfully
diff --git a/tests/src/com/android/services/telephony/TelephonyManagerTest.java b/tests/src/com/android/services/telephony/TelephonyManagerTest.java
index eec38ce..20c062f 100644
--- a/tests/src/com/android/services/telephony/TelephonyManagerTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyManagerTest.java
@@ -56,6 +56,10 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
/** Unit tests for {@link TelephonyManager}. */
@RunWith(AndroidJUnit4.class)
@@ -271,4 +275,24 @@
assertEquals("12345", mTelephonyManager.getPrimaryImei());
verify(mMockITelephony, times(1)).getPrimaryImei(anyString(), anyString());
}
-}
+
+ /**
+ * Verify calling getCarrierRestrictionStatus() with out exception
+ */
+ @Test
+ public void getCarrierRestrictionStatus() {
+ int TIMEOUT = 2 * 60; // 2 minutes
+ LinkedBlockingQueue<Integer> carrierRestrictionStatusResult = new LinkedBlockingQueue<>(1);
+ Executor executor = Executors.newSingleThreadExecutor();
+ mTelephonyManager.getCarrierRestrictionStatus(executor,
+ carrierRestrictionStatusResult::offer);
+ executor.execute(() -> {
+ try {
+ carrierRestrictionStatusResult.poll(TIMEOUT, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ fail();
+ }
+ });
+
+ }
+}
\ No newline at end of file
diff --git a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
index e1de0ab..aedfe9e 100644
--- a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
@@ -35,9 +35,14 @@
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL;
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL;
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_SCAN_TIMER_SEC_INT;
+import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT;
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT;
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL;
import static android.telephony.CarrierConfigManager.ImsEmergency.SCAN_TYPE_NO_PREFERENCE;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_NONE;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_SETTING_ENABLED;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_VALID_EID;
+import static android.telephony.CarrierConfigManager.ImsWfc.KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL;
import static android.telephony.DomainSelectionService.SELECTOR_TYPE_CALLING;
import static android.telephony.NetworkRegistrationInfo.DOMAIN_CS;
import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS;
@@ -62,6 +67,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkRequest;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IPowerManager;
@@ -82,6 +89,7 @@
import android.telephony.WwanSelectorCallback;
import android.telephony.ims.ImsManager;
import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ProvisioningManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.TestableLooper;
import android.util.Log;
@@ -111,12 +119,14 @@
private static final int SLOT_0_SUB_ID = 1;
@Mock private CarrierConfigManager mCarrierConfigManager;
+ @Mock private ConnectivityManager mConnectivityManager;
@Mock private TelephonyManager mTelephonyManager;
@Mock private WwanSelectorCallback mWwanSelectorCallback;
@Mock private TransportSelectorCallback mTransportSelectorCallback;
@Mock private ImsMmTelManager mMmTelManager;
@Mock private ImsStateTracker mImsStateTracker;
@Mock private DomainSelectorBase.DestroyListener mDestroyListener;
+ @Mock private ProvisioningManager mProvisioningManager;
private Context mContext;
@@ -126,6 +136,7 @@
private SelectionAttributes mSelectionAttributes;
private @AccessNetworkConstants.RadioAccessNetworkType List<Integer> mAccessNetwork;
private PowerManager mPowerManager;
+ private ConnectivityManager.NetworkCallback mNetworkCallback;
@Before
public void setUp() throws Exception {
@@ -141,6 +152,8 @@
return Context.CARRIER_CONFIG_SERVICE;
} else if (serviceClass == PowerManager.class) {
return Context.POWER_SERVICE;
+ } else if (serviceClass == ConnectivityManager.class) {
+ return Context.CONNECTIVITY_SERVICE;
}
return super.getSystemServiceName(serviceClass);
}
@@ -151,6 +164,9 @@
case (Context.POWER_SERVICE) : {
return mPowerManager;
}
+ case (Context.CONNECTIVITY_SERVICE) : {
+ return mConnectivityManager;
+ }
}
return super.getSystemService(name);
}
@@ -183,6 +199,17 @@
when(mCarrierConfigManager.getConfigForSubId(anyInt()))
.thenReturn(getDefaultPersistableBundle());
+ mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ mNetworkCallback = (ConnectivityManager.NetworkCallback)
+ invocation.getArguments()[1];
+ return null;
+ }
+ }).when(mConnectivityManager).registerNetworkCallback(
+ any(NetworkRequest.class), any(ConnectivityManager.NetworkCallback.class));
+
IPowerManager powerManager = mock(IPowerManager.class);
mPowerManager = new PowerManager(mContext, powerManager, mock(IThermalService.class),
new Handler(mHandlerThread.getLooper()));
@@ -190,6 +217,8 @@
ImsManager imsManager = mContext.getSystemService(ImsManager.class);
when(imsManager.getImsMmTelManager(anyInt())).thenReturn(mMmTelManager);
when(mMmTelManager.isAdvancedCallingSettingEnabled()).thenReturn(true);
+ doReturn(mProvisioningManager).when(imsManager).getProvisioningManager(anyInt());
+ doReturn(null).when(mProvisioningManager).getProvisioningStringValue(anyInt());
when(mTransportSelectorCallback.onWwanSelected()).thenReturn(mWwanSelectorCallback);
doAnswer(new Answer<Void>() {
@@ -835,7 +864,7 @@
}
@Test
- public void testVoLteOffEpsImsNotRegisteredSelectCs() throws Exception {
+ public void testVoLteOffEpsImsNotRegisteredScanCsPreferred() throws Exception {
PersistableBundle bundle = getDefaultPersistableBundle();
bundle.putBoolean(KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL, true);
when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
@@ -856,7 +885,7 @@
bindImsServiceUnregistered();
// Requires VoLTE enabled but VoLTE is'nt enabled.
- verifyCsDialed();
+ verifyScanCsPreferred();
}
@Test
@@ -882,6 +911,10 @@
@Test
public void testDefaultEpsImsRegisteredBarredScanTimeoutWifi() throws Exception {
+ PersistableBundle bundle = getDefaultPersistableBundle();
+ bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
+ when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
createSelector(SLOT_0_SUB_ID);
unsolBarringInfoChanged(true);
@@ -898,11 +931,159 @@
assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+ // Wi-Fi is not connected.
+ verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+ // Wi-Fi is connected.
+ mNetworkCallback.onAvailable(null);
mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
verify(mTransportSelectorCallback, times(1)).onWlanSelected();
}
+ @Test
+ public void testVoWifiSosPdnRequiresSettingEnabled() throws Exception {
+ PersistableBundle bundle = getDefaultPersistableBundle();
+ bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
+ bundle.putInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT, VOWIFI_REQUIRES_SETTING_ENABLED);
+ when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+ createSelector(SLOT_0_SUB_ID);
+ unsolBarringInfoChanged(true);
+
+ EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+ NetworkRegistrationInfo.DOMAIN_PS,
+ true, true, 0, 0, "", "");
+ SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+ mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+ bindImsServiceUnregistered();
+ processAllMessages();
+
+ assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+
+ mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+ // Wi-Fi is not connected.
+ verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+ // Wi-Fi is connected. But Wi-Fi calling setting is disabled.
+ mNetworkCallback.onAvailable(null);
+ when(mMmTelManager.isVoWiFiRoamingSettingEnabled()).thenReturn(false);
+ mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+ verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+ // Wi-Fi is connected and Wi-Fi calling setting is enabled.
+ when(mMmTelManager.isVoWiFiSettingEnabled()).thenReturn(true);
+ mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+ verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+ }
+
+ @Test
+ public void testVoWifiSosPdnRequiresValidEid() throws Exception {
+ PersistableBundle bundle = getDefaultPersistableBundle();
+ bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
+ bundle.putInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT, VOWIFI_REQUIRES_VALID_EID);
+ when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+ createSelector(SLOT_0_SUB_ID);
+ unsolBarringInfoChanged(true);
+
+ EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+ NetworkRegistrationInfo.DOMAIN_PS,
+ true, true, 0, 0, "", "");
+ SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+ mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+ bindImsServiceUnregistered();
+ processAllMessages();
+
+ assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+
+ mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+ // Wi-Fi is not connected.
+ verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+ // Wi-Fi is connected. But Wi-Fi calling s not activated.
+ mNetworkCallback.onAvailable(null);
+ mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+ verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+ // Wi-Fi is connected and Wi-Fi calling is activated.
+ doReturn("1").when(mProvisioningManager).getProvisioningStringValue(anyInt());
+ mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+ verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+ }
+
+ @Test
+ public void testVoWifiImsPdnRequiresNone() throws Exception {
+ createSelector(SLOT_0_SUB_ID);
+ unsolBarringInfoChanged(true);
+
+ EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+ NetworkRegistrationInfo.DOMAIN_PS,
+ true, true, 0, 0, "", "");
+ SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+ mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+ bindImsServiceUnregistered();
+ processAllMessages();
+
+ assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+
+ mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+ // Wi-Fi is not connected.
+ verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+ // Wi-Fi is connected but IMS is not registered over Wi-Fi.
+ mNetworkCallback.onAvailable(null);
+ mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+ verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+ // IMS is registered over Wi-Fi.
+ bindImsService(true);
+ mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+ verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+ }
+
+ @Test
+ public void testIgnoreDuplicatedCallbacks() throws Exception {
+ createSelector(SLOT_0_SUB_ID);
+ unsolBarringInfoChanged(true);
+
+ EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+ NetworkRegistrationInfo.DOMAIN_PS,
+ true, true, 0, 0, "", "");
+ SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+ mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+ processAllMessages();
+
+ bindImsService(true);
+
+ verify(mTransportSelectorCallback, times(1)).onWwanSelected(any());
+
+ // duplicated event
+ unsolBarringInfoChanged(true);
+
+ // ignore duplicated callback, no change in interaction
+ verify(mTransportSelectorCallback, times(1)).onWwanSelected(any());
+
+ mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+ verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+
+ // duplicated event
+ mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+ // ignore duplicated callback, no change in interaction
+ verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+ }
+
private void createSelector(int subId) throws Exception {
mDomainSelector = new EmergencyCallDomainSelector(
mContext, SLOT_0, subId, mHandlerThread.getLooper(),
@@ -913,10 +1094,12 @@
}
private void verifyCsDialed() {
+ processAllMessages();
verify(mWwanSelectorCallback, times(1)).onDomainSelected(eq(DOMAIN_CS));
}
private void verifyPsDialed() {
+ processAllMessages();
verify(mWwanSelectorCallback, times(1)).onDomainSelected(eq(DOMAIN_PS));
}
@@ -929,6 +1112,7 @@
}
private void verifyScanPreferred(int scanType, int expectedPreferredAccessNetwork) {
+ processAllMessages();
verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
any(), eq(scanType), any(), any());
assertEquals(expectedPreferredAccessNetwork, (int) mAccessNetwork.get(0));
@@ -989,8 +1173,10 @@
CarrierConfigManager.ImsEmergency.DOMAIN_PS_NON_3GPP
};
boolean imsWhenVoiceOnCs = false;
+ int voWifiRequiresCondition = VOWIFI_REQUIRES_NONE;
int maxRetriesOverWiFi = 1;
int cellularScanTimerSec = 10;
+ boolean voWifiOverEmergencyPdn = false;
int scanType = SCAN_TYPE_NO_PREFERENCE;
boolean requiresImsRegistration = false;
boolean requiresVoLteEnabled = false;
@@ -998,17 +1184,19 @@
String[] cdmaPreferredNumbers = new String[] {};
return getPersistableBundle(imsRats, csRats, imsRoamRats, csRoamRats,
- domainPreference, roamDomainPreference, imsWhenVoiceOnCs, maxRetriesOverWiFi,
- cellularScanTimerSec, scanType, requiresImsRegistration, requiresVoLteEnabled,
- ltePreferredAfterNrFailed, cdmaPreferredNumbers);
+ domainPreference, roamDomainPreference, imsWhenVoiceOnCs,
+ voWifiRequiresCondition, maxRetriesOverWiFi, cellularScanTimerSec,
+ scanType, voWifiOverEmergencyPdn, requiresImsRegistration,
+ requiresVoLteEnabled, ltePreferredAfterNrFailed, cdmaPreferredNumbers);
}
private static PersistableBundle getPersistableBundle(
@Nullable int[] imsRats, @Nullable int[] csRats,
@Nullable int[] imsRoamRats, @Nullable int[] csRoamRats,
@Nullable int[] domainPreference, @Nullable int[] roamDomainPreference,
- boolean imsWhenVoiceOnCs, int maxRetriesOverWiFi,
- int cellularScanTimerSec, int scanType, boolean requiresImsRegistration,
+ boolean imsWhenVoiceOnCs, int voWifiRequiresCondition,
+ int maxRetriesOverWiFi, int cellularScanTimerSec, int scanType,
+ boolean voWifiOverEmergencyPdn, boolean requiresImsRegistration,
boolean requiresVoLteEnabled, boolean ltePreferredAfterNrFailed,
@Nullable String[] cdmaPreferredNumbers) {
@@ -1039,8 +1227,10 @@
roamDomainPreference);
}
bundle.putBoolean(KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL, imsWhenVoiceOnCs);
+ bundle.putInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT, voWifiRequiresCondition);
bundle.putInt(KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT, maxRetriesOverWiFi);
bundle.putInt(KEY_EMERGENCY_SCAN_TIMER_SEC_INT, cellularScanTimerSec);
+ bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, voWifiOverEmergencyPdn);
bundle.putInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT, scanType);
bundle.putBoolean(KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL, requiresImsRegistration);
bundle.putBoolean(KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL, requiresVoLteEnabled);
diff --git a/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java b/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java
index b00926f..430adea 100644
--- a/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java
@@ -210,6 +210,23 @@
@Test
@SmallTest
+ public void testStartAfterUnavailableWithReasonSubscriptionInactive() throws ImsException {
+ ImsStateCallback callback = setUpImsStateCallback();
+ callback.onUnavailable(ImsStateCallback.REASON_SUBSCRIPTION_INACTIVE);
+
+ mImsStateTracker.start(SUB_1);
+
+ assertTrue(isImsStateInit());
+ // One is invoked in setUpImsStateCallback and the other is invoked in start(int).
+ verify(mMmTelManager, times(2)).registerImsStateCallback(
+ any(Executor.class), any(ImsStateCallback.class));
+ // ImsStateCallback has already been set to null when onUnavailable is called.
+ verify(mMmTelManager, never()).unregisterImsStateCallback(
+ any(ImsStateCallback.class));
+ }
+
+ @Test
+ @SmallTest
public void testUpdateServiceStateBeforeAddingListener() {
mImsStateTracker.updateServiceState(mServiceState);
mImsStateTracker.addServiceStateListener(mServiceStateListener);
@@ -509,6 +526,7 @@
assertFalse(mImsStateTracker.isImsStateReady());
assertTrue(mImsStateTracker.isImsRegistered());
assertFalse(mImsStateTracker.isImsRegisteredOverWlan());
+ assertFalse(mImsStateTracker.isImsRegisteredOverCrossSim());
assertEquals(AccessNetworkType.EUTRAN, mImsStateTracker.getImsAccessNetworkType());
callback.onRegistered(new ImsRegistrationAttributes.Builder(
@@ -517,6 +535,7 @@
assertFalse(mImsStateTracker.isImsStateReady());
assertTrue(mImsStateTracker.isImsRegistered());
assertFalse(mImsStateTracker.isImsRegisteredOverWlan());
+ assertFalse(mImsStateTracker.isImsRegisteredOverCrossSim());
assertEquals(AccessNetworkType.NGRAN, mImsStateTracker.getImsAccessNetworkType());
callback.onRegistered(new ImsRegistrationAttributes.Builder(
@@ -525,6 +544,16 @@
assertFalse(mImsStateTracker.isImsStateReady());
assertTrue(mImsStateTracker.isImsRegistered());
assertTrue(mImsStateTracker.isImsRegisteredOverWlan());
+ assertFalse(mImsStateTracker.isImsRegisteredOverCrossSim());
+ assertEquals(AccessNetworkType.IWLAN, mImsStateTracker.getImsAccessNetworkType());
+
+ callback.onRegistered(new ImsRegistrationAttributes.Builder(
+ ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM).build());
+
+ assertFalse(mImsStateTracker.isImsStateReady());
+ assertTrue(mImsStateTracker.isImsRegistered());
+ assertTrue(mImsStateTracker.isImsRegisteredOverWlan());
+ assertTrue(mImsStateTracker.isImsRegisteredOverCrossSim());
assertEquals(AccessNetworkType.IWLAN, mImsStateTracker.getImsAccessNetworkType());
callback.onRegistered(new ImsRegistrationAttributes.Builder(
@@ -533,9 +562,10 @@
assertFalse(mImsStateTracker.isImsStateReady());
assertTrue(mImsStateTracker.isImsRegistered());
assertFalse(mImsStateTracker.isImsRegisteredOverWlan());
+ assertFalse(mImsStateTracker.isImsRegisteredOverCrossSim());
assertEquals(AccessNetworkType.UNKNOWN, mImsStateTracker.getImsAccessNetworkType());
- verify(mImsStateListener, times(4)).onImsRegistrationStateChanged();
+ verify(mImsStateListener, times(5)).onImsRegistrationStateChanged();
}
@Test
diff --git a/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java
index 832e480..890ca34 100644
--- a/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/NormalCallDomainSelectorTest.java
@@ -77,7 +77,6 @@
@Mock private Context mMockContext;
@Mock private ImsManager mMockImsManager;
@Mock private ImsMmTelManager mMockMmTelManager;
- @Mock private ServiceState mMockServiceState;
@Mock private ImsStateTracker mMockImsStateTracker;
@Mock private DomainSelectorBase.DestroyListener mMockDestroyListener;
@@ -153,14 +152,14 @@
try {
mNormalCallDomainSelector.selectDomain(null, null);
} catch (Exception e) {
- fail("Invalid input params not handled.");
+ fail("Invalid input params not handled." + e.getMessage());
}
// Case 2: null TransportSelectorCallback
try {
mNormalCallDomainSelector.selectDomain(attributes, null);
} catch (Exception e) {
- fail("Invalid params (SelectionAttributes) not handled.");
+ fail("Invalid params (SelectionAttributes) not handled." + e.getMessage());
}
// Case 3: null SelectionAttributes
@@ -168,7 +167,7 @@
try {
mNormalCallDomainSelector.selectDomain(null, transportSelectorCallback);
} catch (Exception e) {
- fail("Invalid params (SelectionAttributes) not handled.");
+ fail("Invalid params (SelectionAttributes) not handled." + e.getMessage());
}
assertTrue(transportSelectorCallback
@@ -185,7 +184,7 @@
try {
mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
} catch (Exception e) {
- fail("Invalid params (SelectionAttributes) not handled.");
+ fail("Invalid params (SelectionAttributes) not handled." + e.getMessage());
}
assertTrue(transportSelectorCallback
@@ -201,9 +200,9 @@
.setExitedFromAirplaneMode(false)
.build();
try {
- mNormalCallDomainSelector.selectDomain(null, transportSelectorCallback);
+ mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
} catch (Exception e) {
- fail("Invalid params (SelectionAttributes) not handled.");
+ fail("Invalid params (SelectionAttributes) not handled." + e.getMessage());
}
assertTrue(transportSelectorCallback
@@ -211,16 +210,16 @@
// Case 6: Emergency Call
attributes = new DomainSelectionService.SelectionAttributes.Builder(
- SLOT_ID, SUB_ID_1, SELECTOR_TYPE_UT)
+ SLOT_ID, SUB_ID_1, SELECTOR_TYPE_CALLING)
.setCallId(TEST_CALLID)
.setEmergency(true)
.setVideoCall(true)
.setExitedFromAirplaneMode(false)
.build();
try {
- mNormalCallDomainSelector.selectDomain(null, transportSelectorCallback);
+ mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
} catch (Exception e) {
- fail("Invalid params (SelectionAttributes) not handled.");
+ fail("Invalid params (SelectionAttributes) not handled." + e.getMessage());
}
assertTrue(transportSelectorCallback
@@ -239,10 +238,10 @@
.setVideoCall(true)
.setExitedFromAirplaneMode(false)
.build();
- mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
ServiceState serviceState = new ServiceState();
serviceState.setStateOutOfService();
- mNormalCallDomainSelector.onServiceStateUpdated(serviceState);
+ initialize(serviceState, false, false, false, false);
+ mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
assertTrue(transportSelectorCallback
.verifyOnSelectionTerminated(DisconnectCause.OUT_OF_SERVICE));
}
@@ -303,15 +302,23 @@
assertTrue(transportSelectorCallback.verifyOnWwanSelected());
assertTrue(transportSelectorCallback
.verifyOnDomainSelected(NetworkRegistrationInfo.DOMAIN_CS));
+
+ //Case 5: Backup calling
+ serviceState.setStateOutOfService();
+ initialize(serviceState, true, true, true, true);
+ mNormalCallDomainSelector.selectDomain(attributes, transportSelectorCallback);
+ assertTrue(transportSelectorCallback.verifyOnWlanSelected());
}
- class MockTransportSelectorCallback implements TransportSelectorCallback, WwanSelectorCallback {
- public boolean mCreated = false;
- public boolean mWlanSelected = false;
- public boolean mWwanSelected = false;
- public boolean mSelectionTerminated = false;
- int mCauseCode = 0;
- int mSelectedDomain = 0;
+ static class MockTransportSelectorCallback implements TransportSelectorCallback,
+ WwanSelectorCallback {
+ public boolean mCreated;
+ public boolean mWlanSelected;
+ public boolean mWwanSelected;
+ public boolean mSelectionTerminated;
+ public boolean mDomainSelected;
+ int mCauseCode;
+ int mSelectedDomain;
@Override
public synchronized void onCreated(DomainSelector selector) {
@@ -323,7 +330,7 @@
public boolean verifyOnCreated() {
mCreated = false;
Log.d(TAG, "verifyOnCreated");
- waitForCallback();
+ waitForCallback(mCreated);
return mCreated;
}
@@ -336,7 +343,7 @@
public boolean verifyOnWlanSelected() {
Log.d(TAG, "verifyOnWlanSelected");
- waitForCallback();
+ waitForCallback(mWlanSelected);
return mWlanSelected;
}
@@ -356,7 +363,7 @@
}
public boolean verifyOnWwanSelected() {
- waitForCallback();
+ waitForCallback(mWwanSelected);
return mWwanSelected;
}
@@ -370,17 +377,20 @@
public boolean verifyOnSelectionTerminated(int cause) {
Log.i(TAG, "verifyOnSelectionTerminated - called");
- if (!mSelectionTerminated) {
- waitForCallback();
- }
+ waitForCallback(mSelectionTerminated);
return (mSelectionTerminated && cause == mCauseCode);
}
- private synchronized void waitForCallback() {
+ private synchronized void waitForCallback(boolean condition) {
+ long now = System.currentTimeMillis();
+ long deadline = now + 1000;
try {
- wait(1000);
+ while (!condition && now < deadline) {
+ wait(deadline - now);
+ now = System.currentTimeMillis();
+ }
} catch (Exception e) {
- return;
+ Log.i(TAG, e.getMessage());
}
}
@@ -396,12 +406,14 @@
public synchronized void onDomainSelected(@NetworkRegistrationInfo.Domain int domain) {
Log.i(TAG, "onDomainSelected - called");
mSelectedDomain = domain;
+ mDomainSelected = true;
notifyAll();
}
public boolean verifyOnDomainSelected(int domain) {
Log.i(TAG, "verifyOnDomainSelected - called");
- waitForCallback();
+ mDomainSelected = false;
+ waitForCallback(mDomainSelected);
return (domain == mSelectedDomain);
}
}