Merge "Revert "Fix conference call cannot be hung up""
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index ce774d8..f68b72e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -22,10 +22,6 @@
         android:sharedUserLabel="@string/phoneAppLabel"
 >
 
-    <uses-sdk
-        android:minSdkVersion="23"
-        android:targetSdkVersion="26" />
-
     <original-package android:name="com.android.phone" />
 
     <protected-broadcast android:name="android.telecom.action.TTY_PREFERRED_MODE_CHANGED" />
@@ -92,6 +88,10 @@
     <protected-broadcast android:name= "android.telephony.action.SIM_SLOT_STATUS_CHANGED" />
     <protected-broadcast android:name= "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED" />
     <protected-broadcast android:name= "android.telephony.action.SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED" />
+    <protected-broadcast android:name= "android.telephony.action.NETWORK_COUNTRY_CHANGED" />
+
+    <!-- For Vendor Debugging in Telephony -->
+    <protected-broadcast android:name="android.telephony.debug.action.DEBUG_EVENT" />
 
     <uses-permission android:name="android.permission.BROADCAST_STICKY" />
     <uses-permission android:name="android.permission.CALL_PHONE" />
@@ -194,6 +194,7 @@
     <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
     <uses-permission android:name="android.permission.BIND_TELEPHONY_DATA_SERVICE" />
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
+    <uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE" />
 
     <application android:name="PhoneApp"
             android:persistent="true"
diff --git a/ecc/README.md b/ecc/README.md
index b5dc538..304cdfb 100644
--- a/ecc/README.md
+++ b/ecc/README.md
@@ -30,4 +30,4 @@
 4. Make TeleService
 5. Push TeleService.apk to system/priv-app/TeleService
 6. Reboot device
-7. run 'atest TeleServiceTests:IsoToEccProtobufRepositoryTest#testEccDataContent'
+7. run 'atest TeleServiceTests:EccDataTest#testEccDataContent'
diff --git a/ecc/conversion_toolset_v1/verify_eccdata_compatibility.sh b/ecc/conversion_toolset_v1/verify_eccdata_compatibility.sh
new file mode 100644
index 0000000..8686722
--- /dev/null
+++ b/ecc/conversion_toolset_v1/verify_eccdata_compatibility.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+set -o errexit
+
+# Copyright 2018 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.
+
+LOCAL_TOOLSET_DIR="${ECC_ROOT}/conversion_toolset_v1"
+source "${LOCAL_TOOLSET_DIR}/env.sh"
+
+echo "Starting compatibility verification v1"
+echo "Decoding and decompressing eccdata"
+gunzip -c < "${OUTPUT_DATA}" > "${RAW_DATA}"
+${PYTHON_COMMAND} -B \
+  "${LOCAL_TOOLSET_DIR}/verify_protobuf_compatibility.py" \
+  --input="${RAW_DATA}"
+echo "Passed compatibility verification v1"
+
diff --git a/ecc/conversion_toolset_v1/verify_protobuf_compatibility.py b/ecc/conversion_toolset_v1/verify_protobuf_compatibility.py
new file mode 100644
index 0000000..bc707eb
--- /dev/null
+++ b/ecc/conversion_toolset_v1/verify_protobuf_compatibility.py
@@ -0,0 +1,85 @@
+#!/usr/bin/python -B
+
+# Copyright 2018 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.
+
+# Notice:
+# - verify_eccdata_strict.py: Verify data which is generated by this
+# version of this toolset.
+# - verify_eccdata_compatibility.py: Verify data which is generated by any
+# newer version of this tool set for ensuring backward compatibility.
+
+import sys
+import argparse
+import protobuf_ecc_data_pb2
+
+parser = argparse.ArgumentParser()
+parser.add_argument("--input", required=True)
+parser.add_argument("--strict", action="store_true")
+args = parser.parse_args()
+
+all_ecc_info = protobuf_ecc_data_pb2.AllInfo()
+
+with open(args.input, "rb") as ecc_data_source_file:
+  all_ecc_info.ParseFromString(ecc_data_source_file.read())
+
+if (args.strict):
+  print("Verify in strict mode")
+
+assert all_ecc_info.HasField("revision")
+assert all_ecc_info.revision > 0
+assert len(all_ecc_info.countries) > 0
+
+loaded_iso = []
+for country_info in all_ecc_info.countries:
+  assert country_info.HasField("iso_code")
+  assert len(country_info.iso_code) > 0
+  assert country_info.iso_code == country_info.iso_code.strip().upper()
+  assert country_info.iso_code not in loaded_iso
+  loaded_iso.append(country_info.iso_code)
+  assert country_info.HasField("ecc_fallback")
+  assert len(country_info.ecc_fallback) > 0
+
+  if len(country_info.eccs) > 0:
+    loaded_phone_number = []
+    for ecc_info in country_info.eccs:
+      assert ecc_info.HasField("phone_number")
+      phone_number = ecc_info.phone_number.strip()
+      assert len(phone_number) > 0
+      assert phone_number not in loaded_phone_number
+      loaded_phone_number.append(phone_number)
+
+      if (args.strict):
+        assert len(ecc_info.types) > 0
+        loaded_types = []
+        for ecc_type in ecc_info.types:
+          assert ecc_type == protobuf_ecc_data_pb2.EccInfo.POLICE or \
+              ecc_type == protobuf_ecc_data_pb2.EccInfo.AMBULANCE or \
+              ecc_type == protobuf_ecc_data_pb2.EccInfo.FIRE
+          assert ecc_type not in loaded_types
+          loaded_types.append(ecc_type)
+      else:
+        # For forward compatibility, ecc_info.types could be null if a phone
+        # number contains only new types which is not defined now. Just leave
+        # a warning message for this case.
+        if len(ecc_info.types) == 0:
+          print("WARNING: No recognizable type for " + \
+              country_info.iso_code + " - " + ecc_info.phone_number)
+        else:
+          loaded_types = []
+          for ecc_type in ecc_info.types:
+            assert ecc_type not in loaded_types
+            loaded_types.append(ecc_type)
+  elif (args.strict):
+    print("Warning: Empty ecc list for country " + country_info.iso_code)
diff --git a/ecc/gen_eccdata.sh b/ecc/gen_eccdata.sh
index 4f3a097..e4dd745 100755
--- a/ecc/gen_eccdata.sh
+++ b/ecc/gen_eccdata.sh
@@ -57,4 +57,4 @@
 echo "  1. make TeleService"
 echo "  2. push TeleService.apk to system/priv-app/TeleService"
 echo "  3. reboot device"
-echo "  4. run 'atest TeleServiceTests:IsoToEccProtobufRepositoryTest#testEccDataContent'"
+echo "  4. run 'atest TeleServiceTests:EccDataTest#testEccDataContent'"
diff --git a/res/layout/emergency_shortcut_buttons_group.xml b/res/layout/emergency_shortcut_buttons_group.xml
index 7911f30..54563c9 100644
--- a/res/layout/emergency_shortcut_buttons_group.xml
+++ b/res/layout/emergency_shortcut_buttons_group.xml
@@ -77,4 +77,4 @@
         android:divider="@drawable/emergency_shortcuts_divider"
         android:showDividers="middle">
     </LinearLayout>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/res/layout/pref_dialog_editpin.xml b/res/layout/pref_dialog_editpin.xml
index a278690..94cdadf 100644
--- a/res/layout/pref_dialog_editpin.xml
+++ b/res/layout/pref_dialog_editpin.xml
@@ -22,7 +22,7 @@
     android:orientation="vertical"
     android:padding="?android:attr/dialogPreferredPadding">
 
-    <TextView android:id="@+android:id/message"
+    <TextView android:id="@android:id/message"
         style="?android:attr/textAppearanceSmall"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index c483565..37d5af3 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -131,7 +131,7 @@
     <string name="stk_cc_ss_to_ussd_error" msgid="6095812685884176176">"SS zahtjev je izmijenjen u USSD zahtjev"</string>
     <string name="stk_cc_ss_to_ss_error" msgid="7920654012697945858">"Izmijenjeno u novi SS zahtjev"</string>
     <string name="stk_cc_ss_to_dial_video_error" msgid="3873905132181743781">"SS zahtjev je izmijenjen u video poziv"</string>
-    <string name="fdn_check_failure" msgid="18200614306525434">"Uključena je postavka brojeva fiksnog biranja u Aplikaciji za telefon. Zbog toga ne rade neke funkcije vezane za pozive."</string>
+    <string name="fdn_check_failure" msgid="18200614306525434">"Uključena je postavka brojeva fiksnog biranja u aplikaciji Telefon. Zbog toga ne rade neke funkcije vezane za pozive."</string>
     <string name="radio_off_error" msgid="2304459933248513376">"Uključite radio prije prikazivanja ovih postavki."</string>
     <string name="close_dialog" msgid="2365884406356986917">"Uredu"</string>
     <string name="enable" msgid="7248657275000173526">"Uključi"</string>
@@ -172,7 +172,7 @@
     <string name="select_automatically" msgid="1046727200631770962">"Automatski odaberi mrežu"</string>
     <string name="manual_mode_disallowed_summary" msgid="70662262085937277">"Nedostupno kada ste povezani na mrežu %1$s"</string>
     <string name="network_select_title" msgid="7733107364757544558">"Mreža"</string>
-    <string name="register_automatically" msgid="6017849844573519637">"Automatska registracija u toku…"</string>
+    <string name="register_automatically" msgid="6017849844573519637">"Automatska registracija…"</string>
     <string name="preferred_network_mode_title" msgid="2336624679902659306">"Preferirana vrsta mreže"</string>
     <string name="preferred_network_mode_summary" msgid="1434820673166126609">"Promijeni način rada mreže"</string>
     <string name="preferred_network_mode_dialogtitle" msgid="4048082093347807230">"Preferirana vrsta mreže"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 58565c8..707d731 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -385,7 +385,7 @@
     <item msgid="6043847456049107742">"1"</item>
   </string-array>
     <string name="cdma_activate_device" msgid="3793805892364814518">"Activació del dispositiu"</string>
-    <string name="cdma_lte_data_service" msgid="4255018217292548962">"Configuració del servei de dades"</string>
+    <string name="cdma_lte_data_service" msgid="4255018217292548962">"Configura el servei de dades"</string>
     <string name="carrier_settings_title" msgid="9028166176523012300">"Configuració d\'operador"</string>
     <string name="fdn" msgid="7878832555095183202">"Números de marcatge fix"</string>
     <string name="fdn_with_label" msgid="187084204115493366">"Números de marcatge fix (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index b44d876..24caf82 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="phoneAppLabel" product="tablet" msgid="8576272342240415145">"Données mobiles"</string>
+    <string name="phoneAppLabel" product="tablet" msgid="8576272342240415145">"Données cellulaires"</string>
     <string name="phoneAppLabel" product="default" msgid="6790717591729922998">"Services téléphoniques"</string>
     <string name="emergencyDialerIconLabel" msgid="7812140032168171053">"Appels d\'urgence"</string>
     <string name="phoneIconLabel" msgid="2331230813161304895">"Téléphone"</string>
@@ -245,7 +245,7 @@
     <string name="roaming_enable" msgid="7331106985174381987">"Se connecter aux services de données lors de l\'itinérance"</string>
     <string name="roaming_disable" msgid="1843417228755568110">"Se connecter aux services de données lors de l\'itinérance"</string>
     <string name="roaming_reenable_message" msgid="6843814381576397939">"L\'itinérance des données est désactivée. Touchez pour l\'activer."</string>
-    <string name="roaming_notification_title" msgid="4749053220884743110">"Connexion de données mobiles perdue"</string>
+    <string name="roaming_notification_title" msgid="4749053220884743110">"Connexion de données cellulaires perdue"</string>
     <string name="roaming_warning" msgid="1603164667540144353">"Des frais importants peuvent s\'appliquer."</string>
     <string name="roaming_check_price_warning" msgid="7497570906830902550">"Communiquez avec votre fournisseur réseau pour connaître les tarifs."</string>
     <string name="roaming_alert_title" msgid="3654815360303826008">"Autoriser les données en itinérance?"</string>
@@ -260,7 +260,7 @@
     <string name="data_usage_disable_mobile" msgid="3577275288809667615">"Désactiver les données mobiles?"</string>
     <string name="sim_selection_required_pref" msgid="7049424902961844236">"Sélection requise"</string>
     <string name="sim_change_data_title" msgid="5332425991853799280">"Changer de SIM pour les données?"</string>
-    <string name="sim_change_data_message" msgid="2163963581444907496">"Utiliser la carte SIM <xliff:g id="NEW_SIM">%1$s</xliff:g> au lieu de la carte <xliff:g id="OLD_SIM">%2$s</xliff:g> pour les données mobiles?"</string>
+    <string name="sim_change_data_message" msgid="2163963581444907496">"Utiliser la carte SIM <xliff:g id="NEW_SIM">%1$s</xliff:g> au lieu de la carte <xliff:g id="OLD_SIM">%2$s</xliff:g> pour les données cellulaires?"</string>
     <string name="wifi_calling_settings_title" msgid="7741961465416430470">"Appels Wi-Fi"</string>
     <string name="video_calling_settings_title" msgid="539714564273795574">"Appels vidéo par l\'entremise du fournisseur de services"</string>
     <string name="gsm_umts_options" msgid="6538311689850981686">"Options GSM/UMTS"</string>
@@ -570,7 +570,7 @@
     <string name="ota_hfa_activation_title" msgid="2234246934160473981">"Activation en cours…"</string>
     <string name="ota_hfa_activation_dialog_message" msgid="8092479227918463415">"Le téléphone est en train d\'activer votre service de données cellulaires.\n\nCela peut prendre jusqu\'à cinq minutes."</string>
     <string name="ota_skip_activation_dialog_title" msgid="2943366608272261306">"Ignorer l\'activation?"</string>
-    <string name="ota_skip_activation_dialog_message" msgid="2440770373498870550">"Si vous poursuivez sans activer votre mobile, vous ne pourrez ni téléphoner, ni vous connecter à des réseaux de données mobiles. La connexion à un réseau Wi-Fi reste possible. Vous serez invité à effectuer l\'activation à chaque démarrage du téléphone."</string>
+    <string name="ota_skip_activation_dialog_message" msgid="2440770373498870550">"Si vous poursuivez sans activer votre appareil mobile, vous ne pourrez ni téléphoner, ni vous connecter à des réseaux de données cellulaires. La connexion à un réseau Wi-Fi reste possible. Vous serez invité à effectuer l\'activation à chaque démarrage du téléphone."</string>
     <string name="ota_skip_activation_dialog_skip_label" msgid="3458532775091563208">"Passer"</string>
     <string name="ota_activate" msgid="1368528132525626264">"Activer"</string>
     <string name="ota_title_activate_success" msgid="6570240212263372046">"Votre téléphone est activé"</string>
@@ -654,12 +654,12 @@
     <string name="mobile_data_status_roaming_turned_on_subtext" msgid="1335176927083781041">"L\'itinérance de données est activée"</string>
     <string name="mobile_data_status_roaming_without_plan_subtext" msgid="3568412513831673037">"En itinérance. Un forfait de données est requis"</string>
     <string name="mobile_data_status_roaming_with_plan_subtext" msgid="8721998948811064377">"En itinérance. Le forfait de données est actif"</string>
-    <string name="mobile_data_status_no_plan_subtext" msgid="4887747337017565725">"Il ne reste plus de données mobiles"</string>
-    <string name="mobile_data_activate_prepaid" msgid="7447025165850512683">"Il ne reste plus de données mobiles"</string>
-    <string name="mobile_data_activate_prepaid_summary" msgid="5705389791791637666">"Ajouter des données mobiles par l\'intermédiaire de <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
+    <string name="mobile_data_status_no_plan_subtext" msgid="4887747337017565725">"Il ne reste plus de données cellulaires"</string>
+    <string name="mobile_data_activate_prepaid" msgid="7447025165850512683">"Il ne reste plus de données cellulaires"</string>
+    <string name="mobile_data_activate_prepaid_summary" msgid="5705389791791637666">"Ajouter des données cellulaires par l\'intermédiaire de <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
     <string name="mobile_data_activate_roaming_plan" msgid="5998161536947086264">"Aucun forfait d\'itinérance"</string>
     <string name="mobile_data_activate_roaming_plan_summary" msgid="511202908883425459">"Ajouter un forfait d\'itinérance par l\'intermédiaire de <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
-    <string name="mobile_data_activate_footer" msgid="5979019929980140594">"Vous pouvez ajouter des données mobiles ou un forfait d\'itinérance par l\'intermédiaire de votre fournisseur de services, <xliff:g id="PROVIDER_NAME">%s</xliff:g>."</string>
+    <string name="mobile_data_activate_footer" msgid="5979019929980140594">"Vous pouvez ajouter des données cellulaires ou un forfait d\'itinérance par l\'intermédiaire de votre fournisseur de services, <xliff:g id="PROVIDER_NAME">%s</xliff:g>."</string>
     <string name="mobile_data_activate_diag_title" msgid="9044252207707864493">"Ajouter des données?"</string>
     <string name="mobile_data_activate_diag_message" msgid="8216154678758451453">"Vous devrez peut-être ajouter des données par l\'intermédiaire de <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
     <string name="mobile_data_activate_button" msgid="3682400969184405446">"AJOUTER DES DONNÉES"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 8efa8c7..e2616ae 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -276,11 +276,11 @@
     <!-- String.format failed for translation -->
     <!-- no translation found for throttle_data_usage_subtext (6029276011123694701) -->
     <skip />
-    <string name="throttle_data_rate_reduced_subtext" msgid="7492763592720107737">"<xliff:g id="USED_0">%1$s</xliff:g> առավելագույնը գերազանցվել է\nՏվյալների արժեքը նվազել է մինչև <xliff:g id="USED_1">%2$d</xliff:g> կբիթ/վ"</string>
+    <string name="throttle_data_rate_reduced_subtext" msgid="7492763592720107737">"<xliff:g id="USED_0">%1$s</xliff:g> առավելագույնը գերազանցվել է\nՏվյալների արժեքը նվազել է մինչև <xliff:g id="USED_1">%2$d</xliff:g> Կբիթ/վ"</string>
     <!-- String.format failed for translation -->
     <!-- no translation found for throttle_time_frame_subtext (7732763021560399960) -->
     <skip />
-    <string name="throttle_rate_subtext" msgid="2149102656120726855">"Տվյալների ծավալը կնվազի մինչև <xliff:g id="USED">%1$d</xliff:g> կբիթ/վ, եթե տվյալների օգտագործման սահմանաչափը գերազանցվի"</string>
+    <string name="throttle_rate_subtext" msgid="2149102656120726855">"Տվյալների ծավալը կնվազի մինչև <xliff:g id="USED">%1$d</xliff:g> Կբիթ/վ, եթե տվյալների օգտագործման սահմանաչափը գերազանցվի"</string>
     <string name="throttle_help_subtext" msgid="5217706521499010816">"Լրացուցիչ տեղեկություններ ձեր սպասարկողի բջջային ցանցի տվյալների օգտագործման քաղաքականության մասին"</string>
     <string name="cell_broadcast_sms" msgid="5584192824053625842">"Բջջային հեռարձակման SMS"</string>
     <string name="enable_disable_cell_bc_sms" msgid="4851147873691392255">"Բջջային հեռարձակման SMS"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 26efa51..d112f09 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -46,7 +46,7 @@
     <string name="no_vm_number_msg" msgid="1300729501030053828">"सिम कार्डवर कोणताही व्हॉइसमेल नंबर स्टोअर केला नाही."</string>
     <string name="add_vm_number_str" msgid="4676479471644687453">"नंबर जोडा"</string>
     <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"केवळ प्राथमिक वापरकर्ता व्हॉइसमेल सेटिंग्ज बदलू शकतो."</string>
-    <string name="puk_unlocked" msgid="2284912838477558454">"आपले सिम कार्ड अवरोधित करणे रद्द केले गेले आहे. आपला फोन अनलॉक होत आहे…"</string>
+    <string name="puk_unlocked" msgid="2284912838477558454">"तुमचे सिम कार्ड अवरोधित करणे रद्द केले गेले आहे. तुमचा फोन अनलॉक होत आहे…"</string>
     <string name="label_ndp" msgid="780479633159517250">"सिम नेटवर्क अनलॉक पिन"</string>
     <string name="sim_ndp_unlock_text" msgid="683628237760543009">"अनलॉक करा"</string>
     <string name="sim_ndp_dismiss_text" msgid="1604823375752456947">"डिसमिस करा"</string>
@@ -107,17 +107,17 @@
     <string name="messageCFB" msgid="3711089705936187129">"नंबर व्‍यस्‍त असताना"</string>
     <string name="sum_cfb_enabled" msgid="5984198104833116690">"<xliff:g id="PHONENUMBER">{0}</xliff:g> वर अग्रेषित करत आहे"</string>
     <string name="sum_cfb_disabled" msgid="4913145177320506827">"बंद"</string>
-    <string name="disable_cfb_forbidden" msgid="3506984333877998061">"आपला फोन व्‍यस्‍त असताना आपला ऑपरेटर कॉल अग्रेषण करणे अक्षम करण्‍यास समर्थन करीत नाही."</string>
+    <string name="disable_cfb_forbidden" msgid="3506984333877998061">"तुमचा फोन व्‍यस्‍त असताना तुमचा ऑपरेटर कॉल अग्रेषण करणे अक्षम करण्‍यास समर्थन करीत नाही."</string>
     <string name="labelCFNRy" msgid="1736067178393744351">"उत्तर न दिल्यास"</string>
     <string name="messageCFNRy" msgid="672317899884380374">"नंबर अनुत्तरित असताना"</string>
     <string name="sum_cfnry_enabled" msgid="6955775691317662910">"<xliff:g id="PHONENUMBER">{0}</xliff:g> वर अग्रेषित करत आहे"</string>
     <string name="sum_cfnry_disabled" msgid="3884684060443538097">"बंद"</string>
-    <string name="disable_cfnry_forbidden" msgid="4308233959150658058">"आपला फोन उत्तर देत नसताना आपला ऑपरेटर कॉल अग्रेषण करणे अक्षम करण्‍यास समर्थन करीत नाही."</string>
+    <string name="disable_cfnry_forbidden" msgid="4308233959150658058">"तुमचा फोन उत्तर देत नसताना तुमचा ऑपरेटर कॉल अग्रेषण करणे अक्षम करण्‍यास समर्थन करीत नाही."</string>
     <string name="labelCFNRc" msgid="2614827454402079766">"पोहचण्‍यायोग्‍य नसताना"</string>
     <string name="messageCFNRc" msgid="6380695421020295119">"नंबर पोहचण्‍यायोग्‍य नसताना"</string>
     <string name="sum_cfnrc_enabled" msgid="7010898346095497421">"<xliff:g id="PHONENUMBER">{0}</xliff:g> वर अग्रेषित करत आहे"</string>
     <string name="sum_cfnrc_disabled" msgid="2684474391807469832">"बंद"</string>
-    <string name="disable_cfnrc_forbidden" msgid="5646361343094064333">"आपला फोन पोहचण्‍यायोग्‍य नसताना आपला वाहक कॉल अग्रेषण करणे अक्षम करण्‍यास समर्थन करीत नाही."</string>
+    <string name="disable_cfnrc_forbidden" msgid="5646361343094064333">"तुमचा फोन पोहचण्‍यायोग्‍य नसताना तुमचा वाहक कॉल अग्रेषण करणे अक्षम करण्‍यास समर्थन करीत नाही."</string>
     <string name="updating_title" msgid="6146755386174019046">"कॉल सेटिंग्ज"</string>
     <string name="call_settings_admin_user_only" msgid="4526094783818216374">"कॉल सेटिंग्ज केवळ प्रशासक वापरकर्त्याद्वारे बदलल्‍या जाऊ शकतात."</string>
     <string name="call_settings_with_label" msgid="3401177261468593519">"सेटिंग्ज (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
@@ -148,7 +148,7 @@
     <string name="fw_get_in_vm_failed" msgid="8862896836093833973">"वर्तमान अग्रेषण नंबर सेटिंग्‍ज पुनर्प्राप्त करू शकलो नाही आणि सेव्ह करू शकलो नाही.\nतरीही नवीन प्रदात्‍यावर स्‍विच करायचे?"</string>
     <string name="no_change" msgid="3186040086622435212">"कोणतेही बदल केले नाहीत."</string>
     <string name="sum_voicemail_choose_provider" msgid="59911196126278922">"व्हॉइसमेल सेवा निवडा"</string>
-    <string name="voicemail_default" msgid="2001233554889016880">"आपला वाहक"</string>
+    <string name="voicemail_default" msgid="2001233554889016880">"तुमचा वाहक"</string>
     <string name="vm_change_pin_old_pin" msgid="7295220109886682573">"जुना पिन"</string>
     <string name="vm_change_pin_new_pin" msgid="5412922262839438097">"नवीन पिन"</string>
     <string name="vm_change_pin_progress_message" msgid="3977357361934350336">"कृपया प्रतीक्षा करा."</string>
@@ -165,7 +165,7 @@
     <string name="empty_networks_list" msgid="4249426905018815316">"कोणतीही नेटवर्क आढळली नाहीत."</string>
     <string name="network_query_error" msgid="8466081377231178298">"नेटवर्क मिळू शकले नाहीत. पुन्‍हा प्रयत्‍न करा."</string>
     <string name="register_on_network" msgid="9055203954040805084">"<xliff:g id="NETWORK">%s</xliff:g> वर नोंदणी करत आहे…"</string>
-    <string name="not_allowed" msgid="5613353860205691579">"आपले सिम कार्ड या नेटवर्कच्‍या कनेक्‍शनला अनुमती देत नाही."</string>
+    <string name="not_allowed" msgid="5613353860205691579">"तुमचे सिम कार्ड या नेटवर्कच्‍या कनेक्‍शनला अनुमती देत नाही."</string>
     <string name="connect_later" msgid="2308119155752343975">"आत्ता या नेटवर्कशी कनेक्‍ट करू शकत नाही. नंतर पुन्‍हा प्रयत्‍न करा."</string>
     <string name="registration_done" msgid="495135664535876612">"नेटवर्कवर नोंदणी केली."</string>
     <string name="already_auto" msgid="6067116884321285507">"आपोआप निवडीमध्‍ये आधीपासून आहे."</string>
@@ -426,7 +426,7 @@
     <string name="delete_fdn_contact" msgid="6668958073074151717">"निश्चित डायलिंग नंबर हटवा"</string>
     <string name="deleting_fdn_contact" msgid="5669163206349319969">"निश्चित डायलिंग नंबर हटवित आहे..."</string>
     <string name="fdn_contact_deleted" msgid="7154162327112259569">"निश्चित डायलिंग नंबर हटवला."</string>
-    <string name="pin2_invalid" msgid="5470854099230755944">"आपण चुकीचा पिन टाईप केल्‍याने FDN अपडेट केले नव्‍हते."</string>
+    <string name="pin2_invalid" msgid="5470854099230755944">"तुम्ही चुकीचा पिन टाईप केल्‍याने FDN अपडेट केले नव्‍हते."</string>
     <string name="fdn_invalid_number" msgid="2062898833049589309">"FDN अपडेट केलेले नाही, कारण क्रमांक २० अंकांनी जास्‍त होत आहेत."</string>
     <string name="pin2_or_fdn_invalid" msgid="6025144083384701197">"FDN अपडेट केले नव्‍हते. PIN2 चुकीचा होता किंवा फोन नंबरला नकार दिला."</string>
     <string name="fdn_failed" msgid="540018079008319747">"FDN कार्य अयशस्‍वी झाले."</string>
@@ -440,8 +440,8 @@
     <string name="oldPinLabel" msgid="5287773661246368314">"जुना पिन"</string>
     <string name="newPinLabel" msgid="207488227285336897">"नवीन पिन"</string>
     <string name="confirmPinLabel" msgid="257597715098070206">"नवीन पिन ची पुष्‍टी करा"</string>
-    <string name="badPin" msgid="8955102849303984935">"आपण टाईप केलेला जुना पिन बरोबर नाही. पुन्‍हा प्रयत्‍न करा."</string>
-    <string name="mismatchPin" msgid="5923253370683071889">"आपण टाईप केले ते पिन जुळत नाहीत. पुन्‍हा प्रयत्‍न करा."</string>
+    <string name="badPin" msgid="8955102849303984935">"तुम्ही टाईप केलेला जुना पिन बरोबर नाही. पुन्‍हा प्रयत्‍न करा."</string>
+    <string name="mismatchPin" msgid="5923253370683071889">"तुम्ही टाईप केले ते पिन जुळत नाहीत. पुन्‍हा प्रयत्‍न करा."</string>
     <string name="invalidPin" msgid="5981171102258684792">"4 ते 8 अंकांचा पिन टाईप करा."</string>
     <string name="disable_sim_pin" msgid="3419351358300716472">"सिम पिन साफ करा"</string>
     <string name="enable_sim_pin" msgid="4845145659651484248">"सिम पिन सेट करा"</string>
@@ -561,12 +561,12 @@
   </string-array>
     <string name="network_info_message" msgid="7738596060242881930">"नेटवर्क मेसेज"</string>
     <string name="network_error_message" msgid="3394780436230411413">"एरर मेसेज"</string>
-    <string name="ota_title_activate" msgid="8616918561356194398">"आपला फोन सक्रिय करा"</string>
-    <string name="ota_touch_activate" msgid="6553212803262586244">"तुमची फोन सेवा सक्रिय करण्‍यासाठी एक विशिष्‍ट कॉल केला जाणे आवश्‍यक आहे. \n\n“सक्रिय करा” दाबल्‍यानंतर, आपला फोन सक्रिय करण्‍यासाठी प्रदान केलेल्‍या सूचना ऐका."</string>
+    <string name="ota_title_activate" msgid="8616918561356194398">"तुमचा फोन सक्रिय करा"</string>
+    <string name="ota_touch_activate" msgid="6553212803262586244">"तुमची फोन सेवा सक्रिय करण्‍यासाठी एक विशिष्‍ट कॉल केला जाणे आवश्‍यक आहे. \n\n“सक्रिय करा” दाबल्‍यानंतर, तुमचा फोन सक्रिय करण्‍यासाठी प्रदान केलेल्‍या सूचना ऐका."</string>
     <string name="ota_hfa_activation_title" msgid="2234246934160473981">"सक्रिय करत आहे..."</string>
     <string name="ota_hfa_activation_dialog_message" msgid="8092479227918463415">"फोन तुमची मोबाइल डेटा सेवा सक्रिय करत आहे.\n\nयास सुमारे 5 मिनिटे लागतील."</string>
     <string name="ota_skip_activation_dialog_title" msgid="2943366608272261306">"सक्रिय करणे वगळायचे?"</string>
-    <string name="ota_skip_activation_dialog_message" msgid="2440770373498870550">"आपण सक्रिय करणे वगळल्‍यास, आपण कॉल करू शकत नाही किंवा मोबाइल डेटा नेटवर्कशी कनेक्‍ट करू शकत नाही (आपण वाय-फाय नेटवर्कशी कनेक्‍ट करू शकत असला तरीही). आपण आपला फोन सक्रिय करेपर्यंत, आपण तो प्रत्‍येक वेळी चालू करताना आपल्‍याला तो सक्रिय करण्‍यास सांगितले जाईल."</string>
+    <string name="ota_skip_activation_dialog_message" msgid="2440770373498870550">"तुम्ही सक्रिय करणे वगळल्‍यास, तुम्ही कॉल करू शकत नाही किंवा मोबाइल डेटा नेटवर्कशी कनेक्‍ट करू शकत नाही (तुम्ही वाय-फाय नेटवर्कशी कनेक्‍ट करू शकत असला तरीही). तुम्ही तुमचा फोन सक्रिय करेपर्यंत, तुम्ही तो प्रत्‍येक वेळी चालू करताना आपल्‍याला तो सक्रिय करण्‍यास सांगितले जाईल."</string>
     <string name="ota_skip_activation_dialog_skip_label" msgid="3458532775091563208">"वगळा"</string>
     <string name="ota_activate" msgid="1368528132525626264">"सक्रिय करा"</string>
     <string name="ota_title_activate_success" msgid="6570240212263372046">"फोन सक्रिय केला आहे."</string>
@@ -574,9 +574,9 @@
     <string name="ota_listen" msgid="162923839877584937">"सक्रिय करणे पूर्ण झाले आहे असे आपल्‍याला ऐकू येईपर्यंत बोललेल्‍या सूचनांचे फॉलो करा."</string>
     <string name="ota_speaker" msgid="6904589278542719647">"स्पीकर"</string>
     <string name="ota_progress" msgid="460876637828044519">"आपल्‍या फोनचे प्रोग्रामिंग करत आहे…"</string>
-    <string name="ota_failure" msgid="7713756181204620397">"आपला फोन प्रोग्राम करणे शक्य झाले नाही"</string>
-    <string name="ota_successful" msgid="1880780692887077407">"आपला फोन आता सक्रिय केला आहे. सेवा सुरू होण्‍यास सुमारे 15 मिनिटे लागू शकतात."</string>
-    <string name="ota_unsuccessful" msgid="8072141612635635357">"आपला फोन सक्रिय केला नव्‍हता. \nआपल्‍याला अधिक चांगले कव्‍हरेज असलेले क्षेत्र (खिडकीजवळ किंवा बाहेर) शोधण्‍याची आवश्‍यकता असू शकते. \n\nपुन्‍हा प्रयत्‍न करा किंवा अधिक पर्यायांसाठी ग्राहक सेवेस कॉल करा."</string>
+    <string name="ota_failure" msgid="7713756181204620397">"तुमचा फोन प्रोग्राम करणे शक्य झाले नाही"</string>
+    <string name="ota_successful" msgid="1880780692887077407">"तुमचा फोन आता सक्रिय केला आहे. सेवा सुरू होण्‍यास सुमारे 15 मिनिटे लागू शकतात."</string>
+    <string name="ota_unsuccessful" msgid="8072141612635635357">"तुमचा फोन सक्रिय केला नव्‍हता. \nआपल्‍याला अधिक चांगले कव्‍हरेज असलेले क्षेत्र (खिडकीजवळ किंवा बाहेर) शोधण्‍याची आवश्‍यकता असू शकते. \n\nपुन्‍हा प्रयत्‍न करा किंवा अधिक पर्यायांसाठी ग्राहक सेवेस कॉल करा."</string>
     <string name="ota_spc_failure" msgid="3909983542575030796">"अत्‍याधिक SPC अपयश"</string>
     <string name="ota_call_end" msgid="4537279738134612388">"मागील"</string>
     <string name="ota_try_again" msgid="7685477206465902290">"पुन्हा प्रयत्न करा"</string>
@@ -587,12 +587,12 @@
     <string name="phone_in_ecm_call_notification_text" msgid="4611608947314729773">"डेटा कनेक्शन अक्षम केले"</string>
     <string name="phone_in_ecm_notification_complete_time" msgid="7730376844178948351">"<xliff:g id="COMPLETETIME">%s</xliff:g> पर्यंत कोणतेही डेटा कनेक्‍शन नाही"</string>
     <plurals name="alert_dialog_exit_ecm" formatted="false" msgid="7179911675595441201">
-      <item quantity="one">फोन <xliff:g id="COUNT_1">%s</xliff:g> मिनिटासाठी आणीबाणी कॉलबॅक मोडमध्ये राहील. या मोडमध्ये असताना डेटा कनेक्शन वापरणारे कोणतेही अॅप्लिकेशन वापरले जाऊ शकत नाहीत. आपण आता बाहेर पडू इच्छिता?</item>
-      <item quantity="other">फोन <xliff:g id="COUNT_1">%s</xliff:g> मिनिटांसाठी आणीबाणी कॉलबॅक मोडमध्ये राहील. या मोडमध्ये असताना डेटा कनेक्शन वापरणारे कोणतेही अॅप्लिकेशन वापरले जाऊ शकत नाहीत. आपण आता बाहेर पडू इच्छिता?</item>
+      <item quantity="one">फोन <xliff:g id="COUNT_1">%s</xliff:g> मिनिटासाठी आणीबाणी कॉलबॅक मोडमध्ये राहील. या मोडमध्ये असताना डेटा कनेक्शन वापरणारे कोणतेही अॅप्लिकेशन वापरले जाऊ शकत नाहीत. तुम्ही आता बाहेर पडू इच्छिता?</item>
+      <item quantity="other">फोन <xliff:g id="COUNT_1">%s</xliff:g> मिनिटांसाठी आणीबाणी कॉलबॅक मोडमध्ये राहील. या मोडमध्ये असताना डेटा कनेक्शन वापरणारे कोणतेही अॅप्लिकेशन वापरले जाऊ शकत नाहीत. तुम्ही आता बाहेर पडू इच्छिता?</item>
     </plurals>
     <plurals name="alert_dialog_not_avaialble_in_ecm" formatted="false" msgid="8042973425225093895">
-      <item quantity="one">आणीबाणी कॉलबॅक मोडमध्ये असताना निवडलेली क्रिया उपलब्ध नसते. फोन <xliff:g id="COUNT_1">%s</xliff:g> मिनिटासाठी या मोडमध्ये राहील. आपण आता बाहेर पडू इच्छिता?</item>
-      <item quantity="other">आणीबाणी कॉलबॅक मोडमध्ये असताना निवडलेली क्रिया उपलब्ध नसते. फोन <xliff:g id="COUNT_1">%s</xliff:g> मिनिटांसाठी या मोडमध्ये राहील. आपण आता बाहेर पडू इच्छिता?</item>
+      <item quantity="one">आणीबाणी कॉलबॅक मोडमध्ये असताना निवडलेली क्रिया उपलब्ध नसते. फोन <xliff:g id="COUNT_1">%s</xliff:g> मिनिटासाठी या मोडमध्ये राहील. तुम्ही आता बाहेर पडू इच्छिता?</item>
+      <item quantity="other">आणीबाणी कॉलबॅक मोडमध्ये असताना निवडलेली क्रिया उपलब्ध नसते. फोन <xliff:g id="COUNT_1">%s</xliff:g> मिनिटांसाठी या मोडमध्ये राहील. तुम्ही आता बाहेर पडू इच्छिता?</item>
     </plurals>
     <string name="alert_dialog_in_ecm_call" msgid="1886723687211887104">"आणीबाणीच्‍या कॉलमध्‍ये असताना निवडलेली क्रिया उपलब्‍ध नसते."</string>
     <string name="progress_dialog_exiting_ecm" msgid="4835734101617817074">"आणीबाणी कॉलबॅक मोडमधून बाहेर पडत आहे"</string>
@@ -639,7 +639,7 @@
     <string name="change_pin_cancel_label" msgid="353535488390948596">"रद्द करा"</string>
     <string name="change_pin_ok_label" msgid="6204308560844889926">"ठीक आहे"</string>
     <string name="change_pin_enter_old_pin_header" msgid="419179847657548887">"आपल्या जुन्या पिनची पुष्टी करा"</string>
-    <string name="change_pin_enter_old_pin_hint" msgid="8579171678763615453">"सुरु ठेवण्‍यासाठी आपला व्हॉइसमेल पिन प्रविष्‍ट करा."</string>
+    <string name="change_pin_enter_old_pin_hint" msgid="8579171678763615453">"सुरु ठेवण्‍यासाठी तुमचा व्हॉइसमेल पिन प्रविष्‍ट करा."</string>
     <string name="change_pin_enter_new_pin_header" msgid="2611191814590251532">"नवीन पिन सेट करा"</string>
     <string name="change_pin_enter_new_pin_hint" msgid="2322940054329689309">"पिन <xliff:g id="MIN">%1$d</xliff:g>-<xliff:g id="MAX">%2$d</xliff:g> अंकी असणे आवश्‍यक आहे."</string>
     <string name="change_pin_confirm_pin_header" msgid="8113764019347322170">"आपल्या पिनची पुष्टी करा"</string>
@@ -655,9 +655,9 @@
     <string name="mobile_data_activate_prepaid_summary" msgid="5705389791791637666">"<xliff:g id="PROVIDER_NAME">%s</xliff:g> द्वारे मोबाइल डेटा जोडा"</string>
     <string name="mobile_data_activate_roaming_plan" msgid="5998161536947086264">"कोणतीही रोमिंग योजना नाही"</string>
     <string name="mobile_data_activate_roaming_plan_summary" msgid="511202908883425459">"<xliff:g id="PROVIDER_NAME">%s</xliff:g> द्वारे रोमिंग योजना जोडा"</string>
-    <string name="mobile_data_activate_footer" msgid="5979019929980140594">"आपण आपल्या <xliff:g id="PROVIDER_NAME">%s</xliff:g> वाहकाद्वारे मोबाइल डेटा किंवा रोमिंग योजना जोडू शकता."</string>
+    <string name="mobile_data_activate_footer" msgid="5979019929980140594">"तुम्ही आपल्या <xliff:g id="PROVIDER_NAME">%s</xliff:g> वाहकाद्वारे मोबाइल डेटा किंवा रोमिंग योजना जोडू शकता."</string>
     <string name="mobile_data_activate_diag_title" msgid="9044252207707864493">"डेटा जोडायचा?"</string>
-    <string name="mobile_data_activate_diag_message" msgid="8216154678758451453">"आपल्याला <xliff:g id="PROVIDER_NAME">%s</xliff:g> द्वारे डेटा जोडण्याची आवश्यकता असू शकते"</string>
+    <string name="mobile_data_activate_diag_message" msgid="8216154678758451453">"तुम्हाला <xliff:g id="PROVIDER_NAME">%s</xliff:g> द्वारे डेटा जोडण्याची आवश्यकता असू शकते"</string>
     <string name="mobile_data_activate_button" msgid="3682400969184405446">"डेटा जोडा"</string>
     <string name="mobile_data_activate_cancel_button" msgid="1708022171547398765">"रद्द करा"</string>
     <string name="clh_card_title_call_ended_txt" msgid="4072101334811753823">"कॉल संपला"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 9a137ff..3a71328 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -386,7 +386,7 @@
   </string-array>
     <string name="cdma_activate_device" msgid="3793805892364814518">"Kích hoạt thiết bị"</string>
     <string name="cdma_lte_data_service" msgid="4255018217292548962">"Thiết lập dịch vụ dữ liệu"</string>
-    <string name="carrier_settings_title" msgid="9028166176523012300">"Cài đặt nhà cung cấp dịch vụ"</string>
+    <string name="carrier_settings_title" msgid="9028166176523012300">"Cài đặt nhà mạng"</string>
     <string name="fdn" msgid="7878832555095183202">"Số gọi định sẵn"</string>
     <string name="fdn_with_label" msgid="187084204115493366">"Số gọi định sẵn (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
     <string name="manage_fdn_list" msgid="8777755791892122369">"Danh sách FDN"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index b1f8ae8..6b6bf04 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -254,6 +254,7 @@
     <!-- Intent action to launch target emergency app. -->
     <string name="config_emergency_app_intent" translatable="false"></string>
 
-    <!-- Flag indicating whether shortcut view of promoted emergency numbers should be enabled. -->
-    <bool name="config_emergency_shortcut_view_enabled">false</bool>
+    <!-- The country list that shortcut view can be enabled. -->
+    <string-array name="config_countries_to_enable_shortcut_view" translatable="false">
+    </string-array>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8fd194a..d2845ae 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1761,6 +1761,9 @@
     <string name="call_barring_settings">Call barring settings</string>
     <!-- Call barring settings screen, deactivate all call barring settings -->
     <string name="call_barring_deactivate_all_no_password">Deactivate all call barring settings?</string>
+    <!-- In-call screen: error message shown when the user attempts to place a call, but the network
+         does not have enough resources (e.g. it is busy) and the call cannot be placed. -->
+    <string name="callFailed_NetworkBusy">Network is busy.  Please try your call again later.</string>
     <!-- Message displayed to the user when an outgoing call is deflected.  This means that the
          party the user is calling has chosen to send the call to another phone number. -->
     <string name="supp_service_notification_call_deflected">Call deflected.</string>
diff --git a/res/xml/phone_account_settings.xml b/res/xml/phone_account_settings.xml
index ae3e9d9..d230328 100644
--- a/res/xml/phone_account_settings.xml
+++ b/res/xml/phone_account_settings.xml
@@ -29,6 +29,7 @@
             android:order="1" />
 
         <PreferenceScreen
+            android:key="phone_accounts_all_calling_accounts"
             android:title="@string/phone_accounts_all_calling_accounts"
             android:summary="@string/phone_accounts_all_calling_accounts_summary"
             android:persistent="false"
diff --git a/sip/res/values-mr/strings.xml b/sip/res/values-mr/strings.xml
index 5c05fe9..e09b33d 100644
--- a/sip/res/values-mr/strings.xml
+++ b/sip/res/values-mr/strings.xml
@@ -71,8 +71,8 @@
     <string name="all_empty_alert" msgid="4087734950375192387">"नवीन SIP खात्याचा तपशील एंटर करा."</string>
     <string name="empty_alert" msgid="6659484914371384024">"<xliff:g id="INPUT_FIELD_NAME">%s</xliff:g> आवश्‍यक आहे आणि रिक्त सोडले जाऊ शकत नाही."</string>
     <string name="not_a_valid_port" msgid="7931422555587011830">"पोर्ट नंबर 1000 आणि 65534 मध्‍ये असावा."</string>
-    <string name="no_internet_available" msgid="5523747991760017298">"एक SIP कॉल करण्‍यासाठी, प्रथम आपले इंटरनेट कनेक्‍शन तपासा."</string>
-    <string name="no_wifi_available" msgid="1955023904229673488">"SIP कॉलसाठी आपण वाय-फाय नेटवर्कशी कनेक्‍ट केलेले असणे आवश्‍यक आहे (वायरलेस &amp; नेटवर्क सेटिंग्ज वापरा)."</string>
+    <string name="no_internet_available" msgid="5523747991760017298">"एक SIP कॉल करण्‍यासाठी, प्रथम तुमचे इंटरनेट कनेक्‍शन तपासा."</string>
+    <string name="no_wifi_available" msgid="1955023904229673488">"SIP कॉलसाठी तुम्ही वाय-फाय नेटवर्कशी कनेक्‍ट केलेले असणे आवश्‍यक आहे (वायरलेस &amp; नेटवर्क सेटिंग्ज वापरा)."</string>
     <string name="no_voip" msgid="3038021971231952704">"SIP कॉल करणे समर्थित नाही"</string>
     <string name="sip_system_decide" msgid="5577696249416700671">"स्वयंचलित"</string>
     <string name="sip_always_send_keepalive" msgid="4773022409239823318">"नेहमी पाठवा"</string>
diff --git a/sip/src/com/android/services/telephony/sip/SipUtil.java b/sip/src/com/android/services/telephony/sip/SipUtil.java
index d674225..ff38754 100644
--- a/sip/src/com/android/services/telephony/sip/SipUtil.java
+++ b/sip/src/com/android/services/telephony/sip/SipUtil.java
@@ -134,7 +134,7 @@
                 .setAddress(sipUri)
                 .setShortDescription(sipAddress)
                 .setIcon(Icon.createWithResource(
-                        context.getResources(), R.drawable.ic_dialer_sip_black_24dp))
+                        context, R.drawable.ic_dialer_sip_black_24dp))
                 .setExtras(phoneAccountExtras)
                 .setSupportedUriSchemes(supportedUriSchemes);
 
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index 92af129..0cb93aa 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -37,7 +37,9 @@
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneStateListener;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.ims.ProvisioningManager;
 import android.telephony.ims.feature.ImsFeature;
 import android.util.Log;
 import android.view.MenuItem;
@@ -214,10 +216,32 @@
         }
     };
 
+    private final ProvisioningManager.Callback mProvisioningCallback =
+            new ProvisioningManager.Callback() {
+        @Override
+        public void onProvisioningIntChanged(int item, int value) {
+            if (item == ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED
+                    || item == ImsConfig.ConfigConstants.VLT_SETTING_ENABLED
+                    || item == ImsConfig.ConfigConstants.LVC_SETTING_ENABLED) {
+                updateVtWfc();
+            }
+        }
+    };
+
     @Override
     protected void onPause() {
         super.onPause();
         listenPhoneState(false);
+
+        // Remove callback for provisioning changes.
+        try {
+            if (mImsMgr != null) {
+                mImsMgr.getConfigInterface().removeConfigCallback(
+                        mProvisioningCallback.getBinder());
+            }
+        } catch (ImsException e) {
+            Log.w(LOG_TAG, "onPause: Unable to remove callback for provisioning changes");
+        }
     }
 
     @Override
@@ -310,7 +334,24 @@
                 }
             }
         }
+        updateVtWfc();
 
+        // Register callback for provisioning changes.
+        try {
+            if (mImsMgr != null) {
+                mImsMgr.getConfigInterface().addConfigCallback(mProvisioningCallback);
+            }
+        } catch (ImsException e) {
+            Log.w(LOG_TAG, "onResume: Unable to register callback for provisioning changes.");
+        }
+    }
+
+    private void updateVtWfc() {
+        PreferenceScreen prefSet = getPreferenceScreen();
+        TelephonyManager telephonyManager = getSystemService(TelephonyManager.class)
+                .createForSubscriptionId(mPhone.getSubId());
+        PersistableBundle carrierConfig =
+                PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
         if (mImsMgr.isVtEnabledByPlatform() && mImsMgr.isVtProvisionedOnDevice()
                 && (carrierConfig.getBoolean(
                         CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS)
@@ -320,6 +361,7 @@
                     ? mImsMgr.isVtEnabledByUser() : false;
             mEnableVideoCalling.setChecked(currentValue);
             mEnableVideoCalling.setOnPreferenceChangeListener(this);
+            prefSet.addPreference(mEnableVideoCalling);
         } else {
             prefSet.removePreference(mEnableVideoCalling);
         }
@@ -335,6 +377,7 @@
                     mButtonWifiCalling.setTitle(resolutions.get(0).loadLabel(pm));
                     mButtonWifiCalling.setSummary(null);
                     mButtonWifiCalling.setIntent(intent);
+                    prefSet.addPreference(mButtonWifiCalling);
                 } else {
                     prefSet.removePreference(mButtonWifiCalling);
                 }
@@ -344,6 +387,10 @@
         } else if (!mImsMgr.isWfcEnabledByPlatform() || !mImsMgr.isWfcProvisionedOnDevice()) {
             prefSet.removePreference(mButtonWifiCalling);
         } else {
+            String title = SubscriptionManager.getResourcesForSubId(mPhone.getContext(),
+                    mPhone.getSubId()).getString(R.string.wifi_calling);
+            mButtonWifiCalling.setTitle(title);
+
             int resId = com.android.internal.R.string.wifi_calling_off_summary;
             if (mImsMgr.isWfcEnabledByUser()) {
                 boolean isRoaming = telephonyManager.isNetworkRoaming();
@@ -363,6 +410,7 @@
                 }
             }
             mButtonWifiCalling.setSummary(resId);
+            prefSet.addPreference(mButtonWifiCalling);
         }
 
         try {
diff --git a/src/com/android/phone/EccShortcutAdapter.java b/src/com/android/phone/EccShortcutAdapter.java
index e14b90a..a5d955b 100644
--- a/src/com/android/phone/EccShortcutAdapter.java
+++ b/src/com/android/phone/EccShortcutAdapter.java
@@ -17,6 +17,7 @@
 package com.android.phone;
 
 import android.content.Context;
+import android.telephony.emergency.EmergencyNumber;
 import android.text.TextUtils;
 import android.view.View;
 import android.view.ViewGroup;
@@ -25,9 +26,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import com.android.phone.ecc.CountryEccInfo;
-import com.android.phone.ecc.EccInfo;
-
 import com.google.common.collect.LinkedListMultimap;
 
 import java.util.ArrayList;
@@ -35,8 +33,7 @@
 
 /**
  * An abstract adapter between ECC data and the view contains ECC shortcuts.
- * This adapter will convert given {@link CountryEccInfo} to number string, description string and
- * icon resource id for each {@link EccInfo}.
+ * This adapter prepares description and icon for every promoted emergency number.
  * The subclass should implements {@link #inflateView} to provide the view for an ECC data, when the
  * view container calls {@link #getView}.
  */
@@ -90,16 +87,16 @@
      * Get a View that display the given ECC data: number, description and iconRes.
      *
      * @param convertView The old view to reuse, if possible. Note: You should check that this view
-     *                   is non-null and of an appropriate type before using. If it is not possible
-     *                   to convert this view to display the correct data, this method can create a
-     *                   new view. Heterogeneous lists can specify their number of view types, so
-     *                   that this View is always of the right type (see {@link
-     *                   BaseAdapter#getViewTypeCount()} and {@link
-     *                   BaseAdapter#getItemViewType(int)}).
-     * @param parent The parent that this view will eventually be attached to.
-     * @param number The number of the ECC shortcut to display in the view.
+     *                    is non-null and of an appropriate type before using. If it is not possible
+     *                    to convert this view to display the correct data, this method can create a
+     *                    new view. Heterogeneous lists can specify their number of view types, so
+     *                    that this View is always of the right type (see {@link
+     *                    BaseAdapter#getViewTypeCount()} and {@link
+     *                    BaseAdapter#getItemViewType(int)}).
+     * @param parent      The parent that this view will eventually be attached to.
+     * @param number      The number of the ECC shortcut to display in the view.
      * @param description The description of the ECC shortcut to display in the view.
-     * @param iconRes The icon resource ID represent for the ECC shortcut.
+     * @param iconRes     The icon resource ID represent for the ECC shortcut.
      * @return A View corresponding to the data at the specified position.
      */
     public abstract View inflateView(View convertView, ViewGroup parent, CharSequence number,
@@ -110,89 +107,68 @@
      * be display by the short container View.
      *
      * @param context The context used to access resources.
-     * @param countryEccInfo Updated country ECC info.
+     * @param phoneInfo Information of the phone to make an emergency call.
      */
-    public void updateCountryEccInfo(@NonNull Context context, CountryEccInfo countryEccInfo) {
+    public void updateCountryEccInfo(@NonNull Context context,
+            @Nullable ShortcutViewUtils.PhoneInfo phoneInfo) {
         List<EccDisplayMaterial> displayMaterials = new ArrayList<>();
 
-        final EccInfo.Type[] orderedMustHaveTypes =
-                { EccInfo.Type.POLICE, EccInfo.Type.AMBULANCE, EccInfo.Type.FIRE };
-
-        String fallback = null;
-        EccInfo[] eccInfoList = null;
-        if (countryEccInfo != null) {
-            fallback = countryEccInfo.getFallbackEcc();
-            eccInfoList = countryEccInfo.getEccInfoList();
-        }
-        if (TextUtils.isEmpty(fallback)) {
-            fallback = FALLBACK_EMERGENCY_NUMBER;
-        }
-
-        // Finding matched ECC for each must have types.
-        // Using LinkedListMultimap to prevent duplicated keys.
-        // LinkedListMultimap also preserve the insertion order of keys (ECC number) and values
-        // (matched types of the ECC number), which follows the order in orderedMustHaveTypes.
-        LinkedListMultimap<String, EccInfo.Type> eccList = LinkedListMultimap.create();
-        for (EccInfo.Type type : orderedMustHaveTypes) {
-            String number = null;
-            if (eccInfoList != null) {
-                number = pickEccNumberForType(type, eccInfoList);
+        try {
+            if (phoneInfo == null) {
+                return;
             }
-            if (number == null) {
-                number = fallback;
-            }
-            // append type for exist number, otherwise insert a new entry.
-            eccList.put(number, type);
-        }
 
-        // prepare display material for picked ECC
-        for (String number : eccList.keySet()) {
-            EccDisplayMaterial material = prepareDisplayMaterialForEccInfo(context,
-                    new EccInfo(number, eccList.asMap().get(number)));
-            if (material != null) {
-                displayMaterials.add(material);
-            }
-        }
-
-        mEccDisplayMaterialList = displayMaterials;
-        notifyDataSetChanged();
-    }
-
-    private @Nullable String pickEccNumberForType(@NonNull EccInfo.Type targetType,
-            @NonNull EccInfo[] eccInfoList) {
-        EccInfo pickedEccInfo = null;
-        for (EccInfo eccInfo : eccInfoList) {
-            if (eccInfo.containsType(targetType)) {
-                // An ECC is more suitable for a type if the ECC has fewer other types.
-                if (pickedEccInfo == null
-                        || eccInfo.getTypesCount() < pickedEccInfo.getTypesCount()) {
-                    pickedEccInfo = eccInfo;
+            LinkedListMultimap<String, Integer> emergencyNumbers = LinkedListMultimap.create();
+            for (int category : ShortcutViewUtils.PROMOTED_CATEGORIES) {
+                String number = pickEmergencyNumberForCategory(category,
+                        phoneInfo.getPromotedEmergencyNumbers());
+                if (number != null) {
+                    emergencyNumbers.put(number, category);
                 }
             }
+
+            // prepare display material for picked ECC
+            for (String number : emergencyNumbers.keySet()) {
+                EccDisplayMaterial material = prepareEccMaterial(context, number,
+                        emergencyNumbers.get(number));
+                if (material != null) {
+                    displayMaterials.add(material);
+                }
+            }
+        } finally {
+            mEccDisplayMaterialList = displayMaterials;
+            notifyDataSetChanged();
         }
-        if (pickedEccInfo != null) {
-            return pickedEccInfo.getNumber();
+    }
+
+    @Nullable
+    private String pickEmergencyNumberForCategory(int category,
+            @NonNull List<EmergencyNumber> emergencyNumbers) {
+        for (EmergencyNumber number : emergencyNumbers) {
+            if ((number.getEmergencyServiceCategoryBitmask() & category) != 0) {
+                return number.getNumber();
+            }
         }
         return null;
     }
 
-    private @Nullable EccDisplayMaterial prepareDisplayMaterialForEccInfo(@NonNull Context context,
-            @NonNull EccInfo eccInfo) {
+    @Nullable
+    private EccDisplayMaterial prepareEccMaterial(@NonNull Context context, @NonNull String number,
+            @NonNull List<Integer> categories) {
         EccDisplayMaterial material = new EccDisplayMaterial();
-        material.number = eccInfo.getNumber();
-        EccInfo.Type[] types = eccInfo.getTypes();
-        for (EccInfo.Type type : types) {
+        material.number = number;
+        for (int category : categories) {
             CharSequence description;
-            switch (type) {
-                case POLICE:
+            switch (category) {
+                case EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE:
                     description = mPoliceDescription;
                     material.iconRes = R.drawable.ic_local_police_gm2_24px;
                     break;
-                case AMBULANCE:
+                case EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE:
                     description = mAmbulanceDescription;
                     material.iconRes = R.drawable.ic_local_hospital_gm2_24px;
                     break;
-                case FIRE:
+                case EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE:
                     description = mFireDescription;
                     material.iconRes = R.drawable.ic_local_fire_department_gm2_24px;
                     break;
@@ -200,6 +176,7 @@
                     // ignore unknown types
                     continue;
             }
+
             if (TextUtils.isEmpty(material.description)) {
                 material.description = description;
             } else {
@@ -209,10 +186,10 @@
                         material.description, description);
             }
         }
+
         if (TextUtils.isEmpty(material.description) || material.iconRes == 0) {
             return null;
         }
         return material;
     }
-
 }
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index c89ddc6..65edcf9 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -83,9 +83,6 @@
 import com.android.phone.common.dialpad.DialpadKeyButton;
 import com.android.phone.common.util.ViewUtil;
 import com.android.phone.common.widget.ResizingTextEditText;
-import com.android.phone.ecc.CountryEccInfo;
-import com.android.phone.ecc.EccInfoHelper;
-import com.android.phone.ecc.IsoToEccProtobufRepository;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -235,7 +232,7 @@
     private View mEmergencyShortcutView;
     private View mDialpadView;
 
-    private EccInfoHelper mEccInfoHelper;
+    private ShortcutViewUtils.PhoneInfo mPhoneInfo;
 
     private List<EmergencyShortcutButton> mEmergencyShortcutButtonList;
     private EccShortcutAdapter mShortcutAdapter;
@@ -363,14 +360,10 @@
                 configMgr.getConfigForSubId(SubscriptionManager.getDefaultVoiceSubscriptionId());
 
         mIsShortcutViewEnabled = false;
+        mPhoneInfo = null;
         if (canEnableShortcutView(carrierConfig)) {
-            TelephonyManager tm = getSystemService(TelephonyManager.class);
-            String countryIso = tm.getNetworkCountryIso();
-            if (TextUtils.isEmpty(countryIso)) {
-                Log.d(LOG_TAG, "Unable to determine the country of current network.");
-            } else if (!EccInfoHelper.isCountryEccInfoAvailable(this, countryIso)) {
-                Log.d(LOG_TAG, "ECC info is unavailable.");
-            } else {
+            mPhoneInfo = ShortcutViewUtils.pickPreferredPhone(this);
+            if (mPhoneInfo != null) {
                 mIsShortcutViewEnabled = true;
             }
         }
@@ -469,7 +462,6 @@
         mEmergencyInfoGroup = (EmergencyInfoGroup) findViewById(R.id.emergency_info_button);
 
         if (mIsShortcutViewEnabled) {
-            mEccInfoHelper = new EccInfoHelper(IsoToEccProtobufRepository.getInstance());
             setupEmergencyShortcutsView();
         }
     }
@@ -611,11 +603,8 @@
 
         if (!TextUtils.isEmpty(phoneNumber)) {
             if (DBG) Log.d(LOG_TAG, "dial emergency number: " + Rlog.pii(LOG_TAG, phoneNumber));
-            Bundle extras = new Bundle();
-            extras.putInt(TelecomManager.EXTRA_CALL_SOURCE,
-                    ParcelableCallAnalytics.CALL_SOURCE_EMERGENCY_SHORTCUT);
-            TelecomManager tm = (TelecomManager) getSystemService(TELECOM_SERVICE);
-            tm.placeCall(Uri.fromParts(PhoneAccount.SCHEME_TEL, phoneNumber, null), extras);
+            placeCall(phoneNumber, ParcelableCallAnalytics.CALL_SOURCE_EMERGENCY_SHORTCUT,
+                    mPhoneInfo);
         } else {
             Log.d(LOG_TAG, "emergency number is empty");
         }
@@ -769,30 +758,9 @@
             updateTheme(lockScreenColors.supportsDarkText());
         }
 
-        if (mIsShortcutViewEnabled && mEccInfoHelper != null) {
-            final Context context = this;
-            mEccInfoHelper.getCountryEccInfoAsync(context,
-                    new EccInfoHelper.CountryEccInfoResultCallback() {
-                        @Override
-                        public void onSuccess(String iso, CountryEccInfo countryEccInfo) {
-                            Log.d(LOG_TAG, "Retrieve ECC info success, country ISO: "
-                                    + Rlog.pii(LOG_TAG, iso));
-                            updateLocationAndEccInfo(iso, countryEccInfo);
-                        }
-
-                        @Override
-                        public void onDetectCountryFailed() {
-                            Log.w(LOG_TAG, "Cannot detect current country.");
-                            updateLocationAndEccInfo(null, null);
-                        }
-
-                        @Override
-                        public void onRetrieveCountryEccInfoFailed(String iso) {
-                            Log.w(LOG_TAG, "Retrieve ECC info failed, country ISO: "
-                                    + Rlog.pii(LOG_TAG, iso));
-                            updateLocationAndEccInfo(iso, null);
-                        }
-                    });
+        if (mIsShortcutViewEnabled) {
+            mPhoneInfo = ShortcutViewUtils.pickPreferredPhone(this);
+            updateLocationAndEccInfo();
         }
     }
 
@@ -842,10 +810,6 @@
     }
 
     private boolean canEnableShortcutView(PersistableBundle carrierConfig) {
-        if (!getResources().getBoolean(R.bool.config_emergency_shortcut_view_enabled)) {
-            // Disables shortcut view by project.
-            return false;
-        }
         if (!carrierConfig.getBoolean(
                 CarrierConfigManager.KEY_SUPPORT_EMERGENCY_DIALER_SHORTCUT_BOOL)) {
             Log.d(LOG_TAG, "Disables shortcut view by carrier requirement");
@@ -897,7 +861,20 @@
         // nothing and just returns input number.
         mLastNumber = PhoneNumberUtils.convertToEmergencyNumber(this, mLastNumber);
 
-        if (PhoneNumberUtils.isLocalEmergencyNumber(this, mLastNumber)) {
+        boolean isEmergencyNumber = false;
+        ShortcutViewUtils.PhoneInfo phoneToMakeCall = null;
+        if (mPhoneInfo != null) {
+            isEmergencyNumber = mPhoneInfo.hasPromotedEmergencyNumber(mLastNumber);
+            if (isEmergencyNumber) {
+                phoneToMakeCall = mPhoneInfo;
+            }
+        }
+        if (!isEmergencyNumber) {
+            TelephonyManager tm = getSystemService(TelephonyManager.class);
+            isEmergencyNumber = tm.isCurrentEmergencyNumber(mLastNumber);
+        }
+
+        if (isEmergencyNumber) {
             if (DBG) Log.d(LOG_TAG, "placing call to " + mLastNumber);
 
             // place the call if it is a valid number
@@ -910,11 +887,8 @@
             mMetricsWriter.writeMetricsForMakingCall(MetricsWriter.CALL_SOURCE_DIALPAD,
                     MetricsWriter.PHONE_NUMBER_TYPE_EMERGENCY, isShortcutNumber(mLastNumber));
 
-            Bundle extras = new Bundle();
-            extras.putInt(TelecomManager.EXTRA_CALL_SOURCE,
-                    ParcelableCallAnalytics.CALL_SOURCE_EMERGENCY_DIALPAD);
-            TelecomManager tm = (TelecomManager) getSystemService(TELECOM_SERVICE);
-            tm.placeCall(Uri.fromParts(PhoneAccount.SCHEME_TEL, mLastNumber, null), extras);
+            placeCall(mLastNumber, ParcelableCallAnalytics.CALL_SOURCE_EMERGENCY_DIALPAD,
+                    phoneToMakeCall);
         } else {
             if (DBG) Log.d(LOG_TAG, "rejecting bad requested number " + mLastNumber);
 
@@ -928,6 +902,27 @@
         mDigits.getText().delete(0, mDigits.getText().length());
     }
 
+    private void placeCall(String number, int callSource, ShortcutViewUtils.PhoneInfo phone) {
+        Bundle extras = new Bundle();
+        extras.putInt(TelecomManager.EXTRA_CALL_SOURCE, callSource);
+        /**
+         * This is used for Telecom and Telephony to tell modem user's intent is emergency call,
+         * when the dialed number is ambiguous and identified as both emergency number and any
+         * other non-emergency number; e.g. in some situation, 611 could be both an emergency
+         * number in a country and a non-emergency number of a carrier's customer service hotline.
+         */
+        extras.putBoolean(TelecomManager.EXTRA_IS_USER_INTENT_EMERGENCY_CALL, true);
+
+        if (phone != null && phone.getPhoneAccountHandle() != null) {
+            // Requests to dial through the specified phone.
+            extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+                    phone.getPhoneAccountHandle());
+        }
+
+        TelecomManager tm = this.getSystemService(TelecomManager.class);
+        tm.placeCall(Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null), extras);
+    }
+
     /**
      * Plays the specified tone for TONE_LENGTH_MS milliseconds.
      *
@@ -1071,7 +1066,7 @@
         AsyncTask<Void, Void, Boolean> showWfcWarningTask = new AsyncTask<Void, Void, Boolean>() {
             @Override
             protected Boolean doInBackground(Void... voids) {
-                TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
+                TelephonyManager tm = getSystemService(TelephonyManager.class);
                 boolean isWfcAvailable = tm.isWifiCallingAvailable();
                 ServiceState ss = tm.getServiceState();
                 boolean isCellAvailable =
@@ -1143,14 +1138,15 @@
         mEmergencyShortcutButtonList = new ArrayList<>();
         setupEmergencyCallShortcutButton();
 
-        updateLocationAndEccInfo(null, null);
+        updateLocationAndEccInfo();
 
         switchView(mEmergencyShortcutView, mDialpadView, false);
     }
 
-    private void setLocationInfo(String countryIso) {
+    private void setLocationInfo() {
         final View locationInfo = findViewById(R.id.location_info);
 
+        String countryIso = mPhoneInfo != null ? mPhoneInfo.getCountryIso() : null;
         String countryName = null;
         if (!TextUtils.isEmpty(countryIso)) {
             Locale locale = Locale.getDefault();
@@ -1227,11 +1223,11 @@
         mShortcutAdapter.registerDataSetObserver(mShortcutDataSetObserver);
     }
 
-    private void updateLocationAndEccInfo(String iso, CountryEccInfo countryEccInfo) {
+    private void updateLocationAndEccInfo() {
         if (!isFinishing() && !isDestroyed()) {
-            setLocationInfo(iso);
+            setLocationInfo();
             if (mShortcutAdapter != null) {
-                mShortcutAdapter.updateCountryEccInfo(this, countryEccInfo);
+                mShortcutAdapter.updateCountryEccInfo(this, mPhoneInfo);
             }
         }
     }
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index 86babd5..6375f90 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -57,6 +57,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.euicc.EuiccManager;
+import android.telephony.ims.ProvisioningManager;
 import android.telephony.ims.feature.ImsFeature;
 import android.text.TextUtils;
 import android.util.Log;
@@ -485,7 +486,7 @@
 
         public void onIntentUpdate(Intent intent) {
             if (!mUnavailable) {
-                updateCurrentTab(intent);
+                updateCurrentTab(intent.getExtras());
             }
         }
 
@@ -583,8 +584,7 @@
             }
         };
 
-        private int getSlotIdFromIntent(Intent intent) {
-            Bundle data = intent.getExtras();
+        private int getSlotIdFromBundle(Bundle data) {
             int subId = -1;
             if (data != null) {
                 subId = data.getInt(Settings.EXTRA_SUB_ID, -1);
@@ -754,8 +754,8 @@
                     mEmptyTabContent);
         }
 
-        private void updateCurrentTab(Intent intent) {
-            int slotId = getSlotIdFromIntent(intent);
+        private void updateCurrentTab(Bundle data) {
+            int slotId = getSlotIdFromBundle(data);
             if (slotId >= 0 && mTabHost != null && mTabHost.getCurrentTab() != slotId) {
                 mTabHost.setCurrentTab(slotId);
             }
@@ -768,6 +768,9 @@
             // If advanced fields are already expanded, we save it and expand it
             // when it's re-created.
             outState.putBoolean(EXPAND_ADVANCED_FIELDS, mExpandAdvancedFields);
+
+            // Save subId of currently shown tab.
+            outState.putInt(Settings.EXTRA_SUB_ID, mSubId);
         }
 
         @Override
@@ -851,7 +854,12 @@
                 getActivity().setContentView(R.layout.telephony_disallowed_preference_screen);
             } else {
                 initializeSubscriptions();
-                updateCurrentTab(getActivity().getIntent());
+
+                if (savedInstanceState != null) {
+                    updateCurrentTab(savedInstanceState);
+                } else {
+                    updateCurrentTab(getActivity().getIntent().getExtras());
+                }
             }
         }
 
@@ -884,6 +892,18 @@
             }
         }
 
+        private final ProvisioningManager.Callback mProvisioningCallback =
+                new ProvisioningManager.Callback() {
+            @Override
+            public void onProvisioningIntChanged(int item, int value) {
+                if (item == ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED
+                        || item == ImsConfig.ConfigConstants.VLT_SETTING_ENABLED
+                        || item == ImsConfig.ConfigConstants.LVC_SETTING_ENABLED) {
+                    updateBody();
+                }
+            }
+        };
+
         @Override
         public void onDestroy() {
             super.onDestroy();
@@ -933,6 +953,15 @@
             context.getContentResolver().registerContentObserver(ENFORCE_MANAGED_URI, false,
                     mDpcEnforcedContentObserver);
 
+            // Register callback for provisioning changes.
+            try {
+                if (mImsMgr != null) {
+                    mImsMgr.getConfigInterface().addConfigCallback(mProvisioningCallback);
+                }
+            } catch (ImsException e) {
+                Log.w(LOG_TAG, "onResume: Unable to register callback for provisioning changes.");
+            }
+
             Log.i(LOG_TAG, "onResume:-");
 
         }
@@ -1325,6 +1354,17 @@
             final Context context = getActivity();
             context.unregisterReceiver(mPhoneChangeReceiver);
             context.getContentResolver().unregisterContentObserver(mDpcEnforcedContentObserver);
+
+            // Remove callback for provisioning changes.
+            try {
+                if (mImsMgr != null) {
+                    mImsMgr.getConfigInterface().removeConfigCallback(
+                            mProvisioningCallback.getBinder());
+                }
+            } catch (ImsException e) {
+                Log.w(LOG_TAG, "onPause: Unable to remove callback for provisioning changes");
+            }
+
             if (DBG) log("onPause:-");
         }
 
@@ -1860,10 +1900,23 @@
                 return;
             }
 
+            // See what Telecom thinks the SIM call manager is.
             final PhoneAccountHandle simCallManager =
                     TelecomManager.from(getContext()).getSimCallManager();
 
-            if (simCallManager != null) {
+            // Check which SIM call manager is for the current sub ID.
+            PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(mSubId);
+            String currentSubSimCallManager = null;
+            if (carrierConfig != null) {
+                currentSubSimCallManager = carrierConfig.getString(
+                        CarrierConfigManager.KEY_DEFAULT_SIM_CALL_MANAGER_STRING);
+            }
+
+            // Only try to configure the phone account if this is the sim call manager for the
+            // current sub.
+            if (simCallManager != null
+                    && simCallManager.getComponentName().flattenToString().equals(
+                    currentSubSimCallManager)) {
                 Intent intent = MobileNetworkSettings.buildPhoneAccountConfigureIntent(
                         getContext(), simCallManager);
                 PackageManager pm = getContext().getPackageManager();
@@ -1872,6 +1925,10 @@
                 mWiFiCallingPref.setSummary(null);
                 mWiFiCallingPref.setIntent(intent);
             } else {
+                String title = SubscriptionManager.getResourcesForSubId(getContext(), mSubId)
+                        .getString(R.string.wifi_calling_settings_title);
+                mWiFiCallingPref.setTitle(title);
+
                 int resId = com.android.internal.R.string.wifi_calling_off_summary;
                 if (mImsMgr.isWfcEnabledByUser()) {
                     boolean isRoaming = mTelephonyManager.isNetworkRoaming();
diff --git a/src/com/android/phone/PhoneApp.java b/src/com/android/phone/PhoneApp.java
index 333e0ec..df151bf 100644
--- a/src/com/android/phone/PhoneApp.java
+++ b/src/com/android/phone/PhoneApp.java
@@ -19,7 +19,6 @@
 import android.app.Application;
 import android.os.UserHandle;
 
-import com.android.phone.ecc.IsoToEccProtobufRepository;
 import com.android.services.telephony.TelecomAccountRegistry;
 
 /**
@@ -41,10 +40,5 @@
 
             TelecomAccountRegistry.getInstance(this).setupOnBoot();
         }
-
-        new Thread(() -> {
-            // Preload ECC table in background.
-            IsoToEccProtobufRepository.getInstance().loadMappingTable(PhoneApp.this);
-        }).start();
     }
 }
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index ccbb4d0..3d82e74 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -44,6 +44,7 @@
 import android.provider.Settings;
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
+import android.telephony.DebugEventReporter;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -283,6 +284,9 @@
         //   getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS);
 
         if (mCM == null) {
+            // Initialize DebugEventReporter early so that it can be used
+            DebugEventReporter.initialize(this);
+
             // Inject telephony component factory if configured using other jars.
             XmlResourceParser parser = getResources().getXml(R.xml.telephony_injection);
             TelephonyComponentFactory.getInstance().injectTheComponentFactory(parser);
@@ -594,14 +598,22 @@
                     airplaneMode = AIRPLANE_ON;
                 }
                 handleAirplaneModeChange(context, airplaneMode);
-            } else if ((action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) &&
-                    (mPUKEntryActivity != null)) {
-                // if an attempt to un-PUK-lock the device was made, while we're
-                // receiving this state change notification, notify the handler.
-                // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has
-                // been attempted.
-                mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED,
-                        intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)));
+            } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
+                // re-register as it may be a new IccCard
+                int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY,
+                        SubscriptionManager.INVALID_PHONE_INDEX);
+                if (SubscriptionManager.isValidPhoneId(phoneId)) {
+                    PhoneUtils.unregisterIccStatus(mHandler, phoneId);
+                    PhoneUtils.registerIccStatus(mHandler, EVENT_SIM_NETWORK_LOCKED, phoneId);
+                }
+                if (mPUKEntryActivity != null) {
+                    // if an attempt to un-PUK-lock the device was made, while we're
+                    // receiving this state change notification, notify the handler.
+                    // NOTE: This is ONLY triggered if an attempt to un-PUK-lock has
+                    // been attempted.
+                    mHandler.sendMessage(mHandler.obtainMessage(EVENT_SIM_STATE_CHANGED,
+                            intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)));
+                }
             } else if (action.equals(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED)) {
                 String newPhone = intent.getStringExtra(PhoneConstants.PHONE_NAME_KEY);
                 Log.d(LOG_TAG, "Radio technology switched. Now " + newPhone + " is active.");
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index ff69bb7..7e00a05 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -35,6 +35,7 @@
 import android.net.Uri;
 import android.os.AsyncResult;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -68,6 +69,7 @@
 import android.telephony.ModemActivityInfo;
 import android.telephony.NeighboringCellInfo;
 import android.telephony.NetworkScanRequest;
+import android.telephony.PhoneCapability;
 import android.telephony.PhoneNumberRange;
 import android.telephony.RadioAccessFamily;
 import android.telephony.Rlog;
@@ -86,6 +88,7 @@
 import android.telephony.data.ApnSetting;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.gsm.GsmCellLocation;
+import android.telephony.ims.ProvisioningManager;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
 import android.telephony.ims.aidl.IImsConfig;
 import android.telephony.ims.aidl.IImsConfigCallback;
@@ -93,6 +96,8 @@
 import android.telephony.ims.aidl.IImsRcsFeature;
 import android.telephony.ims.aidl.IImsRegistration;
 import android.telephony.ims.aidl.IImsRegistrationCallback;
+import android.telephony.ims.feature.MmTelFeature;
+import android.telephony.ims.stub.ImsConfigImplBase;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.text.TextUtils;
 import android.util.ArraySet;
@@ -110,6 +115,7 @@
 import com.android.internal.telephony.CellNetworkScanResult;
 import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.DefaultPhoneNotifier;
+import com.android.internal.telephony.HalVersion;
 import com.android.internal.telephony.INumberVerificationCallback;
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.IccCard;
@@ -130,7 +136,9 @@
 import com.android.internal.telephony.SmsApplication.SmsApplicationData;
 import com.android.internal.telephony.SubscriptionController;
 import com.android.internal.telephony.TelephonyPermissions;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 import com.android.internal.telephony.euicc.EuiccConnector;
+import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.telephony.uicc.IccIoResult;
 import com.android.internal.telephony.uicc.IccUtils;
 import com.android.internal.telephony.uicc.SIMRecords;
@@ -153,9 +161,11 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Implementation of the ITelephony interface.
@@ -257,6 +267,10 @@
     private static final String PREF_CARRIERS_ALPHATAG_PREFIX = "carrier_alphtag_";
     private static final String PREF_CARRIERS_NUMBER_PREFIX = "carrier_number_";
     private static final String PREF_CARRIERS_SUBSCRIBER_PREFIX = "carrier_subscriber_";
+    private static final String PREF_PROVISION_IMS_MMTEL_PREFIX = "provision_ims_mmtel_";
+
+    // String to store multi SIM allowed
+    private static final String PREF_MULTI_SIM_RESTRICTED = "multisim_restricted";
 
     // The AID of ISD-R.
     private static final String ISDR_AID = "A0000005591010FFFFFFFF8900000100";
@@ -1093,6 +1107,7 @@
                     ar = (AsyncResult) msg.obj;
                     request = (MainThreadRequest) ar.userObj;
                     request.result = (ar.exception == null);
+                    updateModemStateMetrics();
                     notifyRequester(request);
                     break;
                 default:
@@ -1831,9 +1846,21 @@
     public Bundle getCellLocation(String callingPackage) {
         mApp.getSystemService(AppOpsManager.class)
                 .checkPackage(Binder.getCallingUid(), callingPackage);
-        if (!LocationAccessPolicy.canAccessCellLocation(mApp, callingPackage,
-                Binder.getCallingUid(), Binder.getCallingPid(), true)) {
-            return null;
+
+        LocationAccessPolicy.LocationPermissionResult locationResult =
+                LocationAccessPolicy.checkLocationPermission(mApp,
+                        new LocationAccessPolicy.LocationPermissionQuery.Builder()
+                                .setCallingPackage(callingPackage)
+                                .setCallingPid(Binder.getCallingPid())
+                                .setCallingUid(Binder.getCallingUid())
+                                .setMethod("getCellLocation")
+                                .setMinSdkVersionForFine(Build.VERSION_CODES.Q)
+                                .build());
+        switch (locationResult) {
+            case DENIED_HARD:
+                throw new SecurityException("Not allowed to access cell location");
+            case DENIED_SOFT:
+                return new Bundle();
         }
 
         WorkSource workSource = getWorkSource(Binder.getCallingUid());
@@ -1983,9 +2010,22 @@
     public List<CellInfo> getAllCellInfo(String callingPackage) {
         mApp.getSystemService(AppOpsManager.class)
                 .checkPackage(Binder.getCallingUid(), callingPackage);
-        if (!LocationAccessPolicy.canAccessCellLocation(mApp,
-                callingPackage, Binder.getCallingUid(), Binder.getCallingPid(), true)) {
-            return null;
+
+        LocationAccessPolicy.LocationPermissionResult locationResult =
+                LocationAccessPolicy.checkLocationPermission(mApp,
+                        new LocationAccessPolicy.LocationPermissionQuery.Builder()
+                                .setCallingPackage(callingPackage)
+                                .setCallingPid(Binder.getCallingPid())
+                                .setCallingUid(Binder.getCallingUid())
+                                .setMethod("getAllCellInfo")
+                                .setMinSdkVersionForCoarse(Build.VERSION_CODES.BASE)
+                                .setMinSdkVersionForFine(Build.VERSION_CODES.Q)
+                                .build());
+        switch (locationResult) {
+            case DENIED_HARD:
+                throw new SecurityException("Not allowed to access cell info");
+            case DENIED_SOFT:
+                return new ArrayList<>();
         }
 
         final int targetSdk = getTargetSdk(callingPackage);
@@ -2026,9 +2066,21 @@
             int subId, ICellInfoCallback cb, String callingPackage, WorkSource workSource) {
         mApp.getSystemService(AppOpsManager.class)
                 .checkPackage(Binder.getCallingUid(), callingPackage);
-        if (!LocationAccessPolicy.canAccessCellLocation(mApp, callingPackage,
-                Binder.getCallingUid(), Binder.getCallingPid(), true)) {
-            return;
+
+        LocationAccessPolicy.LocationPermissionResult locationResult =
+                LocationAccessPolicy.checkLocationPermission(mApp,
+                        new LocationAccessPolicy.LocationPermissionQuery.Builder()
+                                .setCallingPackage(callingPackage)
+                                .setCallingPid(Binder.getCallingPid())
+                                .setCallingUid(Binder.getCallingUid())
+                                .setMethod("requestCellInfoUpdate")
+                                .setMinSdkVersionForFine(Build.VERSION_CODES.Q)
+                                .build());
+        switch (locationResult) {
+            case DENIED_HARD:
+                throw new SecurityException("Not allowed to access cell info");
+            case DENIED_SOFT:
+                return;
         }
 
         final Phone phone = getPhone(subId);
@@ -2809,6 +2861,9 @@
         } catch (ImsException e) {
             Log.w(LOG_TAG, "IMS isCapable - service unavailable: " + e.getMessage());
             return false;
+        } catch (IllegalArgumentException e) {
+            Log.i(LOG_TAG, "isCapable: " + subId + " is inactive, returning false.");
+            return false;
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -2940,8 +2995,10 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
+            boolean isRoaming = TelephonyManager.from(
+                    getPhone(subId).getContext()).isNetworkRoaming(subId);
             ImsManager.getInstance(mApp,
-                    getSlotIndexOrException(subId)).setWfcNonPersistent(isCapable, mode);
+                    getSlotIndexOrException(subId)).setWfcNonPersistent(isCapable, mode, isRoaming);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -3063,15 +3120,249 @@
     }
 
     @Override
+    public void setImsProvisioningStatusForCapability(int subId, int capability, int tech,
+            boolean isProvisioned) {
+        if (tech != ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN
+                && tech != ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+            throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
+        }
+        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp, subId,
+                "setProvisioningStatusForCapability");
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
+            Phone phone = getPhone(subId);
+            if (phone == null) {
+                loge("setImsProvisioningStatusForCapability: phone instance null for subid "
+                        + subId);
+                return;
+            }
+            if (!doesImsCapabilityRequireProvisioning(phone.getContext(), subId, capability)) {
+                return;
+            }
+
+            // this capability requires provisioning, route to the correct API.
+            ImsManager ims = ImsManager.getInstance(mApp, getSlotIndex(subId));
+            switch (capability) {
+                case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE: {
+                    if (tech == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+                        ims.setVolteProvisioned(isProvisioned);
+                    } else if (tech == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN) {
+                        ims.setWfcProvisioned(isProvisioned);
+                    }
+                    break;
+                }
+                case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO: {
+                    // There is currently no difference in VT provisioning type.
+                    ims.setVtProvisioned(isProvisioned);
+                    break;
+                }
+                case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT: {
+                    // There is no "deprecated" UT provisioning mechanism through ImsConfig, so
+                    // change the capability of the feature instead if needed.
+                    if (isMmTelCapabilityProvisionedInCache(subId, capability, tech)
+                            == isProvisioned) {
+                        // No change in provisioning.
+                        return;
+                    }
+                    cacheMmTelCapabilityProvisioning(subId, capability, tech, isProvisioned);
+                    try {
+                        ims.changeMmTelCapability(capability, tech, isProvisioned);
+                    } catch (ImsException e) {
+                        loge("setImsProvisioningStatusForCapability: couldn't change UT capability"
+                                + ", Exception" + e.getMessage());
+                    }
+                    break;
+                }
+                default: {
+                    throw new IllegalArgumentException("Tried to set provisioning for capability '"
+                            + capability + "', which does not require provisioning.");
+                }
+            }
+
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public boolean getImsProvisioningStatusForCapability(int subId, int capability, int tech) {
+        if (tech != ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN
+                && tech != ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+            throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
+        }
+        enforceReadPrivilegedPermission("getProvisioningStatusForCapability");
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
+            Phone phone = getPhone(subId);
+            if (phone == null) {
+                loge("getImsProvisioningStatusForCapability: phone instance null for subid "
+                        + subId);
+                // We will fail with "true" as the provisioning status because this is the default
+                // if we do not require provisioning.
+                return true;
+            }
+
+            if (!doesImsCapabilityRequireProvisioning(phone.getContext(), subId, capability)) {
+                return true;
+            }
+
+            ImsManager ims = ImsManager.getInstance(mApp, getSlotIndex(subId));
+            switch (capability) {
+                case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE: {
+                    if (tech == ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+                        return ims.isVolteProvisionedOnDevice();
+                    } else if (tech == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN) {
+                        return ims.isWfcProvisionedOnDevice();
+                    }
+                    // This should never happen, since we are checking tech above to make sure it
+                    // is either LTE or IWLAN.
+                    throw new IllegalArgumentException("Invalid radio technology for voice "
+                            + "capability.");
+                }
+                case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO: {
+                    // There is currently no difference in VT provisioning type.
+                    return ims.isVtProvisionedOnDevice();
+                }
+                case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT: {
+                    // There is no "deprecated" UT provisioning mechanism, so get from shared prefs.
+                    return isMmTelCapabilityProvisionedInCache(subId, capability, tech);
+                }
+                default: {
+                    throw new IllegalArgumentException("Tried to get provisioning for capability '"
+                            + capability + "', which does not require provisioning.");
+                }
+            }
+
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public boolean isMmTelCapabilityProvisionedInCache(int subId, int capability, int tech) {
+        if (tech != ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN
+                && tech != ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+            throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
+        }
+        enforceReadPrivilegedPermission("isMmTelCapabilityProvisionedInCache");
+        int provisionedBits = getMmTelCapabilityProvisioningBitfield(subId, tech);
+        return (provisionedBits & capability) > 0;
+    }
+
+    @Override
+    public void cacheMmTelCapabilityProvisioning(int subId, int capability, int tech,
+            boolean isProvisioned) {
+        if (tech != ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN
+                && tech != ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
+            throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
+        }
+        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp, subId,
+                "setProvisioningStatusForCapability");
+        int provisionedBits = getMmTelCapabilityProvisioningBitfield(subId, tech);
+        // If the current provisioning status for capability already matches isProvisioned,
+        // do nothing.
+        if (((provisionedBits & capability) > 0) == isProvisioned) {
+            return;
+        }
+        if (isProvisioned) {
+            setMmTelCapabilityProvisioningBitfield(subId, tech, (provisionedBits | capability));
+        } else {
+            setMmTelCapabilityProvisioningBitfield(subId, tech, (provisionedBits & ~capability));
+        }
+    }
+
+    /**
+     * @return the bitfield containing the MmTel provisioning for the provided subscription and
+     * technology. The bitfield should mirror the bitfield defined by
+     * {@link MmTelFeature.MmTelCapabilities.MmTelCapability}.
+     */
+    private int getMmTelCapabilityProvisioningBitfield(int subId, int tech) {
+        String key = getMmTelProvisioningKey(subId, tech);
+        // Default is no capabilities are provisioned.
+        return mTelephonySharedPreferences.getInt(key, 0 /*default*/);
+    }
+
+    /**
+     * Sets the MmTel capability provisioning bitfield (defined by
+     *     {@link MmTelFeature.MmTelCapabilities.MmTelCapability}) for the subscription and
+     *     technology specified.
+     *
+     * Note: This is a synchronous command and should not be called on UI thread.
+     */
+    private void setMmTelCapabilityProvisioningBitfield(int subId, int tech, int newField) {
+        final SharedPreferences.Editor editor = mTelephonySharedPreferences.edit();
+        String key = getMmTelProvisioningKey(subId, tech);
+        editor.putInt(key, newField);
+        editor.commit();
+    }
+
+    private static String getMmTelProvisioningKey(int subId, int tech) {
+        // resulting key is provision_ims_mmtel_{subId}_{tech}
+        return PREF_PROVISION_IMS_MMTEL_PREFIX + subId + "_" + tech;
+    }
+
+    /**
+     * Query CarrierConfig to see if the specified capability requires provisioning for the
+     * carrier associated with the subscription id.
+     */
+    private boolean doesImsCapabilityRequireProvisioning(Context context, int subId,
+            int capability) {
+        CarrierConfigManager configManager = new CarrierConfigManager(context);
+        PersistableBundle c = configManager.getConfigForSubId(subId);
+        boolean requireUtProvisioning = c.getBoolean(
+                // By default, this config is true (even if there is no SIM). We also check to make
+                // sure the subscription needs provisioning here, so we do not need to check for
+                // the no-SIM case, where we would normally shortcut this to false.
+                CarrierConfigManager.KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL, true)
+                && c.getBoolean(CarrierConfigManager.KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL,
+                false);
+        boolean requireVoiceVtProvisioning = c.getBoolean(
+                CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
+
+        // First check to make sure that the capability requires provisioning.
+        switch (capability) {
+            case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE:
+                // intentional fallthrough
+            case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO: {
+                if (requireVoiceVtProvisioning) {
+                    // Voice and Video requires provisioning
+                    return true;
+                }
+                break;
+            }
+            case MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT: {
+                if (requireUtProvisioning) {
+                    // UT requires provisioning
+                    return true;
+                }
+                break;
+            }
+        }
+        return false;
+    }
+
+    @Override
     public int getImsProvisioningInt(int subId, int key) {
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            throw new IllegalArgumentException("Invalid Subscription id '" + subId + "'");
+        }
         enforceReadPrivilegedPermission("getImsProvisioningInt");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mApp,
-                    getSlotIndexOrException(subId)).getConfigInterface().getConfigInt(key);
+            int slotId = getSlotIndex(subId);
+            if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+                Log.w(LOG_TAG, "getImsProvisioningInt: called with an inactive subscription '"
+                        + subId + "' for key:" + key);
+                return ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
+            }
+            return ImsManager.getInstance(mApp, slotId).getConfigInterface().getConfigInt(key);
         } catch (ImsException e) {
-            throw new IllegalArgumentException(e.getMessage());
+            Log.w(LOG_TAG, "getImsProvisioningInt: ImsService is not available for subscription '"
+                    + subId + "' for key:" + key);
+            return ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -3079,14 +3370,24 @@
 
     @Override
     public String getImsProvisioningString(int subId, int key) {
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            throw new IllegalArgumentException("Invalid Subscription id '" + subId + "'");
+        }
         enforceReadPrivilegedPermission("getImsProvisioningString");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mApp,
-                    getSlotIndexOrException(subId)).getConfigInterface().getConfigString(key);
+            int slotId = getSlotIndex(subId);
+            if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+                Log.w(LOG_TAG, "getImsProvisioningString: called for an inactive subscription id '"
+                        + subId + "' for key:" + key);
+                return ProvisioningManager.STRING_QUERY_RESULT_ERROR_GENERIC;
+            }
+            return ImsManager.getInstance(mApp, slotId).getConfigInterface().getConfigString(key);
         } catch (ImsException e) {
-            throw new IllegalArgumentException(e.getMessage());
+            Log.w(LOG_TAG, "getImsProvisioningString: ImsService is not available for sub '"
+                    + subId + "' for key:" + key);
+            return ProvisioningManager.STRING_QUERY_RESULT_ERROR_NOT_READY;
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -3094,15 +3395,25 @@
 
     @Override
     public int setImsProvisioningInt(int subId, int key, int value) {
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            throw new IllegalArgumentException("Invalid Subscription id '" + subId + "'");
+        }
         TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp, subId,
                 "setImsProvisioningInt");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mApp,
-                    getSlotIndexOrException(subId)).getConfigInterface().setConfig(key, value);
+            int slotId = getSlotIndex(subId);
+            if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+                Log.w(LOG_TAG, "setImsProvisioningInt: called with an inactive subscription id '"
+                        + subId + "' for key:" + key);
+                return ImsConfigImplBase.CONFIG_RESULT_FAILED;
+            }
+            return ImsManager.getInstance(mApp, slotId).getConfigInterface().setConfig(key, value);
         } catch (ImsException e) {
-            throw new IllegalArgumentException(e.getMessage());
+            Log.w(LOG_TAG, "setImsProvisioningInt: ImsService unavailable for sub '" + subId
+                    + "' for key:" + key);
+            return ImsConfigImplBase.CONFIG_RESULT_FAILED;
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -3110,15 +3421,25 @@
 
     @Override
     public int setImsProvisioningString(int subId, int key, String value) {
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            throw new IllegalArgumentException("Invalid Subscription id '" + subId + "'");
+        }
         TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp, subId,
                 "setImsProvisioningString");
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mApp,
-                    getSlotIndexOrException(subId)).getConfigInterface().setConfig(key, value);
+            int slotId = getSlotIndex(subId);
+            if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+                Log.w(LOG_TAG, "setImsProvisioningString: called with an inactive subscription id '"
+                        + subId + "' for key:" + key);
+                return ImsConfigImplBase.CONFIG_RESULT_FAILED;
+            }
+            return ImsManager.getInstance(mApp, slotId).getConfigInterface().setConfig(key, value);
         } catch (ImsException e) {
-            throw new IllegalArgumentException(e.getMessage());
+            Log.w(LOG_TAG, "setImsProvisioningString: ImsService unavailable for sub '" + subId
+                    + "' for key:" + key);
+            return ImsConfigImplBase.CONFIG_RESULT_FAILED;
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -3127,7 +3448,15 @@
     private int getSlotIndexOrException(int subId) throws IllegalArgumentException {
         int slotId = SubscriptionManager.getSlotIndex(subId);
         if (!SubscriptionManager.isValidSlotIndex(slotId)) {
-            throw new IllegalArgumentException("Invalid Subscription Id.");
+            throw new IllegalArgumentException("Invalid Subscription Id, subId=" + subId);
+        }
+        return slotId;
+    }
+
+    private int getSlotIndex(int subId) {
+        int slotId = SubscriptionManager.getSlotIndex(subId);
+        if (!SubscriptionManager.isValidSlotIndex(slotId)) {
+            return SubscriptionManager.INVALID_SIM_SLOT_INDEX;
         }
         return slotId;
     }
@@ -3900,9 +4229,24 @@
      * Scans for available networks.
      */
     @Override
-    public CellNetworkScanResult getCellNetworkScanResults(int subId) {
+    public CellNetworkScanResult getCellNetworkScanResults(int subId, String callingPackage) {
         TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
                 mApp, subId, "getCellNetworkScanResults");
+        LocationAccessPolicy.LocationPermissionResult locationResult =
+                LocationAccessPolicy.checkLocationPermission(mApp,
+                        new LocationAccessPolicy.LocationPermissionQuery.Builder()
+                                .setCallingPackage(callingPackage)
+                                .setCallingPid(Binder.getCallingPid())
+                                .setCallingUid(Binder.getCallingUid())
+                                .setMethod("getCellNetworkScanResults")
+                                .setMinSdkVersionForFine(Build.VERSION_CODES.Q)
+                                .build());
+        switch (locationResult) {
+            case DENIED_HARD:
+                throw new SecurityException("Not allowed to access scan results -- location");
+            case DENIED_SOFT:
+                return null;
+        }
 
         long identity = Binder.clearCallingIdentity();
         try {
@@ -3925,17 +4269,29 @@
      */
     @Override
     public int requestNetworkScan(int subId, NetworkScanRequest request, Messenger messenger,
-            IBinder binder) {
+            IBinder binder, String callingPackage) {
         TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
                 mApp, subId, "requestNetworkScan");
 
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            return mNetworkScanRequestTracker.startNetworkScan(
-                    request, messenger, binder, getPhone(subId));
-        } finally {
-            Binder.restoreCallingIdentity(identity);
+        LocationAccessPolicy.LocationPermissionResult locationResult =
+                LocationAccessPolicy.checkLocationPermission(mApp,
+                        new LocationAccessPolicy.LocationPermissionQuery.Builder()
+                                .setCallingPackage(callingPackage)
+                                .setCallingPid(Binder.getCallingPid())
+                                .setCallingUid(Binder.getCallingUid())
+                                .setMethod("requestNetworkScan")
+                                .setMinSdkVersionForFine(Build.VERSION_CODES.Q)
+                                .build());
+        switch (locationResult) {
+            case DENIED_HARD:
+                throw new SecurityException("Not allowed to request network scan -- location");
+            case DENIED_SOFT:
+                return -1;
         }
+
+        return mNetworkScanRequestTracker.startNetworkScan(
+                request, messenger, binder, getPhone(subId),
+                callingPackage);
     }
 
     /**
@@ -3988,8 +4344,9 @@
      */
     @Override
     public int getPreferredNetworkType(int subId) {
-        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
-                mApp, subId, "getPreferredNetworkType");
+        TelephonyPermissions
+                .enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
+                        mApp, subId, "getPreferredNetworkType");
 
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -4836,51 +5193,29 @@
     }
 
     @Override
-    public String getLocaleFromDefaultSim() {
+    public String getSimLocaleForSubscriber(int subId) {
+        enforceReadPrivilegedPermission("getSimLocaleForSubscriber, subId: " + subId);
+        final Phone phone = getPhone(subId);
+        if (phone == null) {
+            log("getSimLocaleForSubscriber, invalid subId");
+            return null;
+        }
         final long identity = Binder.clearCallingIdentity();
         try {
-            // We query all subscriptions instead of just the active ones, because
-            // this might be called early on in the provisioning flow when the
-            // subscriptions potentially aren't active yet.
-            final List<SubscriptionInfo> slist = getAllSubscriptionInfoList();
-            if (slist == null || slist.isEmpty()) {
-                return null;
-            }
-
-            // This function may be called very early, say, from the setup wizard, at
-            // which point we won't have a default subscription set. If that's the case
-            // we just choose the first, which will be valid in "most cases".
-            final int defaultSubId = getDefaultSubscription();
-            SubscriptionInfo info = null;
-            if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
-                info = slist.get(0);
-            } else {
-                for (SubscriptionInfo item : slist) {
-                    if (item.getSubscriptionId() == defaultSubId) {
-                        info = item;
-                        break;
-                    }
-                }
-
-                if (info == null) {
-                    return null;
-                }
-            }
-
+            final SubscriptionInfo info = mSubscriptionController.getActiveSubscriptionInfo(subId,
+                    phone.getContext().getOpPackageName());
             // Try and fetch the locale from the carrier properties or from the SIM language
             // preferences (EF-PL and EF-LI)...
             final int mcc = info.getMcc();
-            final Phone defaultPhone = getPhone(info.getSubscriptionId());
             String simLanguage = null;
-            if (defaultPhone != null) {
-                final Locale localeFromDefaultSim = defaultPhone.getLocaleFromSimAndCarrierPrefs();
-                if (localeFromDefaultSim != null) {
-                    if (!localeFromDefaultSim.getCountry().isEmpty()) {
-                        if (DBG) log("Using locale from default SIM:" + localeFromDefaultSim);
-                        return localeFromDefaultSim.toLanguageTag();
-                    } else {
-                        simLanguage = localeFromDefaultSim.getLanguage();
-                    }
+            final Locale localeFromDefaultSim = phone.getLocaleFromSimAndCarrierPrefs();
+            if (localeFromDefaultSim != null) {
+                if (!localeFromDefaultSim.getCountry().isEmpty()) {
+                    if (DBG) log("Using locale from subId: " + subId + " locale: "
+                            + localeFromDefaultSim);
+                    return localeFromDefaultSim.toLanguageTag();
+                } else {
+                    simLanguage = localeFromDefaultSim.getLanguage();
                 }
             }
 
@@ -4890,7 +5225,7 @@
             // determined from the SIM MCC to provide an exact locale.
             final Locale mccLocale = MccTable.getLocaleFromMcc(mApp, mcc, simLanguage);
             if (mccLocale != null) {
-                if (DBG) log("No locale from default SIM, using mcc locale:" + mccLocale);
+                if (DBG) log("No locale from SIM, using mcc locale:" + mccLocale);
                 return mccLocale.toLanguageTag();
             }
 
@@ -4997,6 +5332,31 @@
             return null;
         }
 
+        LocationAccessPolicy.LocationPermissionResult fineLocationResult =
+                LocationAccessPolicy.checkLocationPermission(mApp,
+                        new LocationAccessPolicy.LocationPermissionQuery.Builder()
+                                .setCallingPackage(callingPackage)
+                                .setCallingPid(Binder.getCallingPid())
+                                .setCallingUid(Binder.getCallingUid())
+                                .setMethod("getServiceStateForSubscriber")
+                                .setMinSdkVersionForFine(Build.VERSION_CODES.Q)
+                                .build());
+
+        LocationAccessPolicy.LocationPermissionResult coarseLocationResult =
+                LocationAccessPolicy.checkLocationPermission(mApp,
+                        new LocationAccessPolicy.LocationPermissionQuery.Builder()
+                                .setCallingPackage(callingPackage)
+                                .setCallingPid(Binder.getCallingPid())
+                                .setCallingUid(Binder.getCallingUid())
+                                .setMethod("getServiceStateForSubscriber")
+                                .setMinSdkVersionForCoarse(Build.VERSION_CODES.Q)
+                                .build());
+        // We don't care about hard or soft here -- all we need to know is how much info to scrub.
+        boolean hasFinePermission =
+                fineLocationResult == LocationAccessPolicy.LocationPermissionResult.ALLOWED;
+        boolean hasCoarsePermission =
+                coarseLocationResult == LocationAccessPolicy.LocationPermissionResult.ALLOWED;
+
         final long identity = Binder.clearCallingIdentity();
         try {
             final Phone phone = getPhone(subId);
@@ -5004,7 +5364,13 @@
                 return null;
             }
 
-            return phone.getServiceState();
+            ServiceState ss = phone.getServiceState();
+
+            // Scrub out the location info in ServiceState depending on what level of access
+            // the caller has.
+            if (hasFinePermission) return ss;
+            if (hasCoarsePermission) return ss.sanitizeLocationInfo(false);
+            return ss.sanitizeLocationInfo(true);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -5696,13 +6062,43 @@
     }
 
     @Override
-    public UiccCardInfo[] getUiccCardsInfo() {
-        enforceReadPrivilegedPermission("getUiccCardsInfo");
+    public List<UiccCardInfo> getUiccCardsInfo(String callingPackage) {
+        try {
+            enforceReadPrivilegedPermission("getUiccCardsInfo");
+        } catch (SecurityException e) {
+            // even without READ_PRIVILEGED_PHONE_STATE, we allow the call to continue if the caller
+            // has carrier privileges on an active UICC
+            if (checkCarrierPrivilegesForPackageAnyPhone(callingPackage)
+                        != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+                throw new SecurityException("Caller does not have carrier privileges on any UICC");
+            }
+        }
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            ArrayList<UiccCardInfo> cards = UiccController.getInstance().getAllUiccCardInfos();
-            return cards.toArray(new UiccCardInfo[cards.size()]);
+            UiccController uiccController = UiccController.getInstance();
+            ArrayList<UiccCardInfo> cardInfos = uiccController.getAllUiccCardInfos();
+
+            ApplicationInfo ai = mApp.getPackageManager().getApplicationInfo(callingPackage, 0);
+            if ((ai.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+                // Remove private info if the caller doesn't have access
+                ArrayList<UiccCardInfo> filteredInfos = new ArrayList<>();
+                for (UiccCardInfo cardInfo : cardInfos) {
+                    UiccCard card = uiccController.getUiccCard(cardInfo.getSlotIndex());
+                    UiccProfile profile = card.getUiccProfile();
+                    if (profile.getCarrierPrivilegeStatus(mApp.getPackageManager(), callingPackage)
+                            != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+                        filteredInfos.add(cardInfo.getUnprivileged());
+                    } else {
+                        filteredInfos.add(cardInfo);
+                    }
+                }
+                return filteredInfos;
+            }
+            return cardInfos;
+        } catch (PackageManager.NameNotFoundException e) {
+            // This should not happen since we pass the package info in from TelephonyManager
+            throw new SecurityException("Invalid calling package.");
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -5782,11 +6178,6 @@
 
     @Override
     public int getCardIdForDefaultEuicc(int subId, String callingPackage) {
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, subId, callingPackage, "getCardIdForDefaultEuicc")) {
-            return TelephonyManager.INVALID_CARD_ID;
-        }
-
         final long identity = Binder.clearCallingIdentity();
         try {
             return UiccController.getInstance().getCardIdForDefaultEuicc();
@@ -6085,6 +6476,52 @@
         }
     }
 
+    /**
+     * Update emergency number list for test mode.
+     */
+    @Override
+    public void updateEmergencyNumberListTestMode(int action, EmergencyNumber num) {
+        TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(),
+                "updateEmergencyNumberListTestMode");
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            for (Phone phone: PhoneFactory.getPhones()) {
+                EmergencyNumberTracker tracker = phone.getEmergencyNumberTracker();
+                if (tracker != null) {
+                    tracker.executeEmergencyNumberTestModeCommand(action, num);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Get the full emergency number list for test mode.
+     */
+    @Override
+    public List<String> getEmergencyNumberListTestMode() {
+        TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(),
+                "getEmergencyNumberListTestMode");
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            Set<String> emergencyNumbers = new HashSet<>();
+            for (Phone phone: PhoneFactory.getPhones()) {
+                EmergencyNumberTracker tracker = phone.getEmergencyNumberTracker();
+                if (tracker != null) {
+                    for (EmergencyNumber num : tracker.getEmergencyNumberList()) {
+                        emergencyNumbers.add(num.getNumber());
+                    }
+                }
+            }
+            return new ArrayList<>(emergencyNumbers);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     @Override
     public List<String> getCertsFromCarrierPrivilegeAccessRules(int subId) {
         enforceReadPrivilegedPermission("getCertsFromCarrierPrivilegeAccessRules");
@@ -6124,4 +6561,126 @@
             Binder.restoreCallingIdentity(identity);
         }
     }
+
+    @Override
+    public void setMultisimCarrierRestriction(boolean isMultisimCarrierRestricted) {
+        enforceModifyPermission();
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            mTelephonySharedPreferences.edit()
+                    .putBoolean(PREF_MULTI_SIM_RESTRICTED, isMultisimCarrierRestricted)
+                    .commit();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public boolean isMultisimSupported(String callingPackage) {
+        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp,
+                getDefaultPhone().getSubId(), callingPackage, "isMultisimSupported")) {
+            return false;
+        }
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            // If the device has less than 2 SIM cards, indicate that multisim is restricted.
+            int numPhysicalSlots = UiccController.getInstance().getUiccSlots().length;
+            if (numPhysicalSlots < 2) {
+                loge("isMultisimSupported: requires at least 2 cards");
+                return false;
+            }
+            // Check if the hardware supports multisim functionality. If usage of multisim is not
+            // supported by the modem, indicate that it is restricted.
+            PhoneCapability staticCapability =
+                    mPhoneConfigurationManager.getStaticPhoneCapability();
+            if (staticCapability == null) {
+                loge("isMultisimSupported: no static configuration available");
+                return false;
+            }
+            if (staticCapability.logicalModemList.size() < 2) {
+                loge("isMultisimSupported: maximum number of modem is < 2");
+                return false;
+            }
+            // Check if support of multiple SIMs is restricted by carrier
+            if (mTelephonySharedPreferences.getBoolean(PREF_MULTI_SIM_RESTRICTED, false)) {
+                return false;
+            }
+
+            return true;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Switch configs to enable multi-sim or switch back to single-sim
+     * @param numOfSims number of active sims we want to switch to
+     */
+    @Override
+    public void switchMultiSimConfig(int numOfSims) {
+        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+                mApp, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, "switchMultiSimConfig");
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            mPhoneConfigurationManager.switchMultiSimConfig(numOfSims);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Get whether reboot is required or not after making changes to modem configurations.
+     * Return value defaults to true
+     */
+    @Override
+    public boolean isRebootRequiredForModemConfigChange() {
+        enforceReadPrivilegedPermission("isRebootRequiredForModemConfigChange");
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return mPhoneConfigurationManager.isRebootRequiredForModemConfigChange();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private void updateModemStateMetrics() {
+        TelephonyMetrics metrics = TelephonyMetrics.getInstance();
+        // TODO: check the state for each modem if the api is ready.
+        metrics.updateEnabledModemBitmap((1 << TelephonyManager.from(mApp).getPhoneCount()) - 1);
+    }
+
+    @Override
+    public int[] getSlotsMapping() {
+        enforceReadPrivilegedPermission("getSlotsMapping");
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            int phoneCount = TelephonyManager.getDefault().getPhoneCount();
+            // All logical slots should have a mapping to a physical slot.
+            int[] logicalSlotsMapping = new int[phoneCount];
+            UiccSlotInfo[] slotInfos = getUiccSlotsInfo();
+            for (int i = 0; i < slotInfos.length; i++) {
+                if (SubscriptionManager.isValidPhoneId(slotInfos[i].getLogicalSlotIdx())) {
+                    logicalSlotsMapping[slotInfos[i].getLogicalSlotIdx()] = i;
+                }
+            }
+            return logicalSlotsMapping;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Get the IRadio HAL Version
+     */
+    @Override
+    public int getRadioHalVersion() {
+        Phone phone = getDefaultPhone();
+        if (phone == null) return -1;
+        HalVersion hv = phone.getHalVersion();
+        if (hv.equals(HalVersion.UNKNOWN)) return -1;
+        return hv.major * 100 + hv.minor;
+    }
 }
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index c1bd1b6..d3f780f 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -19,7 +19,6 @@
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.ProgressDialog;
-import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -429,6 +428,12 @@
             // been assigned for the PUK unlock / SIM READY process.
             app.setPukEntryProgressDialog(pd);
 
+        } else if ((app.getPUKEntryActivity() != null) && (state == MmiCode.State.FAILED)) {
+            createUssdDialog(app, context, text,
+                    WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+            // In case of failure to unlock, we'll need to reset the
+            // PUK unlock activity, so that the user may try again.
+            app.setPukEntryActivity(null);
         } else {
             // In case of failure to unlock, we'll need to reset the
             // PUK unlock activity, so that the user may try again.
@@ -439,42 +444,8 @@
             // A USSD in a pending state means that it is still
             // interacting with the user.
             if (state != MmiCode.State.PENDING) {
-                log("displayMMIComplete: MMI code has finished running.");
-
-                log("displayMMIComplete: Extended NW displayMMIInitiate (" + text + ")");
-                if (text == null || text.length() == 0)
-                    return;
-
-                // displaying system alert dialog on the screen instead of
-                // using another activity to display the message.  This
-                // places the message at the forefront of the UI.
-
-                if (sUssdDialog == null) {
-                    sUssdDialog = new AlertDialog.Builder(context, THEME)
-                            .setPositiveButton(R.string.ok, null)
-                            .setCancelable(true)
-                            .setOnDismissListener(new DialogInterface.OnDismissListener() {
-                                @Override
-                                public void onDismiss(DialogInterface dialog) {
-                                    sUssdMsg.setLength(0);
-                                }
-                            })
-                            .create();
-
-                    sUssdDialog.getWindow().setType(
-                            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-                    sUssdDialog.getWindow().addFlags(
-                            WindowManager.LayoutParams.FLAG_DIM_BEHIND);
-                }
-                if (sUssdMsg.length() != 0) {
-                    sUssdMsg
-                            .insert(0, "\n")
-                            .insert(0, app.getResources().getString(R.string.ussd_dialog_sep))
-                            .insert(0, "\n");
-                }
-                sUssdMsg.insert(0, text);
-                sUssdDialog.setMessage(sUssdMsg.toString());
-                sUssdDialog.show();
+                createUssdDialog(app, context, text,
+                        WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
             } else {
                 log("displayMMIComplete: USSD code has requested user input. Constructing input "
                         + "dialog.");
@@ -588,6 +559,46 @@
         }
     }
 
+    private static void createUssdDialog(PhoneGlobals app, Context context, CharSequence text,
+            int windowType) {
+        log("displayMMIComplete: MMI code has finished running.");
+
+        log("displayMMIComplete: Extended NW displayMMIInitiate (" + text + ")");
+        if (text == null || text.length() == 0) {
+            return;
+        }
+
+        // displaying system alert dialog on the screen instead of
+        // using another activity to display the message.  This
+        // places the message at the forefront of the UI.
+
+        if (sUssdDialog == null) {
+            sUssdDialog = new AlertDialog.Builder(context, THEME)
+                    .setPositiveButton(R.string.ok, null)
+                    .setCancelable(true)
+                    .setOnDismissListener(new DialogInterface.OnDismissListener() {
+                        @Override
+                        public void onDismiss(DialogInterface dialog) {
+                            sUssdMsg.setLength(0);
+                        }
+                    })
+                    .create();
+
+            sUssdDialog.getWindow().setType(windowType);
+            sUssdDialog.getWindow().addFlags(
+                    WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+        }
+        if (sUssdMsg.length() != 0) {
+            sUssdMsg
+                    .insert(0, "\n")
+                    .insert(0, app.getResources().getString(R.string.ussd_dialog_sep))
+                    .insert(0, "\n");
+        }
+        sUssdMsg.insert(0, text);
+        sUssdDialog.setMessage(sUssdMsg.toString());
+        sUssdDialog.show();
+    }
+
     /**
      * Cancels the current pending MMI operation, if applicable.
      * @return true if we canceled an MMI operation, or false
@@ -1284,6 +1295,34 @@
     }
 
     /**
+     * Register ICC status for all phones.
+     */
+    static final void registerIccStatus(Handler handler, int event, int phoneId) {
+        Phone[] phones = PhoneFactory.getPhones();
+        IccCard sim = phones[phoneId].getIccCard();
+        if (sim != null) {
+            if (VDBG) {
+                Log.v(LOG_TAG, "register for ICC status, phone " + phones[phoneId].getPhoneId());
+            }
+            sim.registerForNetworkLocked(handler, event, phones[phoneId]);
+        }
+    }
+
+    /**
+     * Unregister ICC status for a specific phone.
+     */
+    static final void unregisterIccStatus(Handler handler, int phoneId) {
+        Phone[] phones = PhoneFactory.getPhones();
+        IccCard sim = phones[phoneId].getIccCard();
+        if (sim != null) {
+            if (VDBG) {
+                Log.v(LOG_TAG, "unregister for ICC status, phone " + phones[phoneId].getPhoneId());
+            }
+            sim.unregisterForNetworkLocked(handler);
+        }
+    }
+
+    /**
      * Set the radio power on/off state for all phones.
      *
      * @param enabled true means on, false means off.
diff --git a/src/com/android/phone/ShortcutViewUtils.java b/src/com/android/phone/ShortcutViewUtils.java
new file mode 100644
index 0000000..595ea86
--- /dev/null
+++ b/src/com/android/phone/ShortcutViewUtils.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import android.content.Context;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.telephony.emergency.EmergencyNumber;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+class ShortcutViewUtils {
+    private static final String LOG_TAG = "ShortcutViewUtils";
+
+    // Emergency services which will be promoted on the shortcut view.
+    static final int[] PROMOTED_CATEGORIES = {
+            EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE,
+            EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE,
+            EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE,
+    };
+
+    static final int PROMOTED_CATEGORIES_BITMASK;
+
+    static {
+        int bitmask = 0;
+        for (int category : PROMOTED_CATEGORIES) {
+            bitmask |= category;
+        }
+        PROMOTED_CATEGORIES_BITMASK = bitmask;
+    }
+
+    // Info and emergency call capability of every phone.
+    static class PhoneInfo {
+        private final PhoneAccountHandle mHandle;
+        private final boolean mCanPlaceEmergencyCall;
+        private final int mSubId;
+        private final String mCountryIso;
+        private final List<EmergencyNumber> mPromotedEmergencyNumbers;
+
+        private PhoneInfo(int subId, String countryIso,
+                List<EmergencyNumber> promotedEmergencyNumbers) {
+            this(null, true, subId, countryIso, promotedEmergencyNumbers);
+        }
+
+        private PhoneInfo(PhoneAccountHandle handle, boolean canPlaceEmergencyCall, int subId,
+                String countryIso, List<EmergencyNumber> promotedEmergencyNumbers) {
+            mHandle = handle;
+            mCanPlaceEmergencyCall = canPlaceEmergencyCall;
+            mSubId = subId;
+            mCountryIso = countryIso;
+            mPromotedEmergencyNumbers = promotedEmergencyNumbers;
+        }
+
+        public PhoneAccountHandle getPhoneAccountHandle() {
+            return mHandle;
+        }
+
+        public boolean canPlaceEmergencyCall() {
+            return mCanPlaceEmergencyCall;
+        }
+
+        public int getSubId() {
+            return mSubId;
+        }
+
+        public String getCountryIso() {
+            return mCountryIso;
+        }
+
+        public List<EmergencyNumber> getPromotedEmergencyNumbers() {
+            return mPromotedEmergencyNumbers;
+        }
+
+        public boolean isSufficientForEmergencyCall(@NonNull Context context) {
+            // Checking mCountryIso because the emergency number list is not reliable to be
+            // suggested to users if the device didn't camp to any network. In this case, users
+            // can still try to dial emergency numbers with dial pad.
+            return mCanPlaceEmergencyCall && mPromotedEmergencyNumbers != null
+                    && isSupportedCountry(context, mCountryIso);
+        }
+
+        public boolean hasPromotedEmergencyNumber(String number) {
+            for (EmergencyNumber emergencyNumber : mPromotedEmergencyNumbers) {
+                if (emergencyNumber.getNumber().equalsIgnoreCase(number)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("{");
+            if (mHandle != null) {
+                sb.append("handle=").append(mHandle.getId()).append(", ");
+            }
+            sb.append("subId=").append(mSubId)
+                    .append(", canPlaceEmergencyCall=").append(mCanPlaceEmergencyCall)
+                    .append(", networkCountryIso=").append(mCountryIso);
+            if (mPromotedEmergencyNumbers != null) {
+                sb.append(", emergencyNumbers=");
+                for (EmergencyNumber emergencyNumber : mPromotedEmergencyNumbers) {
+                    sb.append(emergencyNumber.getNumber()).append(":")
+                            .append(emergencyNumber).append(",");
+                }
+            }
+            sb.append("}");
+            return sb.toString();
+        }
+    }
+
+    /**
+     * Picks a preferred phone (SIM slot) which is sufficient for emergency call and can provide
+     * promoted emergency numbers.
+     *
+     * A promoted emergency number should be dialed out over the preferred phone. Other emergency
+     * numbers should be still dialable over the system default phone.
+     *
+     * @return A preferred phone and its promoted emergency number, or null if no phone/promoted
+     * emergency numbers available.
+     */
+    @Nullable
+    static PhoneInfo pickPreferredPhone(@NonNull Context context) {
+        TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
+        if (telephonyManager.getPhoneCount() <= 0) {
+            Log.w(LOG_TAG, "No phone available!");
+            return null;
+        }
+
+        Map<Integer, List<EmergencyNumber>> promotedLists =
+                getPromotedEmergencyNumberLists(telephonyManager);
+        if (promotedLists == null || promotedLists.isEmpty()) {
+            return null;
+        }
+
+        // For a multi-phone device, tries the default phone account.
+        TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
+        PhoneAccountHandle defaultHandle = telecomManager.getDefaultOutgoingPhoneAccount(
+                PhoneAccount.SCHEME_TEL);
+        if (defaultHandle != null) {
+            PhoneInfo phone = loadPhoneInfo(defaultHandle, telephonyManager, telecomManager,
+                    promotedLists);
+            if (phone.isSufficientForEmergencyCall(context)) {
+                return phone;
+            }
+            Log.w(LOG_TAG, "Default PhoneAccount is insufficient for emergency call: "
+                    + phone.toString());
+        } else {
+            Log.w(LOG_TAG, "Missing default PhoneAccount! Is this really a phone device?");
+        }
+
+        // Looks for any one phone which supports emergency call.
+        List<PhoneAccountHandle> allHandles = telecomManager.getCallCapablePhoneAccounts();
+        if (allHandles != null && !allHandles.isEmpty()) {
+            for (PhoneAccountHandle handle : allHandles) {
+                PhoneInfo phone = loadPhoneInfo(handle, telephonyManager, telecomManager,
+                        promotedLists);
+                if (phone.isSufficientForEmergencyCall(context)) {
+                    return phone;
+                } else {
+                    if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
+                        Log.d(LOG_TAG, "PhoneAccount " + phone.toString()
+                                + " is insufficient for emergency call.");
+                    }
+                }
+            }
+        }
+
+        Log.w(LOG_TAG, "No PhoneAccount available for emergency call!");
+        return null;
+    }
+
+    private static boolean isSupportedCountry(@NonNull Context context, String countryIso) {
+        if (TextUtils.isEmpty(countryIso)) {
+            return false;
+        }
+
+        String[] countrysToEnableShortcutView = context.getResources().getStringArray(
+                R.array.config_countries_to_enable_shortcut_view);
+        for (String supportedCountry : countrysToEnableShortcutView) {
+            if (countryIso.equalsIgnoreCase(supportedCountry)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static PhoneInfo loadPhoneInfo(@NonNull PhoneAccountHandle handle,
+            @NonNull TelephonyManager telephonyManager, @NonNull TelecomManager telecomManager,
+            Map<Integer, List<EmergencyNumber>> promotedLists) {
+        boolean canPlaceEmergencyCall = false;
+        int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+        String countryIso = null;
+        List<EmergencyNumber> emergencyNumberList = null;
+
+        PhoneAccount phoneAccount = telecomManager.getPhoneAccount(handle);
+        if (phoneAccount != null) {
+            canPlaceEmergencyCall = phoneAccount.hasCapabilities(
+                    PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS);
+            subId = telephonyManager.getSubIdForPhoneAccount(phoneAccount);
+        }
+
+        TelephonyManager subTelephonyManager = telephonyManager.createForSubscriptionId(subId);
+        if (subTelephonyManager != null) {
+            countryIso = subTelephonyManager.getNetworkCountryIso();
+        }
+
+        if (promotedLists != null) {
+            emergencyNumberList = promotedLists.get(subId);
+        }
+
+        return new PhoneInfo(handle, canPlaceEmergencyCall, subId, countryIso, emergencyNumberList);
+    }
+
+    @NonNull
+    private static Map<Integer, List<EmergencyNumber>> getPromotedEmergencyNumberLists(
+            @NonNull TelephonyManager telephonyManager) {
+        Map<Integer, List<EmergencyNumber>> allLists =
+                telephonyManager.getCurrentEmergencyNumberList();
+        if (allLists == null || allLists.isEmpty()) {
+            Log.w(LOG_TAG, "Unable to retrieve emergency number lists!");
+            return new ArrayMap<>();
+        }
+
+        boolean isDebugLoggable = Log.isLoggable(LOG_TAG, Log.DEBUG);
+        Map<Integer, List<EmergencyNumber>> promotedEmergencyNumberLists = new ArrayMap<>();
+        for (Map.Entry<Integer, List<EmergencyNumber>> entry : allLists.entrySet()) {
+            if (entry.getKey() == null || entry.getValue() == null) {
+                continue;
+            }
+            List<EmergencyNumber> emergencyNumberList = entry.getValue();
+            if (isDebugLoggable) {
+                Log.d(LOG_TAG, "Emergency numbers of " + entry.getKey());
+            }
+
+            // The list of promoted emergency numbers which will be visible on shortcut view.
+            List<EmergencyNumber> promotedList = new ArrayList<>();
+            // A temporary list for non-prioritized emergency numbers.
+            List<EmergencyNumber> tempList = new ArrayList<>();
+
+            for (EmergencyNumber emergencyNumber : emergencyNumberList) {
+                boolean isPromotedCategory = (emergencyNumber.getEmergencyServiceCategoryBitmask()
+                        & PROMOTED_CATEGORIES_BITMASK) != 0;
+
+                // Emergency numbers in DATABASE are prioritized for shortcut view since they were
+                // well-categorized.
+                boolean isFromPrioritizedSource =
+                        (emergencyNumber.getEmergencyNumberSourceBitmask()
+                                & EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE) != 0;
+                if (isDebugLoggable) {
+                    Log.d(LOG_TAG, "  " + emergencyNumber
+                            + (isPromotedCategory ? "M" : "")
+                            + (isFromPrioritizedSource ? "P" : ""));
+                }
+
+                if (isPromotedCategory) {
+                    if (isFromPrioritizedSource) {
+                        promotedList.add(emergencyNumber);
+                    } else {
+                        tempList.add(emergencyNumber);
+                    }
+                }
+            }
+            // Puts numbers in temp list after prioritized numbers.
+            promotedList.addAll(tempList);
+
+            if (!promotedList.isEmpty()) {
+                promotedEmergencyNumberLists.put(entry.getKey(), promotedList);
+            }
+        }
+
+        if (promotedEmergencyNumberLists.isEmpty()) {
+            Log.w(LOG_TAG, "No promoted emergency number found!");
+        }
+        return promotedEmergencyNumberLists;
+    }
+}
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index 9250118..956e0e2 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -22,11 +22,14 @@
 import android.os.ShellCommand;
 import android.os.UserHandle;
 import android.telephony.SubscriptionManager;
+import android.telephony.emergency.EmergencyNumber;
 import android.util.Log;
 
 import com.android.internal.telephony.ITelephony;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
 
 /**
  * Takes actions based on the adb commands given by "adb shell cmd phone ...". Be careful, no
@@ -44,6 +47,7 @@
     private static final String IMS_SUBCOMMAND = "ims";
     private static final String SMS_SUBCOMMAND = "sms";
     private static final String NUMBER_VERIFICATION_SUBCOMMAND = "numverify";
+    private static final String EMERGENCY_NUMBER_TEST_MODE = "emergency-number-test-mode";
 
     private static final String IMS_SET_CARRIER_SERVICE = "set-ims-service";
     private static final String IMS_GET_CARRIER_SERVICE = "get-ims-service";
@@ -79,6 +83,8 @@
             }
             case NUMBER_VERIFICATION_SUBCOMMAND:
                 return handleNumberVerificationCommand();
+            case EMERGENCY_NUMBER_TEST_MODE:
+                return handleEmergencyNumberTestModeCommand();
             default: {
                 return handleDefaultCommands(cmd);
             }
@@ -95,8 +101,11 @@
         pw.println("    IMS Commands.");
         pw.println("  sms");
         pw.println("    SMS Commands.");
+        pw.println("  emergency-number-test-mode");
+        pw.println("    Emergency Number Test Mode Commands.");
         onHelpIms();
         onHelpSms();
+        onHelpEmergencyNumber();
     }
 
     private void onHelpIms() {
@@ -147,6 +156,20 @@
         pw.println("    1 if the call would have been intercepted, 0 otherwise.");
     }
 
+    private void onHelpEmergencyNumber() {
+        PrintWriter pw = getOutPrintWriter();
+        pw.println("Emergency Number Test Mode Commands:");
+        pw.println("  emergency-number-test-mode ");
+        pw.println("    Add(-a), Clear(-c), Print (-p) or Remove(-r) the emergency number list in"
+                + " the test mode");
+        pw.println("      -a <emergency number address>: add an emergency number address for the"
+                + " test mode, only allows '0'-'9', '*', or '#'.");
+        pw.println("      -c: clear the emergency number list in the test mode.");
+        pw.println("      -r <emergency number address>: remove an existing emergency number"
+                + " address added by the test mode, only allows '0'-'9', '*', or '#'.");
+        pw.println("      -p: get the full emergency number list in the test mode.");
+    }
+
     private int handleImsCommand() {
         String arg = getNextArg();
         if (arg == null) {
@@ -172,6 +195,91 @@
         return -1;
     }
 
+    private int handleEmergencyNumberTestModeCommand() {
+        PrintWriter errPw = getErrPrintWriter();
+        String opt = getNextOption();
+        if (opt == null) {
+            onHelpEmergencyNumber();
+            return 0;
+        }
+
+        switch (opt) {
+            case "-a": {
+                String emergencyNumberCmd = getNextArgRequired();
+                if (emergencyNumberCmd == null
+                        || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
+                    errPw.println("An emergency number (only allow '0'-'9', '*', or '#') needs"
+                            + " to be specified after -a in the command ");
+                    return -1;
+                }
+                try {
+                    mInterface.updateEmergencyNumberListTestMode(
+                            EmergencyNumberTracker.ADD_EMERGENCY_NUMBER_TEST_MODE,
+                            new EmergencyNumber(emergencyNumberCmd, "", "",
+                                    EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
+                                    new ArrayList<String>(),
+                                    EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
+                                    EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
+                } catch (RemoteException ex) {
+                    Log.w(LOG_TAG, "emergency-number-test-mode -a " + emergencyNumberCmd
+                            + ", error " + ex.getMessage());
+                    errPw.println("Exception: " + ex.getMessage());
+                    return -1;
+                }
+                break;
+            }
+            case "-c": {
+                try {
+                    mInterface.updateEmergencyNumberListTestMode(
+                            EmergencyNumberTracker.RESET_EMERGENCY_NUMBER_TEST_MODE, null);
+                } catch (RemoteException ex) {
+                    Log.w(LOG_TAG, "emergency-number-test-mode -c " + "error " + ex.getMessage());
+                    errPw.println("Exception: " + ex.getMessage());
+                    return -1;
+                }
+                break;
+            }
+            case "-r": {
+                String emergencyNumberCmd = getNextArgRequired();
+                if (emergencyNumberCmd == null
+                        || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
+                    errPw.println("An emergency number (only allow '0'-'9', '*', or '#') needs"
+                            + " to be specified after -r in the command ");
+                    return -1;
+                }
+                try {
+                    mInterface.updateEmergencyNumberListTestMode(
+                            EmergencyNumberTracker.REMOVE_EMERGENCY_NUMBER_TEST_MODE,
+                            new EmergencyNumber(emergencyNumberCmd, "", "",
+                                    EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
+                                    new ArrayList<String>(),
+                                    EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
+                                    EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
+                } catch (RemoteException ex) {
+                    Log.w(LOG_TAG, "emergency-number-test-mode -r " + emergencyNumberCmd
+                            + ", error " + ex.getMessage());
+                    errPw.println("Exception: " + ex.getMessage());
+                    return -1;
+                }
+                break;
+            }
+            case "-p": {
+                try {
+                    getOutPrintWriter().println(mInterface.getEmergencyNumberListTestMode());
+                } catch (RemoteException ex) {
+                    Log.w(LOG_TAG, "emergency-number-test-mode -p " + "error " + ex.getMessage());
+                    errPw.println("Exception: " + ex.getMessage());
+                    return -1;
+                }
+                break;
+            }
+            default:
+                onHelpEmergencyNumber();
+                break;
+        }
+        return 0;
+    }
+
     private int handleNumberVerificationCommand() {
         String arg = getNextArg();
         if (arg == null) {
diff --git a/src/com/android/phone/ecc/CountryEccInfo.java b/src/com/android/phone/ecc/CountryEccInfo.java
index 969901d..bc7ec84 100644
--- a/src/com/android/phone/ecc/CountryEccInfo.java
+++ b/src/com/android/phone/ecc/CountryEccInfo.java
@@ -16,8 +16,8 @@
 
 package com.android.phone.ecc;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 
 import java.util.Collection;
 
diff --git a/src/com/android/phone/ecc/EccInfo.java b/src/com/android/phone/ecc/EccInfo.java
index fb41370..a219bae 100644
--- a/src/com/android/phone/ecc/EccInfo.java
+++ b/src/com/android/phone/ecc/EccInfo.java
@@ -16,7 +16,7 @@
 
 package com.android.phone.ecc;
 
-import androidx.annotation.NonNull;
+import android.annotation.NonNull;
 
 import java.util.Collection;
 
diff --git a/src/com/android/phone/ecc/EccInfoHelper.java b/src/com/android/phone/ecc/EccInfoHelper.java
index c471c4b..875442a 100644
--- a/src/com/android/phone/ecc/EccInfoHelper.java
+++ b/src/com/android/phone/ecc/EccInfoHelper.java
@@ -16,6 +16,8 @@
 
 package com.android.phone.ecc;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.os.AsyncTask;
 import android.provider.Settings;
@@ -33,9 +35,6 @@
 import android.util.Log;
 import android.util.Pair;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
 import com.android.internal.telephony.MccTable;
 
 import java.io.IOException;
@@ -50,32 +49,6 @@
     private static final boolean DBG = false;
     private static final String LOG_TAG = "EccInfoHelper";
 
-    /**
-     * Check if current CountryEccInfo is available for current environment.
-     */
-    public static boolean isCountryEccInfoAvailable(Context context, String countryIso) {
-        CountryEccInfo countryEccInfo;
-        try {
-            countryEccInfo = IsoToEccProtobufRepository.getInstance()
-                    .getCountryEccInfo(context, countryIso);
-        } catch (IOException e) {
-            Log.e(LOG_TAG, "Failed to retrieve ECC: ", e);
-            return false;
-        }
-
-        if (countryEccInfo == null) {
-            return false;
-        }
-        for (EccInfo entry : countryEccInfo.getEccInfoList()) {
-            if (!PhoneNumberUtils.isEmergencyNumber(entry.getNumber())) {
-                // The CountryEccInfo is unavailable if any ecc number in the local table was
-                // declined.
-                return false;
-            }
-        }
-        return true;
-    }
-
     // country ISO to ECC list data source
     private IsoToEccRepository mEccRepo;
 
@@ -162,8 +135,7 @@
         }.execute();
     }
 
-    @NonNull
-    private CountryEccInfo getDialableCountryEccInfo(CountryEccInfo countryEccInfo) {
+    private @NonNull CountryEccInfo getDialableCountryEccInfo(CountryEccInfo countryEccInfo) {
         ArrayList<EccInfo> dialableECCList = new ArrayList<>();
         String dialableFallback = null;
 
@@ -182,8 +154,7 @@
         return new CountryEccInfo(dialableFallback, dialableECCList);
     }
 
-    @Nullable
-    private String getCurrentCountryIso(@NonNull Context context) {
+    private @Nullable String getCurrentCountryIso(@NonNull Context context) {
         // Do not detect country ISO if airplane mode is on
         int airplaneMode = Settings.System.getInt(context.getContentResolver(),
                 Settings.Global.AIRPLANE_MODE_ON, 0);
@@ -201,7 +172,7 @@
             // XXX: according to ServiceStateTracker's implementation, retrieve cell info in a
             // thread other than TelephonyManager's main thread.
             String mcc = getCurrentMccFromCellInfo(context);
-            iso = MccTable.countryCodeForMcc(mcc);
+            iso = countryCodeForMcc(mcc);
             if (DBG) {
                 Log.d(LOG_TAG, "Current mcc is " + Rlog.pii(LOG_TAG, mcc) + ", mapping to ISO: "
                         + Rlog.pii(LOG_TAG, iso));
@@ -210,11 +181,18 @@
         return iso;
     }
 
+    private String countryCodeForMcc(String mcc) {
+        try {
+            return MccTable.countryCodeForMcc(Integer.parseInt(mcc));
+        } catch (NumberFormatException ex) {
+            return "";
+        }
+    }
+
     // XXX: According to ServiceStateTracker implementation, to actually get current cell info,
     // this method must be called in a separate thread from ServiceStateTracker, which is the
     // main thread of Telephony service.
-    @Nullable
-    private String getCurrentMccFromCellInfo(@NonNull Context context) {
+    private @Nullable String getCurrentMccFromCellInfo(@NonNull Context context) {
         // retrieve mcc info from base station even no SIM present.
         TelephonyManager tm = (TelephonyManager) context.getSystemService(
                 Context.TELEPHONY_SERVICE);
diff --git a/src/com/android/phone/ecc/IsoToEccProtobufRepository.java b/src/com/android/phone/ecc/IsoToEccProtobufRepository.java
index 7d9b4f0..d44de9a 100644
--- a/src/com/android/phone/ecc/IsoToEccProtobufRepository.java
+++ b/src/com/android/phone/ecc/IsoToEccProtobufRepository.java
@@ -16,17 +16,14 @@
 
 package com.android.phone.ecc;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.os.SystemClock;
-import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-
 import java.io.BufferedInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -35,59 +32,42 @@
 import java.util.zip.GZIPInputStream;
 
 /**
- * Provides a mapping table from country ISO to ECC info. The data is stored in Protocol Buffers
- * binary format, compressed with GZIP.
+ * Provide the mapping of country ISO to ECC. The data is stored in Protocol Buffers format,
+ * compressed with GZIP and encoded to base64 string.
  */
 public class IsoToEccProtobufRepository implements IsoToEccRepository {
     private static final String LOG_TAG = "EccRepository";
 
-    private static IsoToEccProtobufRepository sInstance;
-
-    /**
-     * Returns the singleton instance of IsoToEccProtobufRepository
-     */
-    public static synchronized IsoToEccProtobufRepository getInstance() {
-        if (sInstance == null) {
-            sInstance = new IsoToEccProtobufRepository();
-        }
-        return sInstance;
-    }
-
-    private final Map<String, CountryEccInfo> mEccTable = new HashMap<>();
-
-    private IsoToEccProtobufRepository() {
-    }
+    private Map<String, CountryEccInfo> mEccTable = null;
 
     @Override
     @Nullable
-    public CountryEccInfo getCountryEccInfo(@NonNull Context context, String iso)
+    public CountryEccInfo getCountryEccInfo(@NonNull Context context, @Nullable String iso)
             throws IOException {
-        if (TextUtils.isEmpty(iso)) {
+        if (iso != null) {
+            iso = iso.toUpperCase();
+        } else {
             return null;
         }
 
-        synchronized (mEccTable) {
-            return mEccTable.get(iso.toUpperCase());
+        if (mEccTable == null) {
+            mEccTable = initMappingTable(context);
         }
+        return mEccTable.get(iso);
     }
 
-    /**
-     * Loads the mapping table.
-     */
-    public void loadMappingTable(@NonNull Context context) {
+    private Map<String, CountryEccInfo> initMappingTable(@NonNull Context context)
+            throws IOException {
         ProtobufEccData.AllInfo allEccData = null;
 
         long startTime = SystemClock.uptimeMillis();
-        try {
-            allEccData = parseEccData(new BufferedInputStream(
-                    context.getAssets().open("eccdata")));
-        } catch (IOException e) {
-            Log.e(LOG_TAG, "Failed to retrieve ECC: ", e);
-        }
+        allEccData = parseEccData(new BufferedInputStream(
+                context.getAssets().open("eccdata")));
         long endTime = SystemClock.uptimeMillis();
 
         if (allEccData == null) {
-            return;
+            // Return an empty table.
+            return new HashMap<>();
         }
 
         if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
@@ -96,23 +76,17 @@
                     + ", initialized = " + allEccData.isInitialized());
         }
 
-        // Converts to run-time data from Protobuf data.
-        synchronized (mEccTable) {
-            mEccTable.clear();
-            for (ProtobufEccData.CountryInfo countryData : allEccData.getCountriesList()) {
-                if (countryData.hasIsoCode()) {
-                    CountryEccInfo countryInfo = loadCountryEccInfo(countryData);
-                    if (countryInfo != null) {
-                        mEccTable.put(countryData.getIsoCode().toUpperCase(), countryInfo);
-                    }
+        // Convert to run-time data from Protobuf data.
+        Map<String, CountryEccInfo> table = new HashMap<>();
+        for (ProtobufEccData.CountryInfo countryData : allEccData.getCountriesList()) {
+            if (countryData.hasIsoCode()) {
+                CountryEccInfo countryInfo = loadCountryEccInfo(countryData);
+                if (countryInfo != null) {
+                    table.put(countryData.getIsoCode().toUpperCase(), countryInfo);
                 }
             }
         }
-    }
-
-    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    Map<String, CountryEccInfo> getEccTable() {
-        return mEccTable;
+        return table;
     }
 
     private ProtobufEccData.AllInfo parseEccData(InputStream input) throws IOException {
@@ -140,7 +114,7 @@
                     eccTypes.add(EccInfo.Type.FIRE);
                     break;
                 default:
-                    // Ignores unknown types.
+                    // Ignore unknown types.
             }
         }
 
@@ -161,7 +135,7 @@
             if (existentEccInfo == null) {
                 eccInfoMap.put(key, eccInfo);
             } else {
-                // Merges types of duplicated ECC info objects.
+                // Merge types of duplicated ecc info objects.
                 ArraySet<EccInfo.Type> eccTypes = new ArraySet<>(
                         eccInfo.getTypesCount() + existentEccInfo.getTypesCount());
                 for (EccInfo.Type type : eccInfo.getTypes()) {
diff --git a/src/com/android/phone/ecc/IsoToEccRepository.java b/src/com/android/phone/ecc/IsoToEccRepository.java
index 6d95af4..fd5ac83 100644
--- a/src/com/android/phone/ecc/IsoToEccRepository.java
+++ b/src/com/android/phone/ecc/IsoToEccRepository.java
@@ -16,11 +16,10 @@
 
 package com.android.phone.ecc;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
 import java.io.IOException;
 
 /**
diff --git a/src/com/android/phone/settings/PhoneAccountSettingsFragment.java b/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
index 670f98d..ca45b31 100644
--- a/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
+++ b/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
@@ -44,7 +44,7 @@
             "phone_accounts_accounts_list_category_key";
 
     private static final String DEFAULT_OUTGOING_ACCOUNT_KEY = "default_outgoing_account";
-    private static final String ALL_CALLING_ACCOUNTS_KEY = "phone_account_all_calling_accounts";
+    private static final String ALL_CALLING_ACCOUNTS_KEY = "phone_accounts_all_calling_accounts";
 
     private static final String SIP_SETTINGS_CATEGORY_PREF_KEY =
             "phone_accounts_sip_settings_category_key";
@@ -71,11 +71,21 @@
     private PreferenceCategory mAccountList;
 
     private AccountSelectionPreference mDefaultOutgoingAccount;
+    private Preference mAllCallingAccounts;
 
     private ListPreference mUseSipCalling;
     private SwitchPreference mSipReceiveCallsPreference;
     private SipPreferences mSipPreferences;
 
+    private final SubscriptionManager.OnSubscriptionsChangedListener
+            mOnSubscriptionsChangeListener =
+            new SubscriptionManager.OnSubscriptionsChangedListener() {
+        @Override
+        public void onSubscriptionsChanged() {
+            updateAccounts();
+        }
+    };
+
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
@@ -122,34 +132,11 @@
          */
         mAccountList = (PreferenceCategory) getPreferenceScreen().findPreference(
                 ACCOUNTS_LIST_CATEGORY_KEY);
-        List<PhoneAccountHandle> allNonSimAccounts =
-                getCallingAccounts(false /* includeSims */, true /* includeDisabled */);
-        // Check to see if we should show the entire section at all.
-        if (shouldShowConnectionServiceList(allNonSimAccounts)) {
-            List<PhoneAccountHandle> enabledAccounts =
-                    getCallingAccounts(true /* includeSims */, false /* includeDisabled */);
-            // Initialize the account list with the set of enabled & SIM accounts.
-            initAccountList(enabledAccounts);
+        mDefaultOutgoingAccount = (AccountSelectionPreference)
+                getPreferenceScreen().findPreference(DEFAULT_OUTGOING_ACCOUNT_KEY);
+        mAllCallingAccounts = getPreferenceScreen().findPreference(ALL_CALLING_ACCOUNTS_KEY);
 
-            mDefaultOutgoingAccount = (AccountSelectionPreference)
-                    getPreferenceScreen().findPreference(DEFAULT_OUTGOING_ACCOUNT_KEY);
-            mDefaultOutgoingAccount.setListener(this);
-
-            // Only show the 'Make Calls With..." option if there are multiple accounts.
-            if (enabledAccounts.size() > 1) {
-                updateDefaultOutgoingAccountsModel();
-            } else {
-                mAccountList.removePreference(mDefaultOutgoingAccount);
-            }
-
-            Preference allAccounts = getPreferenceScreen().findPreference(ALL_CALLING_ACCOUNTS_KEY);
-            // If there are no third party (nonSim) accounts, then don't show enable/disable dialog.
-            if (allNonSimAccounts.isEmpty() && allAccounts != null) {
-                mAccountList.removePreference(allAccounts);
-            }
-        } else {
-            getPreferenceScreen().removePreference(mAccountList);
-        }
+        updateAccounts();
 
         if (isPrimaryUser() && SipUtil.isVoipSupported(getActivity())) {
             mSipPreferences = new SipPreferences(getActivity());
@@ -183,6 +170,16 @@
             getPreferenceScreen().removePreference(
                     getPreferenceScreen().findPreference(SIP_SETTINGS_CATEGORY_PREF_KEY));
         }
+
+        SubscriptionManager.from(getActivity()).addOnSubscriptionsChangedListener(
+                mOnSubscriptionsChangeListener);
+    }
+
+    @Override
+    public void onPause() {
+        SubscriptionManager.from(getActivity()).removeOnSubscriptionsChangedListener(
+                mOnSubscriptionsChangeListener);
+        super.onPause();
     }
 
     /**
@@ -391,6 +388,40 @@
         return mTelephonyManager.isMultiSimEnabled() || allNonSimAccounts.size() > 0;
     }
 
+    private void updateAccounts() {
+        if (mAccountList != null) {
+            mAccountList.removeAll();
+            List<PhoneAccountHandle> allNonSimAccounts =
+                    getCallingAccounts(false /* includeSims */, true /* includeDisabled */);
+            // Check to see if we should show the entire section at all.
+            if (shouldShowConnectionServiceList(allNonSimAccounts)) {
+                List<PhoneAccountHandle> enabledAccounts =
+                        getCallingAccounts(true /* includeSims */, false /* includeDisabled */);
+                // Initialize the account list with the set of enabled & SIM accounts.
+                initAccountList(enabledAccounts);
+
+                mDefaultOutgoingAccount.setListener(this);
+                // Only show the 'Make Calls With..." option if there are multiple accounts.
+                if (enabledAccounts.size() > 1) {
+                    mAccountList.addPreference(mDefaultOutgoingAccount);
+                    updateDefaultOutgoingAccountsModel();
+                } else {
+                    mAccountList.removePreference(mDefaultOutgoingAccount);
+                }
+
+                // If there are no third party (nonSim) accounts,
+                // then don't show enable/disable dialog.
+                if (!allNonSimAccounts.isEmpty()) {
+                    mAccountList.addPreference(mAllCallingAccounts);
+                } else {
+                    mAccountList.removePreference(mAllCallingAccounts);
+                }
+            } else {
+                getPreferenceScreen().removePreference(mAccountList);
+            }
+        }
+    }
+
     private List<PhoneAccountHandle> getCallingAccounts(
             boolean includeSims, boolean includeDisabledAccounts) {
         PhoneAccountHandle emergencyAccountHandle = getEmergencyPhoneAccount();
diff --git a/src/com/android/services/telephony/ConferenceParticipantConnection.java b/src/com/android/services/telephony/ConferenceParticipantConnection.java
index 82baa92..1f330f9 100644
--- a/src/com/android/services/telephony/ConferenceParticipantConnection.java
+++ b/src/com/android/services/telephony/ConferenceParticipantConnection.java
@@ -33,11 +33,6 @@
  * Represents a participant in a conference call.
  */
 public class ConferenceParticipantConnection extends Connection {
-    /**
-     * RFC5767 states that a SIP URI with an unknown number should use an address of
-     * {@code anonymous@anonymous.invalid}.  E.g. the host name is anonymous.invalid.
-     */
-    private static final String ANONYMOUS_INVALID_HOST = "anonymous.invalid";
 
     /**
      * The user entity URI For the conference participant.
@@ -65,7 +60,7 @@
 
         mParentConnection = parentConnection;
 
-        int presentation = getParticipantPresentation(participant);
+        int presentation = participant.getParticipantPresentation();
         Uri address;
         if (presentation != PhoneConstants.PRESENTATION_ALLOWED) {
             address = null;
@@ -161,53 +156,7 @@
         setConnectionCapabilities(capabilities);
     }
 
-    /**
-     * Determines the number presentation for a conference participant.  Per RFC5767, if the host
-     * name contains {@code anonymous.invalid} we can assume that there is no valid caller ID
-     * information for the caller, otherwise we'll assume that the URI can be shown.
-     *
-     * @param participant The conference participant.
-     * @return The number presentation.
-     */
-    private int getParticipantPresentation(ConferenceParticipant participant) {
-        Uri address = participant.getHandle();
-        if (address == null) {
-            return PhoneConstants.PRESENTATION_RESTRICTED;
-        }
 
-        String number = address.getSchemeSpecificPart();
-        // If no number, bail early and set restricted presentation.
-        if (TextUtils.isEmpty(number)) {
-            return PhoneConstants.PRESENTATION_RESTRICTED;
-        }
-        // Per RFC3261, the host name portion can also potentially include extra information:
-        // E.g. sip:anonymous1@anonymous.invalid;legid=1
-        // In this case, hostName will be anonymous.invalid and there is an extra parameter for
-        // legid=1.
-        // Parameters are optional, and the address (e.g. test@test.com) will always be the first
-        // part, with any parameters coming afterwards.
-        String hostParts[] = number.split("[;]");
-        String addressPart = hostParts[0];
-
-        // Get the number portion from the address part.
-        // This will typically be formatted similar to: 6505551212@test.com
-        String numberParts[] = addressPart.split("[@]");
-
-        // If we can't parse the host name out of the URI, then there is probably other data
-        // present, and is likely a valid SIP URI.
-        if (numberParts.length != 2) {
-            return PhoneConstants.PRESENTATION_ALLOWED;
-        }
-        String hostName = numberParts[1];
-
-        // If the hostname portion of the SIP URI is the invalid host string, presentation is
-        // restricted.
-        if (hostName.equals(ANONYMOUS_INVALID_HOST)) {
-            return PhoneConstants.PRESENTATION_RESTRICTED;
-        }
-
-        return PhoneConstants.PRESENTATION_ALLOWED;
-    }
 
     /**
      * Attempts to build a tel: style URI from a conference participant.
@@ -311,6 +260,10 @@
         sb.append(Log.pii(mParentConnection.getAddress()));
         sb.append(" state:");
         sb.append(Connection.stateToString(getState()));
+        sb.append(" connectTime:");
+        sb.append(getConnectTimeMillis());
+        sb.append(" connectElapsedTime:");
+        sb.append(getConnectElapsedTimeMillis());
         sb.append("]");
 
         return sb.toString();
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index a92dea7..8ef9565 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -249,6 +249,10 @@
                 resourceId = R.string.callFailed_userBusy;
                 break;
 
+            case android.telephony.DisconnectCause.CDMA_REORDER:
+                resourceId = R.string.callFailed_NetworkBusy;
+                break;
+
             case android.telephony.DisconnectCause.CONGESTION:
                 resourceId = R.string.callFailed_congestion;
                 break;
@@ -557,6 +561,10 @@
                 resourceId = R.string.callFailed_cdma_activation;
                 break;
 
+            case android.telephony.DisconnectCause.CDMA_REORDER:
+                resourceId = R.string.callFailed_NetworkBusy;
+                break;
+
             case android.telephony.DisconnectCause.FDN_BLOCKED:
                 resourceId = R.string.callFailed_fdn_only;
                 break;
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index d5af25b..cada504 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -33,7 +33,6 @@
 import android.telecom.VideoProfile;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
-import android.util.FeatureFlagUtils;
 import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -47,7 +46,6 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -542,6 +540,8 @@
     @Override
     public void onConnectionAdded(android.telecom.Connection connection) {
         // No-op
+        Log.d(this, "connection added: " + connection
+                + ", time: " + connection.getConnectTimeMillis());
     }
 
     @Override
@@ -884,7 +884,7 @@
             // Remove the participant from Telecom.  It'll get picked up in a future CEP update
             // again anyways.
             entry.setDisconnected(new DisconnectCause(DisconnectCause.CANCELED,
-                    "EMULATING_SINGLE_CALL"));
+                    DisconnectCause.REASON_EMULATING_SINGLE_CALL));
             entry.removeConnectionListener(mParticipantListener);
             mTelephonyConnectionService.removeConnection(entry);
             removeConnection(entry);
@@ -919,8 +919,13 @@
         ConferenceParticipantConnection connection = new ConferenceParticipantConnection(
                 parent.getOriginalConnection(), participant);
         connection.addConnectionListener(mParticipantListener);
-        connection.setConnectTimeMillis(parent.getConnectTimeMillis());
-
+        if (participant.getConnectTime() == 0) {
+            connection.setConnectTimeMillis(parent.getConnectTimeMillis());
+            connection.setConnectionStartElapsedRealTime(parent.getConnectElapsedTimeMillis());
+        } else {
+            connection.setConnectTimeMillis(participant.getConnectTime());
+            connection.setConnectionStartElapsedRealTime(participant.getConnectElapsedTime());
+        }
         Log.i(this, "createConferenceParticipantConnection: participant=%s, connection=%s",
                 participant, connection);
 
@@ -1083,6 +1088,7 @@
                 c.updateState();
                 // Copy the connect time from the conferenceHost
                 c.setConnectTimeMillis(mConferenceHost.getConnectTimeMillis());
+                c.setConnectionStartElapsedRealTime(mConferenceHost.getConnectElapsedTimeMillis());
                 mTelephonyConnectionService.addExistingConnection(phoneAccountHandle, c);
                 mTelephonyConnectionService.addConnectionToConferenceController(c);
             } // CDMA case not applicable for SRVCC
@@ -1164,8 +1170,7 @@
                 setStatusHints(new StatusHints(
                         context.getString(R.string.status_hint_label_wifi_call),
                         Icon.createWithResource(
-                                context.getResources(),
-                                R.drawable.ic_signal_wifi_4_bar_24dp),
+                                context, R.drawable.ic_signal_wifi_4_bar_24dp),
                         null /* extras */));
             }
         } else {
diff --git a/src/com/android/services/telephony/RadioOnHelper.java b/src/com/android/services/telephony/RadioOnHelper.java
index cd08289..288c72c 100644
--- a/src/com/android/services/telephony/RadioOnHelper.java
+++ b/src/com/android/services/telephony/RadioOnHelper.java
@@ -93,13 +93,12 @@
      * get an onServiceStateChanged() callback when the radio successfully comes up.
      */
     private void powerOnRadio() {
-        Log.d(this, "powerOnRadio().");
 
         // If airplane mode is on, we turn it off the same way that the Settings activity turns it
         // off.
         if (Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.AIRPLANE_MODE_ON, 0) > 0) {
-            Log.d(this, "==> Turning off airplane mode.");
+            Log.d(this, "==> Turning off airplane mode for emergency call.");
 
             // Change the system setting
             Settings.Global.putInt(mContext.getContentResolver(),
diff --git a/src/com/android/services/telephony/RadioOnStateListener.java b/src/com/android/services/telephony/RadioOnStateListener.java
index 91a7d77..729f6a9 100644
--- a/src/com/android/services/telephony/RadioOnStateListener.java
+++ b/src/com/android/services/telephony/RadioOnStateListener.java
@@ -46,16 +46,16 @@
     }
 
     // Number of times to retry the call, and time between retry attempts.
+    // not final for testing
     private static int MAX_NUM_RETRIES = 5;
+    // not final for testing
     private static long TIME_BETWEEN_RETRIES_MILLIS = 5000;  // msec
 
     // Handler message codes; see handleMessage()
-    @VisibleForTesting
-    public static final int MSG_START_SEQUENCE = 1;
+    private static final int MSG_START_SEQUENCE = 1;
     @VisibleForTesting
     public static final int MSG_SERVICE_STATE_CHANGED = 2;
-    @VisibleForTesting
-    public static final int MSG_RETRY_TIMEOUT = 3;
+    private static final int MSG_RETRY_TIMEOUT = 3;
 
     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
         @Override
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 37c5d7c..b29499f 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -46,6 +46,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
 import android.telephony.TelephonyManager;
+import android.telephony.ims.ImsException;
 import android.telephony.ims.ImsMmTelManager;
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -114,10 +115,10 @@
             }
 
             try {
-                mMmTelManager = ImsMmTelManager.createForSubscriptionId(mContext, getSubId());
+                mMmTelManager = ImsMmTelManager.createForSubscriptionId(getSubId());
             } catch (IllegalArgumentException e) {
                 Log.i(this, "Not registering MmTel capabilities listener because the subid '"
-                        + getSubId() + "' is invalid");
+                        + getSubId() + "' is invalid: " + e.getMessage());
                 return;
             }
 
@@ -151,9 +152,13 @@
             try {
                 mMmTelManager.registerMmTelCapabilityCallback(mContext.getMainExecutor(),
                         mMmtelCapabilityCallback);
-            } catch (IllegalStateException e) {
+            } catch (ImsException e) {
                 Log.w(this, "registerMmTelCapabilityCallback: registration failed, no ImsService"
-                        + " available.");
+                        + " available. Exception: " + e.getMessage());
+                return;
+            } catch (IllegalArgumentException e) {
+                Log.w(this, "registerMmTelCapabilityCallback: registration failed, invalid"
+                        + " subscription, Exception" + e.getMessage());
                 return;
             }
         }
@@ -262,7 +267,15 @@
                 capabilities |= PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS;
             }
 
-            mIsVideoCapable = mPhone.isVideoEnabled();
+            if (PhoneGlobals.getInstance().phoneMgr.isRttEnabled(subId)
+                    && isImsVoiceAvailable()) {
+                capabilities |= PhoneAccount.CAPABILITY_RTT;
+                mIsRttCapable = true;
+            } else {
+                mIsRttCapable = false;
+            }
+
+            mIsVideoCapable = mPhone.isVideoEnabled() && !mIsRttCapable;
             boolean isVideoEnabledByPlatform = ImsManager.getInstance(mPhone.getContext(),
                     mPhone.getPhoneId()).isVtEnabledByPlatform();
 
@@ -312,12 +325,6 @@
                 extras.putBoolean(PhoneAccount.EXTRA_PLAY_CALL_RECORDING_TONE, true);
             }
 
-            if (PhoneGlobals.getInstance().phoneMgr.isRttEnabled(subId)
-                    && isImsVoiceAvailable()) {
-                capabilities |= PhoneAccount.CAPABILITY_RTT;
-                mIsRttCapable = true;
-            }
-
             extras.putBoolean(PhoneAccount.EXTRA_SUPPORTS_VIDEO_CALLING_FALLBACK,
                     mContext.getResources()
                             .getBoolean(R.bool.config_support_video_calling_fallback));
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index d2ba8f1..7c09320 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -2107,8 +2107,7 @@
             setStatusHints(new StatusHints(
                     context.getString(labelId),
                     Icon.createWithResource(
-                            context.getResources(),
-                            R.drawable.ic_signal_wifi_4_bar_24dp),
+                            context, R.drawable.ic_signal_wifi_4_bar_24dp),
                     null /* extras */));
         } else {
             setStatusHints(null);
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index ab9e211..6d7c1f0 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -40,8 +40,8 @@
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.emergency.EmergencyNumber;
 import android.text.TextUtils;
-import android.util.FeatureFlagUtils;
 import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -68,9 +68,12 @@
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.Queue;
 import java.util.regex.Pattern;
 
+import javax.annotation.Nullable;
+
 /**
  * Service for making GSM and CDMA connections.
  */
@@ -206,26 +209,47 @@
     };
 
     // TelephonyManager Proxy interface for testing
+    @VisibleForTesting
     public interface TelephonyManagerProxy {
         int getPhoneCount();
         boolean hasIccCard(int slotId);
+        boolean isCurrentEmergencyNumber(String number);
+        Map<Integer, List<EmergencyNumber>> getCurrentEmergencyNumberList();
     }
 
-    private TelephonyManagerProxy mTelephonyManagerProxy = new TelephonyManagerProxy() {
-        private final TelephonyManager sTelephonyManager = TelephonyManager.getDefault();
+    private TelephonyManagerProxy mTelephonyManagerProxy;
+
+    private class TelephonyManagerProxyImpl implements TelephonyManagerProxy {
+        private final TelephonyManager mTelephonyManager;
+
+
+        TelephonyManagerProxyImpl(Context context) {
+            mTelephonyManager = new TelephonyManager(context);
+        }
 
         @Override
         public int getPhoneCount() {
-            return sTelephonyManager.getPhoneCount();
+            return mTelephonyManager.getPhoneCount();
         }
 
         @Override
         public boolean hasIccCard(int slotId) {
-            return sTelephonyManager.hasIccCard(slotId);
+            return mTelephonyManager.hasIccCard(slotId);
         }
-    };
+
+        @Override
+        public boolean isCurrentEmergencyNumber(String number) {
+            return mTelephonyManager.isCurrentEmergencyNumber(number);
+        }
+
+        @Override
+        public Map<Integer, List<EmergencyNumber>> getCurrentEmergencyNumberList() {
+            return mTelephonyManager.getCurrentEmergencyNumberList();
+        }
+    }
 
     //PhoneFactory proxy interface for testing
+    @VisibleForTesting
     public interface PhoneFactoryProxy {
         Phone getPhone(int index);
         Phone getDefaultPhone();
@@ -284,6 +308,7 @@
     public void onCreate() {
         super.onCreate();
         Log.initLogging(this);
+        setTelephonyManagerProxy(new TelephonyManagerProxyImpl(getApplicationContext()));
         mExpectedComponentName = new ComponentName(this, this.getClass());
         mEmergencyTonePlayer = new EmergencyTonePlayer(this);
         TelecomAccountRegistry.getInstance(this).setTelephonyConnectionService(this);
@@ -321,8 +346,8 @@
         if (PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
             // TODO: We don't check for SecurityException here (requires
             // CALL_PRIVILEGED permission).
-            final Phone phone = getPhoneForAccount(request.getAccountHandle(), false,
-                    handle.getSchemeSpecificPart());
+            final Phone phone = getPhoneForAccount(request.getAccountHandle(),
+                    false /* isEmergencyCall */, null /* not an emergency call */);
             if (phone == null) {
                 Log.d(this, "onCreateOutgoingConnection, phone is null");
                 return Connection.createFailedConnection(
@@ -360,8 +385,8 @@
                                 "Unable to parse number"));
             }
 
-            final Phone phone = getPhoneForAccount(request.getAccountHandle(), false,
-                    handle.getSchemeSpecificPart());
+            final Phone phone = getPhoneForAccount(request.getAccountHandle(),
+                    false /* isEmergencyCall*/, null /* not an emergency call */);
             if (phone != null && CDMA_ACTIVATION_CODE_REGEX_PATTERN.matcher(number).matches()) {
                 // Obtain the configuration for the outgoing phone's SIM. If the outgoing number
                 // matches the *228 regex pattern, fail the call. This number is used for OTASP, and
@@ -385,9 +410,13 @@
             }
         }
 
+        final boolean isEmergencyNumber = mTelephonyManagerProxy.isCurrentEmergencyNumber(number);
+        // Find out if this is a test emergency number
+        final boolean isTestEmergencyNumber = isEmergencyNumberTestNumber(number);
+
         // Convert into emergency number if necessary
         // This is required in some regions (e.g. Taiwan).
-        if (!PhoneNumberUtils.isLocalEmergencyNumber(this, number)) {
+        if (isEmergencyNumber) {
             final Phone phone = getPhoneForAccount(request.getAccountHandle(), false,
                     handle.getSchemeSpecificPart());
             // We only do the conversion if the phone is not in service. The un-converted
@@ -406,9 +435,6 @@
         }
         final String numberToDial = number;
 
-        final boolean isEmergencyNumber =
-                PhoneNumberUtils.isLocalEmergencyNumber(this, numberToDial);
-
 
         final boolean isAirplaneModeOn = Settings.Global.getInt(getContentResolver(),
                 Settings.Global.AIRPLANE_MODE_ON, 0) > 0;
@@ -435,7 +461,12 @@
 
                 @Override
                 public boolean isOkToCall(Phone phone, int serviceState) {
-                    if (isEmergencyNumber) {
+                    // HAL 1.4 introduced a new variant of dial for emergency calls, which includes
+                    // an isTesting parameter. For HAL 1.4+, do not wait for IN_SERVICE, this will
+                    // be handled at the RIL/vendor level by emergencyDial(...).
+                    boolean waitForInServiceToDialEmergency = isTestEmergencyNumber
+                            && phone.getHalVersion().less(RIL.RADIO_HAL_VERSION_1_4);
+                    if (isEmergencyNumber && !waitForInServiceToDialEmergency) {
                         // We currently only look to make sure that the radio is on before dialing.
                         // We should be able to make emergency calls at any time after the radio has
                         // been powered on and isn't in the UNAVAILABLE state, even if it is
@@ -443,9 +474,10 @@
                         return (phone.getState() == PhoneConstants.State.OFFHOOK)
                             || phone.getServiceState().getState() != ServiceState.STATE_POWER_OFF;
                     } else {
-                        // It is not an emergency number, so wait until we are in service and ready
-                        // to make calls. This can happen when we power down the radio on bluetooth
-                        // to save power on watches.
+                        // Wait until we are in service and ready to make calls. This can happen
+                        // when we power down the radio on bluetooth to save power on watches or if
+                        // it is a test emergency number and we have to wait for the device to move
+                        // IN_SERVICE before the call can take place over normal routing.
                         return (phone.getState() == PhoneConstants.State.OFFHOOK)
                             || serviceState == ServiceState.STATE_IN_SERVICE;
                     }
@@ -468,7 +500,8 @@
 
             // Get the right phone object from the account data passed in.
             final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber,
-                    handle.getSchemeSpecificPart());
+                    /* Note: when not an emergency, handle can be null for unknown callers */
+                    handle == null ? null : handle.getSchemeSpecificPart());
             Connection resultConnection = getTelephonyConnection(request, numberToDial,
                     isEmergencyNumber, handle, phone);
             // If there was a failure, the resulting connection will not be a TelephonyConnection,
@@ -484,6 +517,24 @@
         }
     }
 
+    private boolean isEmergencyNumberTestNumber(String number) {
+        Map<Integer, List<EmergencyNumber>> list =
+                mTelephonyManagerProxy.getCurrentEmergencyNumberList();
+        // Do not worry about which subscription the test emergency call is on yet, only detect that
+        // it is an emergency.
+        for (Integer sub : list.keySet()) {
+            for (EmergencyNumber eNumber : list.get(sub)) {
+                if (number.equals(eNumber.getNumber())
+                        && eNumber.isFromSources(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST)) {
+                    Log.i(this, "isEmergencyNumberTestNumber: " + number + " has been detected as "
+                            + "a test emergency number.,");
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     /**
      * Whether the cellular radio is power off because the device is on Bluetooth.
      */
@@ -512,8 +563,9 @@
         if (isRadioReady) {
             // Get the right phone object since the radio has been turned on
             // successfully.
-            final Phone phone = getPhoneForAccount(request.getAccountHandle(),
-                    isEmergencyNumber, handle.getSchemeSpecificPart());
+            final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber,
+                    /* Note: when not an emergency, handle can be null for unknown callers */
+                    handle == null ? null : handle.getSchemeSpecificPart());
             // If the PhoneType of the Phone being used is different than the Default Phone, then we
             // need create a new Connection using that PhoneType and replace it in Telecom.
             if (phone.getPhoneType() != originalPhoneType) {
@@ -732,7 +784,8 @@
             isEmergency = true;
         }
         Phone phone = getPhoneForAccount(accountHandle, isEmergency,
-                request.getAddress().getSchemeSpecificPart());
+                /* Note: when not an emergency, handle can be null for unknown callers */
+                request.getAddress() == null ? null : request.getAddress().getSchemeSpecificPart());
         if (phone == null) {
             return Connection.createFailedConnection(
                     DisconnectCauseUtil.toTelecomDisconnectCause(
@@ -844,7 +897,8 @@
             isEmergency = true;
         }
         Phone phone = getPhoneForAccount(accountHandle, isEmergency,
-                request.getAddress().getSchemeSpecificPart());
+                /* Note: when not an emergency, handle can be null for unknown callers */
+                request.getAddress() == null ? null : request.getAddress().getSchemeSpecificPart());
         if (phone == null) {
             return Connection.createFailedConnection(
                     DisconnectCauseUtil.toTelecomDisconnectCause(
@@ -1234,8 +1288,17 @@
         return false;
     }
 
+    /**
+     * Determines which {@link Phone} will be used to place the call.
+     * @param accountHandle The {@link PhoneAccountHandle} which was sent from Telecom to place the
+     *      call on.
+     * @param isEmergency {@code true} if this is an emergency call, {@code false} otherwise.
+     * @param emergencyNumberAddress When {@code isEmergency} is {@code true}, will be the phone
+     *      of the emergency call.  Otherwise, this can be {@code null}  .
+     * @return
+     */
     private Phone getPhoneForAccount(PhoneAccountHandle accountHandle, boolean isEmergency,
-                                     String emergencyNumberAddress) {
+                                     @Nullable String emergencyNumberAddress) {
         Phone chosenPhone = null;
         int subId = PhoneUtils.getSubIdForPhoneAccountHandle(accountHandle);
         if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
diff --git a/testapps/ImsTestService/AndroidManifest.xml b/testapps/ImsTestService/AndroidManifest.xml
index 7662a42..eea54b8 100644
--- a/testapps/ImsTestService/AndroidManifest.xml
+++ b/testapps/ImsTestService/AndroidManifest.xml
@@ -19,6 +19,9 @@
           coreApp="true"
           package="com.android.phone.testapps.imstestapp">
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+    <!--Beware, declaring the below permission will cause the device to not boot unless you add
+        this app and permission to frameworks/base/data/etc/privapp-permissions-platform.xml-->
+    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
     <application
         android:label="ImsTestService"
         android:directBootAware="true">
diff --git a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsCallingActivity.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsCallingActivity.java
index fea2bf8..0ff6cc1 100644
--- a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsCallingActivity.java
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsCallingActivity.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.os.Bundle;
 import android.telephony.SubscriptionManager;
+import android.telephony.ims.ImsException;
 import android.telephony.ims.ImsMmTelManager;
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -162,12 +163,12 @@
         mListView = (ListView) findViewById(R.id.cap_cb_list);
         mListView.setAdapter(mCapabiltyEventAdapter);
         try {
-            mImsManager = ImsMmTelManager.createForSubscriptionId(this,
+            mImsManager = ImsMmTelManager.createForSubscriptionId(
                     SubscriptionManager.getDefaultVoiceSubscriptionId());
             Log.i("ImsCallingActivity", "onResume");
             mImsManager.registerMmTelCapabilityCallback(getMainExecutor(), mCapabilityCallback);
-        } catch (IllegalArgumentException e) {
-            Log.w("ImsCallingActivity", "illegal subscription ID.");
+        } catch (IllegalArgumentException | ImsException e) {
+            Log.w("ImsCallingActivity", "Exception: " + e.getMessage());
         }
     }
 
diff --git a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java
index 3317ff1..84ec7b9 100644
--- a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java
@@ -19,7 +19,9 @@
 import android.app.Activity;
 import android.content.Context;
 import android.os.Bundle;
+import android.telephony.AccessNetworkConstants;
 import android.telephony.SubscriptionManager;
+import android.telephony.ims.ImsException;
 import android.telephony.ims.ImsMmTelManager;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -149,8 +151,8 @@
     private static final Map<Integer, String> REG_TECH_STRING = new ArrayMap<>(2);
     static {
         REG_TECH_STRING.put(ImsRegistrationImplBase.REGISTRATION_TECH_NONE, "NONE");
-        REG_TECH_STRING.put(ImsRegistrationImplBase.REGISTRATION_TECH_LTE, "LTE");
-        REG_TECH_STRING.put(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN, "IWLAN");
+        REG_TECH_STRING.put(AccessNetworkConstants.TransportType.WWAN, "WWAN");
+        REG_TECH_STRING.put(AccessNetworkConstants.TransportType.WLAN, "WLAN");
     }
 
 
@@ -177,10 +179,10 @@
         mListView = (ListView) findViewById(R.id.reg_cb_list);
         mListView.setAdapter(mRegItemAdapter);
         try {
-            mImsManager = ImsMmTelManager.createForSubscriptionId(this,
+            mImsManager = ImsMmTelManager.createForSubscriptionId(
                     SubscriptionManager.getDefaultVoiceSubscriptionId());
             mImsManager.registerImsRegistrationCallback(getMainExecutor(), mRegistrationCallback);
-        } catch (IllegalArgumentException e) {
+        } catch (IllegalArgumentException | ImsException e) {
             Log.w("ImsCallingActivity", "illegal subscription ID.");
         }
 
diff --git a/testapps/TelephonyManagerTestApp/res/layout/calling_method.xml b/testapps/TelephonyManagerTestApp/res/layout/calling_method.xml
index 5145a63..6dd8bc2 100644
--- a/testapps/TelephonyManagerTestApp/res/layout/calling_method.xml
+++ b/testapps/TelephonyManagerTestApp/res/layout/calling_method.xml
@@ -73,7 +73,6 @@
         android:layout_height="50dip">
     </Button>
 
-
     <ScrollView
         android:id="@+id/return_value_wrapper"
         android:layout_width="fill_parent"
diff --git a/testapps/TelephonyRegistryTestApp/AndroidManifest.xml b/testapps/TelephonyRegistryTestApp/AndroidManifest.xml
index 708ea66..550c9f0 100644
--- a/testapps/TelephonyRegistryTestApp/AndroidManifest.xml
+++ b/testapps/TelephonyRegistryTestApp/AndroidManifest.xml
@@ -16,9 +16,13 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.phone.testapps.telephonyregistry">
+    <uses-sdk android:minSdkVersion="25"
+          android:targetSdkVersion="25"/>
+
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
     <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+    <uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE"/>
     <application android:label="TelephonyRegistryTestApp">
         <activity
             android:name=".TelephonyRegistryTestApp"
diff --git a/testapps/TelephonyRegistryTestApp/src/com/android/phone/testapps/telephonyregistry/TelephonyRegistryTestApp.java b/testapps/TelephonyRegistryTestApp/src/com/android/phone/testapps/telephonyregistry/TelephonyRegistryTestApp.java
index 74cafcd..96f8bf7 100644
--- a/testapps/TelephonyRegistryTestApp/src/com/android/phone/testapps/telephonyregistry/TelephonyRegistryTestApp.java
+++ b/testapps/TelephonyRegistryTestApp/src/com/android/phone/testapps/telephonyregistry/TelephonyRegistryTestApp.java
@@ -24,6 +24,7 @@
 import android.telephony.CellInfo;
 import android.telephony.CellLocation;
 import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.util.SparseArray;
 import android.widget.Button;
@@ -76,6 +77,11 @@
             notify("onSrvccStateChanged", srvccState);
         }
 
+        @Override
+        public void onServiceStateChanged(ServiceState state) {
+            notify("onServiceStateChanged", state);
+        }
+
         private void notify(String method, Object data) {
             Notification.Builder builder = new Notification.Builder(TelephonyRegistryTestApp.this,
                     NOTIFICATION_CHANNEL);
diff --git a/tests/src/com/android/phone/LocationAccessPolicyTest.java b/tests/src/com/android/phone/LocationAccessPolicyTest.java
new file mode 100644
index 0000000..9938bf2
--- /dev/null
+++ b/tests/src/com/android/phone/LocationAccessPolicyTest.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.location.LocationManager;
+import android.os.Build;
+import android.os.UserHandle;
+import android.telephony.LocationAccessPolicy;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+@RunWith(Parameterized.class)
+public class LocationAccessPolicyTest {
+    private static class Scenario {
+        static class Builder {
+            private int mAppSdkLevel;
+            private boolean mAppHasFineManifest = false;
+            private boolean mAppHasCoarseManifest = false;
+            private int mFineAppOp = AppOpsManager.MODE_IGNORED;
+            private int mCoarseAppOp = AppOpsManager.MODE_IGNORED;
+            private boolean mIsDynamicLocationEnabled;
+            private LocationAccessPolicy.LocationPermissionQuery mQuery;
+            private LocationAccessPolicy.LocationPermissionResult mExpectedResult;
+            private String mName;
+
+            public Builder setAppSdkLevel(int appSdkLevel) {
+                mAppSdkLevel = appSdkLevel;
+                return this;
+            }
+
+            public Builder setAppHasFineManifest(boolean appHasFineManifest) {
+                mAppHasFineManifest = appHasFineManifest;
+                return this;
+            }
+
+            public Builder setAppHasCoarseManifest(
+                    boolean appHasCoarseManifest) {
+                mAppHasCoarseManifest = appHasCoarseManifest;
+                return this;
+            }
+
+            public Builder setFineAppOp(int fineAppOp) {
+                mFineAppOp = fineAppOp;
+                return this;
+            }
+
+            public Builder setCoarseAppOp(int coarseAppOp) {
+                mCoarseAppOp = coarseAppOp;
+                return this;
+            }
+
+            public Builder setIsDynamicLocationEnabled(
+                    boolean isDynamicLocationEnabled) {
+                mIsDynamicLocationEnabled = isDynamicLocationEnabled;
+                return this;
+            }
+
+            public Builder setQuery(
+                    LocationAccessPolicy.LocationPermissionQuery query) {
+                mQuery = query;
+                return this;
+            }
+
+            public Builder setExpectedResult(
+                    LocationAccessPolicy.LocationPermissionResult expectedResult) {
+                mExpectedResult = expectedResult;
+                return this;
+            }
+
+            public Builder setName(String name) {
+                mName = name;
+                return this;
+            }
+
+            public Scenario build() {
+                return new Scenario(mAppSdkLevel, mAppHasFineManifest, mAppHasCoarseManifest,
+                        mFineAppOp, mCoarseAppOp, mIsDynamicLocationEnabled, mQuery,
+                        mExpectedResult, mName);
+            }
+        }
+        int appSdkLevel;
+        boolean appHasFineManifest;
+        boolean appHasCoarseManifest;
+        int fineAppOp;
+        int coarseAppOp;
+        boolean isDynamicLocationEnabled;
+        LocationAccessPolicy.LocationPermissionQuery query;
+        LocationAccessPolicy.LocationPermissionResult expectedResult;
+        String name;
+
+        private Scenario(int appSdkLevel, boolean appHasFineManifest, boolean appHasCoarseManifest,
+                int fineAppOp, int coarseAppOp,
+                boolean isDynamicLocationEnabled,
+                LocationAccessPolicy.LocationPermissionQuery query,
+                LocationAccessPolicy.LocationPermissionResult expectedResult,
+                String name) {
+            this.appSdkLevel = appSdkLevel;
+            this.appHasFineManifest = appHasFineManifest;
+            this.appHasCoarseManifest = appHasFineManifest || appHasCoarseManifest;
+            this.fineAppOp = fineAppOp;
+            this.coarseAppOp = coarseAppOp == AppOpsManager.MODE_ALLOWED ? coarseAppOp : fineAppOp;
+            this.isDynamicLocationEnabled = isDynamicLocationEnabled;
+            this.query = query;
+            this.expectedResult = expectedResult;
+            this.name = name;
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+    }
+
+    @Mock Context mContext;
+    @Mock AppOpsManager mAppOpsManager;
+    @Mock LocationManager mLocationManager;
+    @Mock PackageManager mPackageManager;
+    Scenario mScenario;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mockContextSystemService(AppOpsManager.class, mAppOpsManager);
+        mockContextSystemService(LocationManager.class, mLocationManager);
+        mockContextSystemService(PackageManager.class, mPackageManager);
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+    }
+
+    private <T> void mockContextSystemService(Class<T> clazz , T obj) {
+        when(mContext.getSystemServiceName(eq(clazz))).thenReturn(clazz.getSimpleName());
+        when(mContext.getSystemService(clazz.getSimpleName())).thenReturn(obj);
+    }
+
+    public LocationAccessPolicyTest(Scenario scenario) {
+        mScenario = scenario;
+    }
+
+
+    @Test
+    public void test() {
+        setupScenario(mScenario);
+        assertEquals(mScenario.expectedResult,
+                LocationAccessPolicy.checkLocationPermission(mContext, mScenario.query));
+    }
+
+    private void setupScenario(Scenario s) {
+        when(mContext.checkPermission(eq(Manifest.permission.ACCESS_FINE_LOCATION),
+                anyInt(), anyInt())).thenReturn(s.appHasFineManifest
+                ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED);
+
+        when(mContext.checkPermission(eq(Manifest.permission.ACCESS_COARSE_LOCATION),
+                anyInt(), anyInt())).thenReturn(s.appHasCoarseManifest
+                ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED);
+
+        when(mAppOpsManager.noteOpNoThrow(eq(AppOpsManager.OP_FINE_LOCATION),
+                anyInt(), anyString()))
+                .thenReturn(s.fineAppOp);
+        when(mAppOpsManager.noteOpNoThrow(eq(AppOpsManager.OP_COARSE_LOCATION),
+                anyInt(), anyString()))
+                .thenReturn(s.coarseAppOp);
+
+        if (s.isDynamicLocationEnabled) {
+            when(mLocationManager.isLocationEnabledForUser(any(UserHandle.class))).thenReturn(true);
+            when(mContext.checkPermission(eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL),
+                    anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED);
+        } else {
+            when(mLocationManager.isLocationEnabledForUser(any(UserHandle.class)))
+                    .thenReturn(false);
+            when(mContext.checkPermission(eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL),
+                    anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED);
+        }
+
+        ApplicationInfo fakeAppInfo = new ApplicationInfo();
+        fakeAppInfo.targetSdkVersion = s.appSdkLevel;
+
+        try {
+            when(mPackageManager.getApplicationInfo(anyString(), anyInt()))
+                    .thenReturn(fakeAppInfo);
+        } catch (Exception e) {
+            // this is a formality
+        }
+    }
+
+    private static LocationAccessPolicy.LocationPermissionQuery.Builder getDefaultQueryBuilder() {
+        return new LocationAccessPolicy.LocationPermissionQuery.Builder()
+                .setMethod("test")
+                .setCallingPackage("com.android.test")
+                .setCallingPid(10001)
+                .setCallingUid(10001);
+    }
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Collection<Scenario> getScenarios() {
+        List<Scenario> scenarios = new ArrayList<>();
+        scenarios.add(new Scenario.Builder()
+                .setName("System location is off")
+                .setAppHasFineManifest(true)
+                .setFineAppOp(AppOpsManager.MODE_ALLOWED)
+                .setAppSdkLevel(Build.VERSION_CODES.P)
+                .setIsDynamicLocationEnabled(false)
+                .setQuery(getDefaultQueryBuilder()
+                        .setMinSdkVersionForFine(Build.VERSION_CODES.N)
+                        .setMinSdkVersionForCoarse(Build.VERSION_CODES.N).build())
+                .setExpectedResult(LocationAccessPolicy.LocationPermissionResult.DENIED_SOFT)
+                .build());
+
+        scenarios.add(new Scenario.Builder()
+                .setName("App on latest SDK level has all proper permissions for fine")
+                .setAppHasFineManifest(true)
+                .setFineAppOp(AppOpsManager.MODE_ALLOWED)
+                .setAppSdkLevel(Build.VERSION_CODES.P)
+                .setIsDynamicLocationEnabled(true)
+                .setQuery(getDefaultQueryBuilder()
+                        .setMinSdkVersionForFine(Build.VERSION_CODES.N)
+                        .setMinSdkVersionForCoarse(Build.VERSION_CODES.N).build())
+                .setExpectedResult(LocationAccessPolicy.LocationPermissionResult.ALLOWED)
+                .build());
+
+        scenarios.add(new Scenario.Builder()
+                .setName("App on older SDK level missing permissions for fine but has coarse")
+                .setAppHasCoarseManifest(true)
+                .setCoarseAppOp(AppOpsManager.MODE_ALLOWED)
+                .setAppSdkLevel(Build.VERSION_CODES.JELLY_BEAN)
+                .setIsDynamicLocationEnabled(true)
+                .setQuery(getDefaultQueryBuilder()
+                        .setMinSdkVersionForFine(Build.VERSION_CODES.M)
+                        .setMinSdkVersionForCoarse(Build.VERSION_CODES.JELLY_BEAN).build())
+                .setExpectedResult(LocationAccessPolicy.LocationPermissionResult.ALLOWED)
+                .build());
+
+        scenarios.add(new Scenario.Builder()
+                .setName("App on latest SDK level missing fine app ops permission")
+                .setAppHasFineManifest(true)
+                .setFineAppOp(AppOpsManager.MODE_ERRORED)
+                .setAppSdkLevel(Build.VERSION_CODES.P)
+                .setIsDynamicLocationEnabled(true)
+                .setQuery(getDefaultQueryBuilder()
+                        .setMinSdkVersionForFine(Build.VERSION_CODES.N)
+                        .setMinSdkVersionForCoarse(Build.VERSION_CODES.N).build())
+                .setExpectedResult(LocationAccessPolicy.LocationPermissionResult.DENIED_HARD)
+                .build());
+
+        scenarios.add(new Scenario.Builder()
+                .setName("App has coarse permission but fine permission isn't being enforced yet")
+                .setAppHasCoarseManifest(true)
+                .setCoarseAppOp(AppOpsManager.MODE_ALLOWED)
+                .setAppSdkLevel(LocationAccessPolicy.MAX_SDK_FOR_ANY_ENFORCEMENT + 1)
+                .setIsDynamicLocationEnabled(true)
+                .setQuery(getDefaultQueryBuilder()
+                        .setMinSdkVersionForFine(
+                                LocationAccessPolicy.MAX_SDK_FOR_ANY_ENFORCEMENT + 1)
+                        .setMinSdkVersionForCoarse(Build.VERSION_CODES.N).build())
+                .setExpectedResult(LocationAccessPolicy.LocationPermissionResult.ALLOWED)
+                .build());
+
+        scenarios.add(new Scenario.Builder()
+                .setName("App on latest SDK level has coarse but missing fine when fine is req.")
+                .setAppHasCoarseManifest(true)
+                .setCoarseAppOp(AppOpsManager.MODE_ALLOWED)
+                .setAppSdkLevel(Build.VERSION_CODES.P)
+                .setIsDynamicLocationEnabled(true)
+                .setQuery(getDefaultQueryBuilder()
+                        .setMinSdkVersionForFine(Build.VERSION_CODES.P)
+                        .setMinSdkVersionForCoarse(Build.VERSION_CODES.N).build())
+                .setExpectedResult(LocationAccessPolicy.LocationPermissionResult.DENIED_HARD)
+                .build());
+
+        scenarios.add(new Scenario.Builder()
+                .setName("App on latest SDK level has MODE_IGNORED for app ops on fine")
+                .setAppHasCoarseManifest(true)
+                .setCoarseAppOp(AppOpsManager.MODE_ALLOWED)
+                .setFineAppOp(AppOpsManager.MODE_IGNORED)
+                .setAppSdkLevel(Build.VERSION_CODES.P)
+                .setIsDynamicLocationEnabled(true)
+                .setQuery(getDefaultQueryBuilder()
+                        .setMinSdkVersionForFine(Build.VERSION_CODES.P)
+                        .setMinSdkVersionForCoarse(Build.VERSION_CODES.O).build())
+                .setExpectedResult(LocationAccessPolicy.LocationPermissionResult.DENIED_HARD)
+                .build());
+
+        scenarios.add(new Scenario.Builder()
+                .setName("App has no permissions but it's sdk level grandfathers it in")
+                .setAppSdkLevel(Build.VERSION_CODES.N)
+                .setIsDynamicLocationEnabled(true)
+                .setQuery(getDefaultQueryBuilder()
+                        .setMinSdkVersionForFine(Build.VERSION_CODES.Q)
+                        .setMinSdkVersionForCoarse(Build.VERSION_CODES.O).build())
+                .setExpectedResult(LocationAccessPolicy.LocationPermissionResult.ALLOWED)
+                .build());
+
+        scenarios.add(new Scenario.Builder()
+                .setName("App on latest SDK level has proper permissions for coarse")
+                .setAppHasCoarseManifest(true)
+                .setCoarseAppOp(AppOpsManager.MODE_ALLOWED)
+                .setAppSdkLevel(Build.VERSION_CODES.P)
+                .setIsDynamicLocationEnabled(true)
+                .setQuery(getDefaultQueryBuilder()
+                        .setMinSdkVersionForCoarse(Build.VERSION_CODES.P).build())
+                .setExpectedResult(LocationAccessPolicy.LocationPermissionResult.ALLOWED)
+                .build());
+        return scenarios;
+    }
+}
diff --git a/tests/src/com/android/phone/ecc/EccDataTest.java b/tests/src/com/android/phone/ecc/EccDataTest.java
new file mode 100644
index 0000000..8f4abc5
--- /dev/null
+++ b/tests/src/com/android/phone/ecc/EccDataTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 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.ecc;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.TelephonyTestBase;
+import com.android.phone.ecc.nano.ProtobufEccData;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashSet;
+import java.util.zip.GZIPInputStream;
+
+/**
+ * Unit tests for eccdata.
+ */
+@RunWith(AndroidJUnit4.class)
+public class EccDataTest extends TelephonyTestBase {
+    @Test
+    public void testEccDataContent() throws IOException {
+        InputStream eccData = new GZIPInputStream(new BufferedInputStream(
+                InstrumentationRegistry.getTargetContext().getAssets().open("eccdata")));
+        ProtobufEccData.AllInfo allEccMessages = ProtobufEccData.AllInfo.parseFrom(
+                readInputStreamToByteArray(eccData));
+        eccData.close();
+
+        HashSet loadedIsos = new HashSet(300);
+        HashSet loadedNumbers = new HashSet(5);
+
+        for (ProtobufEccData.CountryInfo countryInfo : allEccMessages.countries) {
+            assertThat(countryInfo.isoCode).isNotEmpty();
+            assertThat(countryInfo.isoCode).isEqualTo(countryInfo.isoCode.toUpperCase().trim());
+            assertThat(loadedIsos.contains(countryInfo.isoCode)).isFalse();
+            loadedIsos.add(countryInfo.isoCode);
+
+            loadedNumbers.clear();
+            for (ProtobufEccData.EccInfo eccInfo : countryInfo.eccs) {
+                assertThat(eccInfo.phoneNumber).isNotEmpty();
+                assertThat(eccInfo.phoneNumber).isEqualTo(eccInfo.phoneNumber.trim());
+                assertThat(loadedNumbers.contains(eccInfo.phoneNumber)).isFalse();
+                assertThat(eccInfo.types).isNotEmpty();
+                loadedNumbers.add(eccInfo.phoneNumber);
+            }
+        }
+    }
+
+    /**
+     * Util function to convert inputStream to byte array before parsing proto data.
+     */
+    private static byte[] readInputStreamToByteArray(InputStream inputStream) throws IOException {
+        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+        int nRead;
+        byte[] data = new byte[16 * 1024]; // Read 16k chunks
+        while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
+            buffer.write(data, 0, nRead);
+        }
+        buffer.flush();
+        return buffer.toByteArray();
+    }
+}
diff --git a/tests/src/com/android/phone/ecc/IsoToEccProtobufRepositoryTest.java b/tests/src/com/android/phone/ecc/IsoToEccProtobufRepositoryTest.java
deleted file mode 100644
index f6e5ba2..0000000
--- a/tests/src/com/android/phone/ecc/IsoToEccProtobufRepositoryTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2018 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.ecc;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.util.Log;
-
-import com.android.TelephonyTestBase;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.HashSet;
-import java.util.Map;
-
-/**
- * Unit tests for IsoToEccProtobufRepository.
- */
-
-@RunWith(AndroidJUnit4.class)
-public class IsoToEccProtobufRepositoryTest extends TelephonyTestBase {
-    private static final String LOG_TAG = "IsoToEccProtobufRepositoryTest";
-
-    @Test
-    public void testEccDataContent() {
-        IsoToEccProtobufRepository repository = IsoToEccProtobufRepository.getInstance();
-        repository.loadMappingTable(InstrumentationRegistry.getTargetContext());
-        Map<String, CountryEccInfo> eccTable = repository.getEccTable();
-        HashSet loadedIsos = new HashSet(300);
-        HashSet loadedNumbers = new HashSet(5);
-
-        assertThat(eccTable).isNotEmpty();
-        for (Map.Entry<String, CountryEccInfo> entry : eccTable.entrySet()) {
-            String countryIso = entry.getKey();
-            CountryEccInfo countryEccInfo = entry.getValue();
-            EccInfo[] eccInfoList = countryEccInfo.getEccInfoList();
-            if (eccInfoList.length > 0) {
-                Log.i(LOG_TAG, "Verifying country " + countryIso + " with "
-                        + eccInfoList.length + " ecc(s)");
-            } else {
-                Log.w(LOG_TAG, "Verifying country " + countryIso + " with no ecc");
-            }
-
-            assertThat(countryIso).isNotEmpty();
-            assertThat(countryIso).isEqualTo(countryIso.toUpperCase().trim());
-            assertThat(loadedIsos.contains(countryIso)).isFalse();
-            loadedIsos.add(countryIso);
-
-            assertThat(countryEccInfo.getFallbackEcc()).isNotEmpty();
-
-            if (eccInfoList.length != 0) {
-                loadedNumbers.clear();
-                for (EccInfo eccInfo : eccInfoList) {
-                    String eccNumber = eccInfo.getNumber();
-                    assertThat(eccNumber).isNotEmpty();
-                    assertThat(eccNumber).isEqualTo(eccNumber.trim());
-                    assertThat(eccInfo.getTypes()).isNotEmpty();
-                    assertThat(loadedNumbers.contains(eccNumber)).isFalse();
-                    loadedNumbers.add(eccNumber);
-                }
-            }
-        }
-    }
-}
diff --git a/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java b/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
index fb214cc..d9de2e8 100644
--- a/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
+++ b/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
@@ -16,17 +16,25 @@
 
 package com.android.services.telephony;
 
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 import android.os.AsyncResult;
 import android.os.Handler;
-import android.telephony.ServiceState;
 import android.support.test.runner.AndroidJUnit4;
-import android.support.test.filters.FlakyTest;
+import android.telephony.ServiceState;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.TelephonyTestBase;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.ServiceStateTracker;
 
 import org.junit.After;
 import org.junit.Before;
@@ -34,16 +42,6 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Matchers.isNull;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.when;
-
 /**
  * Tests the RadioOnStateListener, which listens to one Phone and waits until its service
  * state changes to accepting emergency calls or in service. If it can not find a tower to camp onto
@@ -52,21 +50,26 @@
 @RunWith(AndroidJUnit4.class)
 public class RadioOnStateListenerTest extends TelephonyTestBase {
 
-    private static final long TIMEOUT_MS = 100;
+    private static final long TIMEOUT_MS = 1000;
 
     @Mock Phone mMockPhone;
     @Mock RadioOnStateListener.Callback mCallback;
     RadioOnStateListener mListener;
 
+    @Override
     @Before
     public void setUp() throws Exception {
         super.setUp();
         mListener = new RadioOnStateListener();
     }
 
+    @Override
     @After
     public void tearDown() throws Exception {
+        // Wait for the queue to clear...
+        waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS /*ms timeout*/);
         mListener.getHandler().removeCallbacksAndMessages(null);
+        mListener = null;
         super.tearDown();
     }
 
@@ -86,8 +89,9 @@
     }
 
     /**
-     * {@link RadioOnStateListener.Callback#isOkToCall(int)} returns true, so we are expecting
-     * {@link RadioOnStateListener.Callback#onComplete(boolean)} to return true.
+     *  {@link RadioOnStateListener.Callback#isOkToCall(Phone, int)} returns true, so we are
+     *  expecting {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} to
+     *  return true.
      */
     @Test
     @SmallTest
@@ -107,8 +111,9 @@
     }
 
     /**
-     * We never receive a {@link RadioOnStateListener.Callback#onComplete(boolean)} because
-     * {@link RadioOnStateListener.Callback#isOkToCall(int)} returns false.
+     * We never receive a
+     * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} because
+     * {@link RadioOnStateListener.Callback#isOkToCall(Phone, int)} returns false.
      */
     @Test
     @SmallTest
@@ -129,27 +134,27 @@
     }
 
     /**
-     * Tests {@link RadioOnStateListener.Callback#isOkToCall(int)} returning false and hitting the
-     * max number of retries. This should result in
-     * {@link RadioOnStateListener.Callback#onComplete(boolean)} returning false.
+     * Tests {@link RadioOnStateListener.Callback#isOkToCall(Phone, int)} returning false and
+     * hitting the max number of retries. This should result in
+     * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} returning
+     * false.
      */
     @Test
-    @FlakyTest
+    @SmallTest
     public void testTimeout_RetryFailure() {
         ServiceState state = new ServiceState();
         state.setState(ServiceState.STATE_POWER_OFF);
         when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
         when(mMockPhone.getServiceState()).thenReturn(state);
         when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(false);
-        mListener.setTimeBetweenRetriesMillis(50);
+        mListener.setTimeBetweenRetriesMillis(0/*ms*/);
         mListener.setMaxNumRetries(2);
 
         // Wait for the timer to expire and check state manually in onRetryTimeout
         mListener.waitForRadioOn(mMockPhone, mCallback);
-        waitForHandlerActionDelayed(mListener.getHandler(), TIMEOUT_MS, 500);
+        waitForHandlerActionDelayed(mListener.getHandler(), TIMEOUT_MS, TIMEOUT_MS /*delay*/);
 
         verify(mCallback).onComplete(eq(mListener), eq(false));
         verify(mMockPhone, times(2)).setRadioPower(eq(true));
     }
-
 }